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  }