github.com/octohelm/cuemod@v0.9.4/pkg/cuemod/path.go (about) 1 package cuemod 2 3 import ( 4 "context" 5 "os" 6 "path/filepath" 7 "strings" 8 9 "golang.org/x/mod/module" 10 11 "github.com/octohelm/cuemod/pkg/cueify" 12 "github.com/octohelm/cuemod/pkg/cuemod/modfile" 13 "github.com/pkg/errors" 14 ) 15 16 func PathFor(mod *Mod, importPath string) *Path { 17 i := &Path{} 18 i.Mod = *mod 19 20 if importPath != "" { 21 // when use replace with custom forked repo 22 // mod.Module may not same as mod.Repo 23 // then should to overwrite this path.Module with mode.Repo 24 if !strings.HasPrefix(importPath, i.Module) { 25 if strings.HasPrefix(importPath, i.Repo) { 26 i.Module = i.Repo 27 } 28 } 29 30 i.Module = i.ModuleRoot() 31 i.SubPath, _ = subDir(i.Module, importPath) 32 } 33 34 return i 35 } 36 37 type Path struct { 38 Mod 39 SubPath string 40 Replace *ReplaceRule 41 } 42 43 func (i Path) String() string { 44 s := strings.Builder{} 45 46 if i.Replace != nil { 47 s.WriteString(i.Replace.From) 48 49 if i.SubPath != "" { 50 s.WriteString("/") 51 s.WriteString(i.SubPath) 52 } 53 54 s.WriteString(" => ") 55 } 56 57 s.WriteString(i.Module) 58 59 if i.SubPath != "" { 60 s.WriteString("/") 61 s.WriteString(i.SubPath) 62 } 63 64 return s.String() 65 } 66 67 type ReplaceRule struct { 68 From string 69 modfile.ReplaceTarget 70 } 71 72 func (i Path) WithReplace(from string, replaceTarget modfile.ReplaceTarget) *Path { 73 i.Replace = &ReplaceRule{ 74 From: from, 75 ReplaceTarget: replaceTarget, 76 } 77 return &i 78 } 79 80 func (i *Path) SymlinkOrImport(ctx context.Context, root string) error { 81 if root == i.Dir { 82 // skip root dir 83 return nil 84 } 85 86 if !i.Mod.Root { 87 return nil 88 } 89 90 gen := "" 91 92 if i.Replace != nil && i.Replace.Import != "" { 93 gen = i.Replace.Import 94 } 95 96 resolveDest := func(base string, withPathMajor bool, genSource bool) string { 97 // for generated code 98 // 99 // pkg/ 100 // .cuemod/<import_path> -> <GOMODCACHE>/<import_path>@<version>/ 101 if genSource { 102 return filepath.Join(root, "cue.mod/pkg/.cuemod", base) 103 } 104 // support multi versions of pkg 105 // 106 // gen/ 107 // <import_path>/v2 -> <GOMODCACHE>/<import_path>@<version>/ 108 // pkg/ 109 // <import_path> -> <GOMODCACHE>/<import_path>@<version>/ 110 if withPathMajor { 111 return filepath.Join(root, "cue.mod/gen", base) 112 } 113 return filepath.Join(root, "cue.mod/pkg", base) 114 } 115 116 _, pathMajor, ok := module.SplitPathVersion(i.ImportPathRoot()) 117 withPathMajor := ok && pathMajor != "" 118 119 if err := i.symlink(ctx, i.ImportPathRootDir(), resolveDest(i.ImportPathRoot(), withPathMajor, gen != "")); err != nil { 120 return err 121 } 122 123 if gen != "" { 124 if err := cueify.ExtractToDir( 125 ctx, 126 gen, 127 resolveDest(i.ImportPath(), withPathMajor, gen != ""), 128 resolveDest(i.ImportPath(), withPathMajor, false), 129 ); err != nil { 130 return err 131 } 132 } 133 134 return nil 135 } 136 137 func (i *Path) symlink(ctx context.Context, from string, to string) error { 138 if _, err := os.Stat(from); err != nil { 139 return errors.Wrapf(err, "invalid path %s", from) 140 } 141 return forceSymlink(from, to) 142 } 143 144 func forceSymlink(from, to string) error { 145 if err := os.RemoveAll(to); err != nil { 146 return err 147 } 148 if err := os.MkdirAll(filepath.Dir(to), 0755); err != nil { 149 return err 150 } 151 return os.Symlink(from, to) 152 } 153 154 func (i *Path) shouldReplace() bool { 155 return i.Replace != nil && i.Replace.From != i.Replace.Path 156 } 157 158 func (i *Path) ImportPath() string { 159 if i.shouldReplace() { 160 return i.Replace.From + filepath.Join(i.Module, i.SubPath)[len(i.Replace.Path):] 161 } 162 return filepath.Join(i.Module, i.SubPath) 163 } 164 165 func (i *Path) ResolvedImportPath() string { 166 return filepath.Join(i.Dir, i.SubPath) 167 } 168 169 func (i Path) ImportPathRoot() string { 170 if i.Replace != nil { 171 return i.Replace.From 172 } 173 return i.Repo 174 } 175 176 func (i Path) ImportPathRootDir() string { 177 ipr := i.ImportPathRoot() 178 ip := i.ImportPath() 179 if ip == ipr { 180 return i.Dir 181 } 182 rel, _ := subDir(ipr, ip) 183 dir := i.Dir 184 if i.SubPath != "" { 185 dir = filepath.Join(dir, i.SubPath) 186 } 187 return dir[0 : len(dir)-len("/"+rel)] 188 }