1 /* Deals with parsing Manifest Text. */
3 // Inspired by the Manifest class in arvados/sdk/ruby/lib/arvados/keep.rb
15 var LocatorPattern = regexp.MustCompile(
16 "^[0-9a-fA-F]{32}\\+[0-9]+(\\+[A-Z][A-Za-z0-9@_-]+)*$")
18 type Manifest struct {
22 type BlockLocator struct {
28 type ManifestLine struct {
34 func ParseBlockLocator(s string) (b BlockLocator, err error) {
35 if !LocatorPattern.MatchString(s) {
36 err = fmt.Errorf("String \"%s\" does not match BlockLocator pattern " +
39 LocatorPattern.String())
41 tokens := strings.Split(s, "+")
43 // We expect ParseInt to succeed since LocatorPattern restricts
44 // tokens[1] to contain exclusively digits.
45 blockSize, err = strconv.ParseInt(tokens[1], 10, 0)
48 b.Size = int(blockSize)
55 func parseManifestLine(s string) (m ManifestLine) {
56 tokens := strings.Split(s, " ")
57 m.StreamName = tokens[0]
60 for i = range tokens {
61 if !LocatorPattern.MatchString(tokens[i]) {
70 func (m *Manifest) LineIter() <-chan ManifestLine {
71 ch := make(chan ManifestLine)
72 go func(input string) {
73 // This slice holds the current line and the remainder of the
74 // manifest. We parse one line at a time, to save effort if we
75 // only need the first few lines.
76 lines := []string{"", input}
78 lines = strings.SplitN(lines[1], "\n", 2)
79 if len(lines[0]) > 0 {
80 // Only parse non-blank lines
81 ch <- parseManifestLine(lines[0])
93 // Blocks may appear mulitple times within the same manifest if they
94 // are used by multiple files. In that case this Iterator will output
95 // the same block multiple times.
96 func (m *Manifest) BlockIterWithDuplicates() <-chan BlockLocator {
97 blockChannel := make(chan BlockLocator)
98 go func(lineChannel <-chan ManifestLine) {
99 for m := range lineChannel {
100 for _, block := range m.Blocks {
101 if b, err := ParseBlockLocator(block); err == nil {
104 log.Printf("ERROR: Failed to parse block: %v", err)