1 /* Deals with parsing Manifest Text. */
3 // Inspired by the Manifest class in arvados/sdk/ruby/lib/arvados/keep.rb
9 "git.curoverse.com/arvados.git/sdk/go/blockdigest"
16 var LocatorPattern = regexp.MustCompile(
17 "^[0-9a-fA-F]{32}\\+[0-9]+(\\+[A-Z][A-Za-z0-9@_-]+)*$")
19 type Manifest struct {
23 type BlockLocator struct {
24 Digest blockdigest.BlockDigest
29 // Represents a single line from a manifest.
30 type ManifestStream struct {
36 func ParseBlockLocator(s string) (b BlockLocator, err error) {
37 if !LocatorPattern.MatchString(s) {
38 err = fmt.Errorf("String \"%s\" does not match BlockLocator pattern "+
41 LocatorPattern.String())
43 tokens := strings.Split(s, "+")
45 var blockDigest blockdigest.BlockDigest
46 // We expect both of the following to succeed since LocatorPattern
47 // restricts the strings appropriately.
48 blockDigest, err = blockdigest.FromString(tokens[0])
52 blockSize, err = strconv.ParseInt(tokens[1], 10, 0)
56 b.Digest = blockDigest
57 b.Size = int(blockSize)
63 func parseManifestStream(s string) (m ManifestStream) {
64 tokens := strings.Split(s, " ")
65 m.StreamName = tokens[0]
68 for i = range tokens {
69 if !LocatorPattern.MatchString(tokens[i]) {
78 func (m *Manifest) StreamIter() <-chan ManifestStream {
79 ch := make(chan ManifestStream)
80 go func(input string) {
81 // This slice holds the current line and the remainder of the
82 // manifest. We parse one line at a time, to save effort if we
83 // only need the first few lines.
84 lines := []string{"", input}
86 lines = strings.SplitN(lines[1], "\n", 2)
87 if len(lines[0]) > 0 {
88 // Only parse non-blank lines
89 ch <- parseManifestStream(lines[0])
100 // Blocks may appear mulitple times within the same manifest if they
101 // are used by multiple files. In that case this Iterator will output
102 // the same block multiple times.
103 func (m *Manifest) BlockIterWithDuplicates() <-chan BlockLocator {
104 blockChannel := make(chan BlockLocator)
105 go func(streamChannel <-chan ManifestStream) {
106 for m := range streamChannel {
107 for _, block := range m.Blocks {
108 if b, err := ParseBlockLocator(block); err == nil {
111 log.Printf("ERROR: Failed to parse block: %v", err)