github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/local/index.go (about)

     1  package local
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io/fs"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"github.com/treeverse/lakefs/pkg/fileutil"
    12  	"github.com/treeverse/lakefs/pkg/uri"
    13  	"gopkg.in/yaml.v3"
    14  )
    15  
    16  const (
    17  	IndexFileName = ".lakefs_ref.yaml"
    18  	IgnoreMarker  = "ignored by lakectl local"
    19  	IndexFileMode = 0o644
    20  )
    21  
    22  // Index defines the structure of the lakefs local reference file
    23  // consisting of the information linking local directory with lakefs path
    24  type Index struct {
    25  	root            string `yaml:"-"`
    26  	PathURI         string `yaml:"src"`
    27  	AtHead          string `yaml:"at_head"`
    28  	ActiveOperation string `yaml:"active_operation"`
    29  }
    30  
    31  func (l *Index) LocalPath() string {
    32  	return l.root
    33  }
    34  
    35  func (l *Index) GetCurrentURI() (*uri.URI, error) {
    36  	return uri.Parse(l.PathURI)
    37  }
    38  
    39  func WriteIndex(path string, remote *uri.URI, atHead string, operation string) (*Index, error) {
    40  	idx := &Index{
    41  		PathURI:         remote.String(),
    42  		AtHead:          atHead,
    43  		ActiveOperation: operation,
    44  	}
    45  	data, err := yaml.Marshal(idx)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	idxPath := filepath.Join(path, IndexFileName)
    50  	return idx, os.WriteFile(idxPath, data, IndexFileMode)
    51  }
    52  
    53  func IndexExists(baseAbs string) (bool, error) {
    54  	refPath := filepath.Join(baseAbs, IndexFileName)
    55  	_, err := os.Stat(refPath)
    56  	switch {
    57  	case err == nil:
    58  		return true, nil
    59  	case errors.Is(err, os.ErrNotExist):
    60  		return false, nil
    61  	default:
    62  		return false, err
    63  	}
    64  }
    65  
    66  func ReadIndex(path string) (*Index, error) {
    67  	idxPath, err := fileutil.FindInParents(path, IndexFileName)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	if idxPath == "" {
    72  		return nil, fmt.Errorf("could not find lakefs reference file in path %s or parents: %w", path, fs.ErrNotExist)
    73  	}
    74  	data, err := os.ReadFile(idxPath)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	idx := &Index{
    79  		root: filepath.Dir(idxPath),
    80  	}
    81  	err = yaml.Unmarshal(data, idx)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	return idx, nil
    86  }
    87  
    88  // FindIndices searches the specified root directory for index files, returning their relative directory paths while skipping hidden folders.
    89  func FindIndices(root string) ([]string, error) {
    90  	locs := make([]string, 0)
    91  	err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
    92  		if err != nil {
    93  			return err
    94  		}
    95  		// don't traverse hidden folders like '.git', etc.
    96  		if d.IsDir() && strings.HasPrefix(d.Name(), ".") {
    97  			return filepath.SkipDir
    98  		}
    99  		// if we found an index, no need to further traverse
   100  		if filepath.Base(path) == IndexFileName {
   101  			// add the relative location of the directory containing the index
   102  			rel, err := filepath.Rel(root, filepath.Dir(path))
   103  			if err != nil {
   104  				return err
   105  			}
   106  			locs = append(locs, rel)
   107  			return filepath.SkipDir // no need to traverse further!
   108  		}
   109  		return nil
   110  	})
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	return locs, nil
   115  }