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 }