github.com/jmigpin/editor@v1.6.0/util/goutil/modules.go (about)

     1  package goutil
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	"github.com/jmigpin/editor/util/osutil"
    11  	"golang.org/x/mod/modfile"
    12  )
    13  
    14  //----------
    15  
    16  func ReadGoMod(ctx context.Context, dir string, env []string) (*modfile.File, error) {
    17  	f, _, err := ParseDirGoMod(dir)
    18  	if err != nil {
    19  		return nil, err
    20  	}
    21  	return f, nil
    22  }
    23  
    24  //----------
    25  
    26  func GoModInit(ctx context.Context, dir, modPath string, env []string) error {
    27  	args := []string{"go", "mod", "init"}
    28  	if modPath != "" {
    29  		args = append(args, modPath)
    30  	}
    31  	_, err := runGoModCmd(ctx, dir, args, env)
    32  	return err
    33  }
    34  
    35  func GoModTidy(ctx context.Context, dir string, env []string) error {
    36  	args := []string{"go", "mod", "tidy"}
    37  	_, err := runGoModCmd(ctx, dir, args, env)
    38  	return err
    39  }
    40  
    41  func GoModRequire(ctx context.Context, dir, path string, env []string) error {
    42  	args := []string{"go", "mod", "edit", "-require=" + path}
    43  	_, err := runGoModCmd(ctx, dir, args, env)
    44  	return err
    45  }
    46  
    47  func GoModExclude(ctx context.Context, dir, path string, env []string) error {
    48  	args := []string{"go", "mod", "edit", "-exclude=" + path}
    49  	_, err := runGoModCmd(ctx, dir, args, env)
    50  	return err
    51  }
    52  
    53  func GoModReplace(ctx context.Context, dir, old, new string, env []string) error {
    54  	//// fails when using directories that contain the version in the name. So it would not allow a downloaded module to be used (contains directories with '@' version in the name).
    55  	//args := []string{"go", "mod", "edit", "-replace=" + old + "=" + new}
    56  	//_, err := runGoModCmd(ctx, dir, args, env)
    57  	//return err
    58  
    59  	// simple append to the file (works, but can add repeated strings)
    60  	//return goModReplaceUsingAppend(ctx, dir, old, new)
    61  
    62  	f, fname, err := ParseDirGoMod(dir)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	if err := f.AddReplace(old, "", new, ""); err != nil {
    67  		return err
    68  	}
    69  	f.Cleanup()
    70  	b, err := f.Format()
    71  	if err != nil {
    72  		return err
    73  	}
    74  	return ioutil.WriteFile(fname, b, 0660)
    75  }
    76  
    77  //----------
    78  
    79  func runGoModCmd(ctx context.Context, dir string, args []string, env []string) ([]byte, error) {
    80  	cmd := osutil.NewCmd(ctx, args...)
    81  	cmd.Dir = dir
    82  	cmd.Env = env
    83  	bout, err := osutil.RunCmdStdoutAndStderrInErr(cmd, nil)
    84  	if err != nil {
    85  		return nil, fmt.Errorf("runGoMod: %v (args=%v, dir=%v)", err, args, dir)
    86  	}
    87  	return bout, nil
    88  }
    89  
    90  //----------
    91  
    92  func FindGoMod(dir string) (string, bool) {
    93  	return findFileUp(dir, "go.mod")
    94  }
    95  func FindGoSum(dir string) (string, bool) {
    96  	return findFileUp(dir, "go.sum")
    97  }
    98  func findFileUp(dir, name string) (string, bool) {
    99  	for {
   100  		fp := filepath.Join(dir, name)
   101  		_, err := os.Stat(fp)
   102  		if err == nil {
   103  			return fp, true
   104  		}
   105  		// parent dir
   106  		oldDir := dir
   107  		dir = filepath.Dir(dir)
   108  		isRoot := oldDir == dir
   109  		if isRoot {
   110  			return "", false
   111  		}
   112  	}
   113  }
   114  
   115  //----------
   116  
   117  func ParseDirGoMod(dir string) (*modfile.File, string, error) {
   118  	name, b, err := readDirGoModFile(dir)
   119  	if err != nil {
   120  		return nil, "", err
   121  	}
   122  	f, err := modfile.Parse(name, b, nil) // ParseLax will not read replaces's
   123  	if err != nil {
   124  		return nil, "", err
   125  	}
   126  	return f, name, nil
   127  }
   128  
   129  func readDirGoModFile(dir string) (string, []byte, error) {
   130  	s := filepath.Join(dir, "go.mod")
   131  	b, err := ioutil.ReadFile(s)
   132  	return s, b, err
   133  }
   134  
   135  //----------
   136  
   137  //func GoModCreateContent(dir string, content string) error {
   138  //	filename := filepath.Join(dir, "go.mod")
   139  //	f, err := os.Create(filename)
   140  //	if err != nil {
   141  //		return err
   142  //	}
   143  //	defer f.Close()
   144  //	if _, err := fmt.Fprintf(f, content); err != nil {
   145  //		return err
   146  //	}
   147  //	return nil
   148  //}
   149  
   150  //----------
   151  
   152  //func goModReplaceUsingAppend(ctx context.Context, dir, old, new string) error {
   153  //	filename := filepath.Join(dir, "go.mod")
   154  //	f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
   155  //	if err != nil {
   156  //		return err
   157  //	}
   158  //	defer f.Close()
   159  //	u := "replace " + old + " => " + new
   160  //	if _, err := f.WriteString("\n" + u + "\n"); err != nil {
   161  //		return err
   162  //	}
   163  //	return nil
   164  //}