ab0d607923
That imports sources from the local Go sources into the Nix store.
218 lines
4.1 KiB
Go
218 lines
4.1 KiB
Go
package fetch
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/nix-community/go-nix/pkg/nar"
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/tweag/gomod2nix/lib"
|
|
schema "github.com/tweag/gomod2nix/schema"
|
|
"golang.org/x/mod/modfile"
|
|
)
|
|
|
|
type goModDownload struct {
|
|
Path string
|
|
Version string
|
|
Info string
|
|
GoMod string
|
|
Zip string
|
|
Dir string
|
|
Sum string
|
|
GoModSum string
|
|
}
|
|
|
|
func sourceFilter(name string, nodeType nar.NodeType) bool {
|
|
return strings.ToLower(filepath.Base(name)) != ".ds_store"
|
|
}
|
|
|
|
func common(directory string) ([]*goModDownload, map[string]string, error) {
|
|
goModPath := filepath.Join(directory, "go.mod")
|
|
|
|
log.WithFields(log.Fields{
|
|
"modPath": goModPath,
|
|
}).Info("Parsing go.mod")
|
|
|
|
// Read go.mod
|
|
data, err := ioutil.ReadFile(goModPath)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Parse go.mod
|
|
mod, err := modfile.Parse(goModPath, data, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Map repos -> replacement repo
|
|
replace := make(map[string]string)
|
|
for _, repl := range mod.Replace {
|
|
replace[repl.New.Path] = repl.Old.Path
|
|
}
|
|
|
|
var modDownloads []*goModDownload
|
|
{
|
|
log.Info("Downloading dependencies")
|
|
|
|
cmd := exec.Command(
|
|
"go", "mod", "download", "--json",
|
|
)
|
|
cmd.Dir = directory
|
|
stdout, err := cmd.Output()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
dec := json.NewDecoder(bytes.NewReader(stdout))
|
|
for {
|
|
var dl *goModDownload
|
|
err := dec.Decode(&dl)
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
modDownloads = append(modDownloads, dl)
|
|
}
|
|
|
|
log.Info("Done downloading dependencies")
|
|
}
|
|
|
|
return modDownloads, replace, nil
|
|
}
|
|
|
|
func ImportPkgs(directory string, numWorkers int) error {
|
|
modDownloads, _, err := common(directory)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
executor := lib.NewParallellExecutor(numWorkers)
|
|
for _, dl := range modDownloads {
|
|
dl := dl
|
|
executor.Add(func() error {
|
|
log.WithFields(log.Fields{
|
|
"goPackagePath": dl.Path,
|
|
}).Info("Importing sources")
|
|
|
|
pathName := filepath.Base(dl.Path) + "_" + dl.Version
|
|
|
|
cmd := exec.Command(
|
|
"nix-instantiate",
|
|
"--eval",
|
|
"--expr",
|
|
fmt.Sprintf(`
|
|
builtins.filterSource (name: type: baseNameOf name != ".DS_Store") (
|
|
builtins.path {
|
|
path = "%s";
|
|
name = "%s";
|
|
}
|
|
)
|
|
`, dl.Dir, pathName),
|
|
)
|
|
cmd.Stderr = os.Stderr
|
|
|
|
err = cmd.Start()
|
|
if err != nil {
|
|
fmt.Println(cmd)
|
|
return err
|
|
}
|
|
|
|
err = cmd.Wait()
|
|
if err != nil {
|
|
fmt.Println(cmd)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
return executor.Wait()
|
|
}
|
|
|
|
func GeneratePkgs(directory string, goMod2NixPath string, numWorkers int) ([]*schema.Package, error) {
|
|
modDownloads, replace, err := common(directory)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
executor := lib.NewParallellExecutor(numWorkers)
|
|
var mux sync.Mutex
|
|
|
|
cache := schema.ReadCache(goMod2NixPath)
|
|
|
|
packages := []*schema.Package{}
|
|
addPkg := func(pkg *schema.Package) {
|
|
mux.Lock()
|
|
packages = append(packages, pkg)
|
|
mux.Unlock()
|
|
}
|
|
|
|
for _, dl := range modDownloads {
|
|
dl := dl
|
|
|
|
goPackagePath, hasReplace := replace[dl.Path]
|
|
if !hasReplace {
|
|
goPackagePath = dl.Path
|
|
}
|
|
|
|
cached, ok := cache[goPackagePath]
|
|
if ok && cached.Version == dl.Version {
|
|
addPkg(cached)
|
|
continue
|
|
}
|
|
|
|
executor.Add(func() error {
|
|
log.WithFields(log.Fields{
|
|
"goPackagePath": goPackagePath,
|
|
}).Info("Calculating NAR hash")
|
|
|
|
h := sha256.New()
|
|
err := nar.DumpPathFilter(h, dl.Dir, sourceFilter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
digest := h.Sum(nil)
|
|
|
|
pkg := &schema.Package{
|
|
GoPackagePath: goPackagePath,
|
|
Version: dl.Version,
|
|
Hash: "sha256-" + base64.StdEncoding.EncodeToString(digest),
|
|
}
|
|
if hasReplace {
|
|
pkg.ReplacedPath = dl.Path
|
|
}
|
|
|
|
addPkg(pkg)
|
|
|
|
log.WithFields(log.Fields{
|
|
"goPackagePath": goPackagePath,
|
|
}).Info("Done calculating NAR hash")
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
err = executor.Wait()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sort.Slice(packages, func(i, j int) bool {
|
|
return packages[i].GoPackagePath < packages[j].GoPackagePath
|
|
})
|
|
|
|
return packages, nil
|
|
|
|
}
|