github.com/pachyderm/pachyderm@v1.13.4/src/server/pkg/storage/fileset/util.go (about) 1 package fileset 2 3 import ( 4 "context" 5 "io" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/pachyderm/pachyderm/src/server/pkg/dbutil" 11 "github.com/pachyderm/pachyderm/src/server/pkg/storage/chunk" 12 "github.com/pachyderm/pachyderm/src/server/pkg/storage/fileset/index" 13 "github.com/pachyderm/pachyderm/src/server/pkg/storage/track" 14 "github.com/pachyderm/pachyderm/src/server/pkg/tar" 15 "github.com/pachyderm/pachyderm/src/server/pkg/tarutil" 16 ) 17 18 // NewTestStorage constructs a local storage instance scoped to the lifetime of the test 19 func NewTestStorage(t testing.TB) *Storage { 20 db := dbutil.NewTestDB(t) 21 tr := track.NewTestTracker(t, db) 22 _, chunks := chunk.NewTestStorage(t, db, tr) 23 store := NewTestStore(t, db) 24 return NewStorage(store, tr, chunks) 25 } 26 27 // CopyFiles copies files from a file set to a file set writer. 28 func CopyFiles(ctx context.Context, w *Writer, fs FileSet, deletive ...bool) error { 29 if len(deletive) > 0 && deletive[0] { 30 if err := fs.Iterate(ctx, func(f File) error { 31 return deleteIndex(w, f.Index()) 32 }, deletive...); err != nil { 33 return err 34 } 35 } 36 return fs.Iterate(ctx, func(f File) error { 37 return w.Copy(f) 38 }) 39 } 40 41 func deleteIndex(w *Writer, idx *index.Index) error { 42 p := idx.Path 43 if len(idx.File.Parts) == 0 { 44 return w.Delete(p) 45 } 46 var tags []string 47 for _, part := range idx.File.Parts { 48 tags = append(tags, part.Tag) 49 } 50 return w.Delete(p, tags...) 51 } 52 53 // WriteTarEntry writes an tar entry for f to w 54 func WriteTarEntry(w io.Writer, f File) error { 55 idx := f.Index() 56 tw := tar.NewWriter(w) 57 if err := tw.WriteHeader(tarutil.NewHeader(idx.Path, index.SizeBytes(idx))); err != nil { 58 return err 59 } 60 if err := f.Content(tw); err != nil { 61 return err 62 } 63 return tw.Flush() 64 } 65 66 // WriteTarStream writes an entire tar stream to w 67 // It will contain an entry for each File in fs 68 func WriteTarStream(ctx context.Context, w io.Writer, fs FileSet) error { 69 if err := fs.Iterate(ctx, func(f File) error { 70 return WriteTarEntry(w, f) 71 }); err != nil { 72 return err 73 } 74 return tar.NewWriter(w).Close() 75 } 76 77 // Clean cleans a file path. 78 func Clean(x string, isDir bool) string { 79 y := "/" + strings.Trim(x, "/") 80 if isDir && !IsDir(y) { 81 y += "/" 82 } 83 return y 84 } 85 86 // IsClean checks if a file path is clean. 87 func IsClean(x string, isDir bool) bool { 88 y := Clean(x, isDir) 89 return y == x 90 } 91 92 // IsDir determines if a path is for a directory. 93 func IsDir(p string) bool { 94 return strings.HasSuffix(p, "/") 95 } 96 97 // Iterator provides functionality for imperative iteration over a file set. 98 type Iterator struct { 99 peek File 100 fileChan chan File 101 errChan chan error 102 } 103 104 // NewIterator creates a new iterator. 105 func NewIterator(ctx context.Context, fs FileSet, deletive ...bool) *Iterator { 106 fileChan := make(chan File) 107 errChan := make(chan error, 1) 108 go func() { 109 if err := fs.Iterate(ctx, func(f File) error { 110 fileChan <- f 111 return nil 112 }, deletive...); err != nil { 113 errChan <- err 114 return 115 } 116 close(fileChan) 117 }() 118 return &Iterator{ 119 fileChan: fileChan, 120 errChan: errChan, 121 } 122 } 123 124 // Peek returns the next file without progressing the iterator. 125 func (i *Iterator) Peek() (File, error) { 126 if i.peek != nil { 127 return i.peek, nil 128 } 129 var err error 130 i.peek, err = i.Next() 131 return i.peek, err 132 } 133 134 // Next returns the next file and progresses the iterator. 135 func (i *Iterator) Next() (File, error) { 136 if i.peek != nil { 137 tmp := i.peek 138 i.peek = nil 139 return tmp, nil 140 } 141 select { 142 case file, more := <-i.fileChan: 143 if !more { 144 return nil, io.EOF 145 } 146 return file, nil 147 case err := <-i.errChan: 148 return nil, err 149 } 150 } 151 152 func getDataRefs(parts []*index.Part) []*chunk.DataRef { 153 var dataRefs []*chunk.DataRef 154 for _, part := range parts { 155 dataRefs = append(dataRefs, part.DataRefs...) 156 } 157 return dataRefs 158 } 159 160 func createTrackerObject(ctx context.Context, p string, idxs []*index.Index, tracker track.Tracker, ttl time.Duration) error { 161 var pointsTo []string 162 for _, idx := range idxs { 163 for _, cid := range index.PointsTo(idx) { 164 pointsTo = append(pointsTo, chunk.ObjectID(cid)) 165 } 166 } 167 return tracker.CreateObject(ctx, filesetObjectID(p), pointsTo, ttl) 168 }