0
0
mirror of https://github.com/whyrusleeping/gx synced 2025-10-06 07:32:40 +02:00
Files
gx/check.go
2018-05-03 13:32:31 -07:00

129 lines
2.7 KiB
Go

package main
import (
"fmt"
"sort"
gx "github.com/whyrusleeping/gx/gxutil"
"github.com/blang/semver"
)
type pkgImport struct {
parents []string
version semver.Version
}
func check(pkg *gx.Package) (bool, error) {
var failed bool
// name -> hash -> path+version
packages := make(map[string]map[string]*pkgImport)
var traverse func(*gx.Package) error
traverse = func(pkg *gx.Package) error {
return pkg.ForEachDep(func(dep *gx.Dependency, dpkg *gx.Package) error {
pkgVersions, ok := packages[dpkg.Name]
if !ok {
pkgVersions = make(map[string]*pkgImport, 1)
packages[dpkg.Name] = pkgVersions
}
imp, ok := pkgVersions[dep.Hash]
if !ok {
version, err := semver.Parse(dpkg.Version)
if dpkg.Version != "" && err != nil {
fmt.Printf(
"package %s (%s) has an invalid version '%s': %s\n",
dpkg.Name,
dep.Hash,
dpkg.Version,
err,
)
}
pkgVersions[dep.Hash] = &pkgImport{
version: version,
parents: []string{pkg.Name},
}
return traverse(dpkg)
}
imp.parents = append(imp.parents, pkg.Name)
return nil
})
}
if err := traverse(pkg); err != nil {
return !failed, err
}
var dupes []string
for name, pkgVersions := range packages {
switch len(pkgVersions) {
case 0:
panic("must have at least one package version")
case 1:
continue
}
dupes = append(dupes, name)
}
if len(dupes) > 0 {
failed = true
sort.Strings(dupes)
for _, name := range dupes {
pkgVersions := packages[name]
hashes := make([]string, 0, len(pkgVersions))
for h := range pkgVersions {
hashes = append(hashes, h)
}
sort.Slice(hashes, func(i, j int) bool {
ih := hashes[i]
jh := hashes[j]
iv := pkgVersions[ih].version
jv := pkgVersions[jh].version
if res := iv.Compare(jv); res != 0 {
return res < 0
}
return ih < jh
})
fmt.Printf("package %s imported as:\n", name)
for _, hash := range hashes {
imp := pkgVersions[hash]
fmt.Printf(" - %s %s\n", imp.version, hash)
sort.Strings(imp.parents)
for _, p := range imp.parents {
fmt.Printf(" - %s\n", p)
}
}
}
}
// Finally, check names and versions.
if err := pkg.ForEachDep(func(dep *gx.Dependency, dpkg *gx.Package) error {
if dep.Name != dpkg.Name {
failed = true
fmt.Printf(
"dependency %s references a package with name %s\n",
dep.Name,
dpkg.Name,
)
}
if dep.Version != dpkg.Version {
failed = true
fmt.Printf(
"dependency %s has version %s but the referenced package has version %s\n",
dep.Name,
dep.Version,
dpkg.Version,
)
}
return nil
}); err != nil {
return !failed, err
}
return !failed, nil
}