github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/gateway/path/resolver.go (about)

     1  package path
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"regexp"
     7  	"strings"
     8  
     9  	"github.com/treeverse/lakefs/pkg/graveler"
    10  
    11  	"github.com/treeverse/lakefs/pkg/block"
    12  )
    13  
    14  const (
    15  	Separator = "/"
    16  
    17  	rePath      = "(?P<path>.*)"
    18  	reReference = `(?P<ref>[^/]+)`
    19  )
    20  
    21  var (
    22  	EncodedPathRe          = regexp.MustCompile(fmt.Sprintf("^/?%s/%s", reReference, rePath))
    23  	EncodedPathReferenceRe = regexp.MustCompile(fmt.Sprintf("^/?%s$", reReference))
    24  
    25  	ErrPathMalformed = errors.New("encoded path is malformed")
    26  )
    27  
    28  type Ref struct {
    29  	Branch   string
    30  	CommitID graveler.CommitID
    31  }
    32  
    33  type ResolvedPath struct {
    34  	Ref      string
    35  	Path     string
    36  	WithPath bool
    37  }
    38  
    39  type ResolvedAbsolutePath struct {
    40  	Repo      string
    41  	Reference string
    42  	Path      string
    43  }
    44  
    45  func ResolveAbsolutePath(encodedPath string) (ResolvedAbsolutePath, error) {
    46  	const encodedPartsCount = 3
    47  	encodedPath = strings.TrimLeft(encodedPath, "/")
    48  	parts := strings.SplitN(encodedPath, "/", encodedPartsCount)
    49  	if len(parts) != encodedPartsCount {
    50  		return ResolvedAbsolutePath{}, ErrPathMalformed
    51  	}
    52  	return ResolvedAbsolutePath{
    53  		Repo:      parts[0],
    54  		Reference: parts[1],
    55  		Path:      parts[2],
    56  	}, nil
    57  }
    58  
    59  func ResolvePath(encodedPath string) (ResolvedPath, error) {
    60  	r := ResolvedPath{}
    61  	if len(encodedPath) == 0 {
    62  		return r, nil // empty path.
    63  	}
    64  	// try reference with path or just reference regexp
    65  	for _, re := range []*regexp.Regexp{EncodedPathRe, EncodedPathReferenceRe} {
    66  		match := re.FindStringSubmatch(encodedPath)
    67  		if len(match) == 0 {
    68  			continue
    69  		}
    70  		for i, name := range re.SubexpNames() {
    71  			switch name {
    72  			case "ref":
    73  				r.Ref = match[i]
    74  			case "path":
    75  				r.Path = match[i]
    76  				r.WithPath = true
    77  			}
    78  		}
    79  		return r, nil
    80  	}
    81  	return r, ErrPathMalformed
    82  }
    83  
    84  func WithRef(path, ref string) string {
    85  	return block.JoinPathParts([]string{ref, path})
    86  }