github.com/octohelm/cuekit@v0.0.0-20240424021256-e7df8d743066/pkg/mod/module/module.go (about) 1 package module 2 3 import ( 4 "bytes" 5 cuemodfile "cuelang.org/go/mod/modfile" 6 "cuelang.org/go/mod/module" 7 "fmt" 8 "github.com/octohelm/cuekit/pkg/mod/modfile" 9 "io" 10 "io/fs" 11 "os" 12 "path/filepath" 13 "sync" 14 ) 15 16 const ( 17 fileModule = "cue.mod/module.cue" 18 fileModuleOverwrites = "cue.mod/module_overwrites.cue" 19 ) 20 21 type Module struct { 22 module.SourceLoc 23 modfile.File 24 Overwrites *modfile.FileOverwrites 25 26 mu sync.Mutex 27 } 28 29 func (m *Module) SourceRoot() string { 30 if osRoot, ok := m.FS.(module.OSRootFS); ok { 31 return filepath.Join(osRoot.OSRoot(), m.Dir) 32 } 33 return fmt.Sprintf("mem:%s", m.Dir) 34 } 35 36 func (m *Module) GetDepOverwrite(mpath string) (*modfile.DepOverwrite, bool) { 37 v, ok := m.Overwrites.GetDep(mpath) 38 if ok { 39 return v, ok 40 } 41 return nil, false 42 } 43 44 func (m *Module) Load(strict bool) error { 45 if m.Overwrites == nil { 46 m.Overwrites = &modfile.FileOverwrites{} 47 } 48 49 if err := m.loadModule(strict); err != nil { 50 return err 51 } 52 53 // optional load 54 if data, err := fs.ReadFile(m.FS, filepath.Join(m.Dir, fileModuleOverwrites)); err == nil { 55 if err := m.Overwrites.Load(data); err != nil { 56 return err 57 } 58 } 59 60 return nil 61 } 62 63 func (m *Module) loadModule(strict bool) error { 64 data, err := fs.ReadFile(m.FS, filepath.Join(m.Dir, fileModule)) 65 if err != nil { 66 if os.IsNotExist(err) && !strict { 67 return nil 68 } 69 return err 70 } 71 72 var parse = cuemodfile.Parse 73 if !strict { 74 parse = cuemodfile.ParseNonStrict 75 } 76 77 mf, err := parse(data, "") 78 if err != nil { 79 return fmt.Errorf("cannot parse module file: %s, %v", m.SourceRoot(), err) 80 } 81 82 m.File.Module = mf.Module 83 m.File.Deps = mf.Deps 84 m.File.Language = mf.Language 85 86 return nil 87 } 88 89 func (m *Module) AddDep(mpath string, dep *cuemodfile.Dep) { 90 if m.File.Deps == nil { 91 m.File.Deps = map[string]*cuemodfile.Dep{} 92 } 93 m.File.Deps[mpath] = dep 94 } 95 96 func (mm *Module) Save() error { 97 mm.mu.Lock() 98 defer mm.mu.Unlock() 99 100 m := &Module{ 101 SourceLoc: mm.SourceLoc, 102 File: mm.File, 103 Overwrites: mm.Overwrites, 104 } 105 106 if !m.Overwrites.IsZero() { 107 for mpath, d := range m.Overwrites.Deps { 108 if d.IsLocalReplacement() { 109 m.AddDep(mpath, &cuemodfile.Dep{ 110 Version: "v0.0.0", 111 }) 112 continue 113 } 114 115 if d.Version != "" { 116 m.AddDep(mpath, &cuemodfile.Dep{ 117 Version: d.Version, 118 }) 119 } 120 } 121 data, err := m.Overwrites.Format() 122 if err != nil { 123 return nil 124 } 125 if err := putFileContents(filepath.Join(m.SourceRoot(), fileModuleOverwrites), bytes.NewBuffer(data)); err != nil { 126 return err 127 } 128 } 129 130 data, err := m.File.Format() 131 if err != nil { 132 return err 133 } 134 if err := putFileContents(filepath.Join(m.SourceRoot(), fileModule), bytes.NewBuffer(data)); err != nil { 135 return err 136 } 137 return nil 138 } 139 140 func (m *Module) Tidy() { 141 if len(m.Deps) > 0 { 142 for mpath := range m.Overwrites.Deps { 143 if _, ok := m.Deps[mpath]; !ok { 144 // remove unused dep overwrite 145 delete(m.Overwrites.Deps, mpath) 146 } 147 } 148 } 149 } 150 151 func putFileContents(filename string, r io.Reader) error { 152 if err := os.MkdirAll(filepath.Dir(filename), os.ModePerm); err != nil { 153 return err 154 } 155 df, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm) 156 if err != nil { 157 return err 158 } 159 defer df.Close() 160 _, err = io.Copy(df, r) 161 return nil 162 }