mirror of
https://github.com/tweag/gomod2nix.git
synced 2024-11-09 20:19:08 +00:00
190 lines
3.7 KiB
Go
190 lines
3.7 KiB
Go
package generate
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"go/printer"
|
|
"go/token"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.org/x/mod/module"
|
|
"golang.org/x/tools/go/vcs" // nolint:staticcheck
|
|
)
|
|
|
|
type TempProject struct {
|
|
Dir string
|
|
SubPackages []string
|
|
GoPackagePath string
|
|
}
|
|
|
|
func NewTempProject(packages []string) (*TempProject, error) {
|
|
// Imports without version suffix
|
|
install := make([]string, len(packages))
|
|
for i, imp := range packages {
|
|
idx := strings.Index(imp, "@")
|
|
if idx == -1 {
|
|
idx = len(imp)
|
|
}
|
|
|
|
install[i] = imp[:idx]
|
|
}
|
|
|
|
var goPackagePath string
|
|
|
|
for _, path := range install {
|
|
log.WithFields(log.Fields{
|
|
"path": path,
|
|
}).Info("Finding repo root for import path")
|
|
|
|
repoRoot, err := vcs.RepoRootForImportPath(path, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_, versionSuffix, _ := module.SplitPathVersion(path)
|
|
|
|
p := repoRoot.Root + versionSuffix
|
|
|
|
if goPackagePath != "" && p != goPackagePath {
|
|
return nil, fmt.Errorf("Mixed origin packages are not allowed")
|
|
}
|
|
|
|
goPackagePath = p
|
|
}
|
|
|
|
log.Info("Setting up temporary project")
|
|
|
|
dir, err := os.MkdirTemp("", "gomod2nix-proj")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
log.WithFields(log.Fields{
|
|
"dir": dir,
|
|
}).Info("Created temporary directory")
|
|
|
|
// Create tools.go
|
|
{
|
|
log.WithFields(log.Fields{
|
|
"dir": dir,
|
|
}).Info("Creating tools.go")
|
|
|
|
astFile := &ast.File{
|
|
Name: ast.NewIdent("main"),
|
|
Decls: []ast.Decl{
|
|
&ast.GenDecl{
|
|
Tok: token.IMPORT,
|
|
Specs: func() []ast.Spec {
|
|
specs := make([]ast.Spec, len(install))
|
|
|
|
i := 0
|
|
for _, imp := range install {
|
|
specs[i] = &ast.ImportSpec{
|
|
Name: ast.NewIdent("_"),
|
|
Path: &ast.BasicLit{
|
|
ValuePos: token.NoPos,
|
|
Kind: token.STRING,
|
|
Value: strconv.Quote(imp),
|
|
},
|
|
}
|
|
|
|
i++
|
|
}
|
|
|
|
return specs
|
|
}(),
|
|
},
|
|
},
|
|
}
|
|
|
|
f, err := os.Create(filepath.Join(dir, "tools.go"))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Error creating tools.go: %v", err)
|
|
}
|
|
defer f.Close()
|
|
|
|
fset := token.NewFileSet()
|
|
err = printer.Fprint(f, fset, astFile)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error writing tools.go: %v", err)
|
|
}
|
|
|
|
log.WithFields(log.Fields{
|
|
"dir": dir,
|
|
}).Info("Created tools.go")
|
|
}
|
|
|
|
// Set up go module
|
|
{
|
|
log.WithFields(log.Fields{
|
|
"dir": dir,
|
|
}).Info("Initializing go.mod")
|
|
|
|
cmd := exec.Command("go", "mod", "init", "gomod2nix/dummy/package")
|
|
cmd.Dir = dir
|
|
cmd.Stderr = os.Stderr
|
|
|
|
_, err := cmd.Output()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error creating go module: %v", err)
|
|
}
|
|
|
|
log.WithFields(log.Fields{
|
|
"dir": dir,
|
|
}).Info("Done initializing go.mod")
|
|
|
|
// For every dependency fetch it
|
|
{
|
|
log.WithFields(log.Fields{
|
|
"dir": dir,
|
|
}).Info("Getting dependencies")
|
|
|
|
args := []string{"get", "-d"}
|
|
args = append(args, packages...)
|
|
|
|
cmd := exec.Command("go", args...)
|
|
cmd.Dir = dir
|
|
cmd.Stderr = os.Stderr
|
|
|
|
_, err := cmd.Output()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error fetching: %v", err)
|
|
}
|
|
|
|
log.WithFields(log.Fields{
|
|
"dir": dir,
|
|
}).Info("Done getting dependencies")
|
|
}
|
|
}
|
|
|
|
subPackages := []string{}
|
|
{
|
|
prefix, versionSuffix, _ := module.SplitPathVersion(goPackagePath)
|
|
for _, path := range install {
|
|
p := strings.TrimPrefix(path, prefix)
|
|
p = strings.TrimSuffix(p, versionSuffix)
|
|
p = strings.TrimPrefix(p, "/")
|
|
|
|
if p == "" {
|
|
continue
|
|
}
|
|
|
|
subPackages = append(subPackages, p)
|
|
}
|
|
}
|
|
|
|
return &TempProject{
|
|
Dir: dir,
|
|
SubPackages: subPackages,
|
|
GoPackagePath: goPackagePath,
|
|
}, nil
|
|
}
|
|
|
|
func (t *TempProject) Remove() error {
|
|
return os.RemoveAll(t.Dir)
|
|
}
|