package catalogue import ( "fmt" "regexp" "strings" ) // PlacedDataItem is one data item a module on a node declares, as placed on that node. type PlacedDataItem struct { Module string `json:"module"` ID string `json:"item"` Class string `json:"class"` // Path is the item's place on the node; CoveredBy the path whose snapshot keeps it (the item, or the item its dump // writes into), empty when it is not backed up. Path string `json:"path"` CoveredBy string `json:"covered_by,omitempty"` // Protection is backup, redundancy, both or none; Measure walk, dataset or shallow. Protection string `json:"protection,omitempty"` Measure string `json:"measure,omitempty"` } var ( dataModuleHeader = regexp.MustCompile(`^#\s*([a-z0-9][a-z0-9-]*)$`) dataSafePath = regexp.MustCompile(`^/[^\s'"\\$` + "`" + `]*$`) ) // ParseDataItems reads the node-backup holder's data text (`${backup:data}`: a `# ` line, then one line per item, // `item `) into each module's items, in order. A line it does // not read is refused, naming the module: a path with a space or a quote is never handed to a measuring shell. func ParseDataItems(text string) (map[string][]PlacedDataItem, error) { out := map[string][]PlacedDataItem{} module := "" for _, raw := range strings.Split(text, "\n") { line := strings.TrimSpace(raw) if line == "" { continue } if m := dataModuleHeader.FindStringSubmatch(line); m != nil { module = m[1] continue } if strings.HasPrefix(line, "#") || module == "" { continue } f := strings.Fields(line) if len(f) < 5 || len(f) > 7 || f[0] != "item" || !dataSafePath.MatchString(f[3]) || (f[4] != "-" && !dataSafePath.MatchString(f[4])) { return nil, fmt.Errorf("%s declares a data line that is not read: %s", module, line) } it := PlacedDataItem{Module: module, ID: f[1], Class: f[2], Path: f[3], Measure: MeasureWalk} if len(f) >= 6 { it.Protection = f[5] } if len(f) == 7 { it.Measure = f[6] } if it.Measure != MeasureWalk && it.Measure != MeasureDataset && it.Measure != MeasureShallow { return nil, fmt.Errorf("%s declares a data line that is not read: %s", module, line) } if f[4] != "-" { it.CoveredBy = f[4] } out[module] = append(out[module], it) } return out, nil }