github.com/octohelm/cuemod@v0.9.4/pkg/cuemod/stdlib/stdlib.go (about)

     1  package stdlib
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"io/fs"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"github.com/octohelm/cuemod/pkg/cuemod/mod"
    13  	"golang.org/x/mod/sumdb/dirhash"
    14  )
    15  
    16  var stdlibs = map[string]*stdlib{}
    17  
    18  type stdlib struct {
    19  	mod.Mod
    20  	fs fs.ReadDirFS
    21  }
    22  
    23  func Register(dirFs fs.ReadDirFS, version string, pkgs ...string) {
    24  	for _, p := range pkgs {
    25  		m := &stdlib{}
    26  		m.Repo = p
    27  		m.Module = p
    28  		m.Version = version
    29  		m.Root = true
    30  		m.fs = dirFs
    31  
    32  		stdlibs[m.Repo] = m
    33  	}
    34  }
    35  
    36  func RepoRootForImportPath(repo string) (string, bool) {
    37  	for lib := range stdlibs {
    38  		if isSubDirFor(repo, lib) {
    39  			return lib, true
    40  		}
    41  	}
    42  	return "", false
    43  }
    44  
    45  func Mount(ctx context.Context, importPath string, modRoot string) (*mod.Mod, error) {
    46  	repo, ok := RepoRootForImportPath(importPath)
    47  	if !ok {
    48  		return nil, nil
    49  	}
    50  
    51  	noWrite := modRoot == ""
    52  	if noWrite {
    53  		modRoot = "<cue_mod_root>"
    54  	}
    55  
    56  	for lib := range stdlibs {
    57  		if isSubDirFor(repo, lib) {
    58  			found := stdlibs[lib]
    59  
    60  			m := found.Mod
    61  
    62  			dirSum, err := HashDir(found.fs, ".", "", dirhash.DefaultHash)
    63  			if err != nil {
    64  				return nil, err
    65  			}
    66  			m.Sum = dirSum
    67  
    68  			m.Dir = filepath.Join(modRoot, "cue.mod/pkg/.cuemod/std", fmt.Sprintf(
    69  				"%s@%s-%s",
    70  				m.Repo,
    71  				m.Version,
    72  				m.Sum,
    73  			))
    74  
    75  			if !noWrite {
    76  				if _, err := os.Stat(m.Dir); os.IsNotExist(err) {
    77  					_ = os.MkdirAll(m.Dir, os.ModePerm)
    78  
    79  					err := fs.WalkDir(found.fs, repo, func(path string, d fs.DirEntry, err error) error {
    80  						tmpPath := filepath.Join(m.Dir, "."+strings.TrimPrefix(path, repo))
    81  
    82  						if d.IsDir() {
    83  							_ = os.MkdirAll(tmpPath, os.ModePerm)
    84  						} else {
    85  							f, err := found.fs.Open(path)
    86  							if err != nil {
    87  								return err
    88  							}
    89  							defer f.Close()
    90  							data, _ := io.ReadAll(f)
    91  							if err = os.WriteFile(tmpPath, data, os.ModePerm); err != nil {
    92  								return err
    93  							}
    94  						}
    95  
    96  						return err
    97  					})
    98  
    99  					if err != nil {
   100  						return nil, err
   101  					}
   102  				}
   103  			}
   104  
   105  			return &m, nil
   106  		}
   107  	}
   108  
   109  	return nil, nil
   110  }
   111  
   112  func isSubDirFor(targetpath string, root string) bool {
   113  	targetpath = targetpath + "/"
   114  	root = root + "/"
   115  	return strings.HasPrefix(targetpath, root)
   116  }
   117  
   118  func HashDir(fs fs.ReadDirFS, dir string, prefix string, hash dirhash.Hash) (string, error) {
   119  	files := make([]string, 0)
   120  
   121  	if err := RangeFile(fs, dir, func(filename string) error {
   122  		files = append(files, filepath.ToSlash(filepath.Join(prefix, filename)))
   123  		return nil
   124  	}); err != nil {
   125  		return "", err
   126  	}
   127  
   128  	return hash(files, func(name string) (io.ReadCloser, error) {
   129  		return fs.Open(filepath.Join(dir, strings.TrimPrefix(name, prefix)))
   130  	})
   131  }
   132  
   133  func RangeFile(f fs.ReadDirFS, root string, each func(filename string) error) error {
   134  	return fs.WalkDir(f, root, func(path string, d fs.DirEntry, err error) error {
   135  		if err != nil {
   136  			return err
   137  		}
   138  		if d.IsDir() {
   139  			return nil
   140  		}
   141  		rel := path
   142  		if root != "" && root != "." {
   143  			rel, _ = filepath.Rel(root, path)
   144  		}
   145  		return each(rel)
   146  	})
   147  
   148  }