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  }