got async working
parent
367880643b
commit
3a29e3b289
2
go.mod
2
go.mod
|
|
@ -2,4 +2,4 @@ module github.com/adamveld12/gpm
|
|||
|
||||
go 1.14
|
||||
|
||||
require github.com/Masterminds/semver v1.5.0
|
||||
require github.com/Masterminds/semver v1.4.3-0.20190911182330-3c3e3c79b8d8
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -1,2 +1,4 @@
|
|||
github.com/Masterminds/semver v1.4.3-0.20190911182330-3c3e3c79b8d8 h1:fRMn4k/mYz+TbNFoDYD96QX3gpymTJhB87G2RNChYmg=
|
||||
github.com/Masterminds/semver v1.4.3-0.20190911182330-3c3e3c79b8d8/go.mod h1:8CV7kYbvgykQs8Io0EDPxUVkQQsXveUpKzLB6tuHV2w=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
|
|
|
|||
182
lib/deptree.go
182
lib/deptree.go
|
|
@ -3,71 +3,13 @@ package lib
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
)
|
||||
|
||||
func BuildDependencyTree(rp PackageJSON) (*DependencyList, error) {
|
||||
resolved := map[string]Dependency{}
|
||||
unresolved := []Dependency{
|
||||
Dependency{Name: rp.Name, Requires: rp.Dependencies},
|
||||
}
|
||||
|
||||
for len(unresolved) > 0 {
|
||||
unresolvedDep := unresolved[0]
|
||||
unresolved = unresolved[1:len(unresolved)]
|
||||
|
||||
for k, p := range unresolvedDep.Requires {
|
||||
meta, err := GetPackageInfo(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err := semver.NewConstraint(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var selectedRelease PackageRelease
|
||||
var max *semver.Version
|
||||
for r, release := range meta.Versions {
|
||||
v, err := semver.NewVersion(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.Check(v) && (max == nil || v.GreaterThan(max)) {
|
||||
selectedRelease = release
|
||||
max = v
|
||||
}
|
||||
}
|
||||
|
||||
unresolved = append(unresolved, Dependency{
|
||||
Name: selectedRelease.Name,
|
||||
Version: selectedRelease.VersionNumber,
|
||||
Integrity: selectedRelease.Dist.Sum,
|
||||
Resolved: selectedRelease.Dist.Tarball,
|
||||
Requires: selectedRelease.Dependencies,
|
||||
})
|
||||
}
|
||||
|
||||
// don't add root dep to the resolve list
|
||||
if unresolvedDep.Name == rp.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
resolved[unresolvedDep.Name] = unresolvedDep
|
||||
}
|
||||
|
||||
return &DependencyList{
|
||||
Name: rp.Name,
|
||||
Version: rp.Version,
|
||||
LockfileVersion: 1,
|
||||
Requires: true,
|
||||
Dependencies: resolved,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Dependency struct {
|
||||
Name string
|
||||
Version string
|
||||
|
|
@ -94,9 +36,125 @@ func (d Dependency) String() string {
|
|||
type RequireList map[string]string
|
||||
|
||||
type DependencyList struct {
|
||||
sync.Mutex
|
||||
deps map[string]Dependency
|
||||
}
|
||||
|
||||
func (r *DependencyList) Get(key string) (Dependency, bool) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if value, ok := r.deps[key]; ok {
|
||||
return value, true
|
||||
}
|
||||
return Dependency{}, false
|
||||
}
|
||||
|
||||
func (r *DependencyList) Set(value Dependency) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.deps[value.Name] = value
|
||||
}
|
||||
|
||||
type Package struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
LockfileVersion int `json:"lockfileVersion"`
|
||||
Requires bool `json:"requires"`
|
||||
Dependencies map[string]Dependency `json:"dependencies"`
|
||||
Dependencies DependencyList `json:"dependencies"`
|
||||
}
|
||||
|
||||
const badVersionNumberFmtErrStr = "bad version number provided for package '%s' got '%s': %v"
|
||||
|
||||
func resolveDependency(rootPackageName string, resolvedQueue chan<- Dependency, unresolvedQueue chan Dependency, wg *sync.WaitGroup, resolved *DependencyList) {
|
||||
for unresolvedDep := range unresolvedQueue {
|
||||
for k, p := range unresolvedDep.Requires {
|
||||
meta, err := GetPackageInfo(k)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
// return nil, err
|
||||
}
|
||||
|
||||
c, err := semver.NewConstraint(p)
|
||||
if err != nil {
|
||||
log.Fatalf("bad version constraint for package '%s': %v", k, err)
|
||||
}
|
||||
|
||||
if resolvedDep, ok := resolved.Get(k); ok {
|
||||
version, err := semver.NewVersion(resolvedDep.Version)
|
||||
if err != nil {
|
||||
log.Fatalf(badVersionNumberFmtErrStr, resolvedDep.Name, resolvedDep.Version, err)
|
||||
}
|
||||
|
||||
if c.Check(version) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
var selectedRelease PackageRelease
|
||||
var max *semver.Version
|
||||
for r, release := range meta.Versions {
|
||||
v, err := semver.NewVersion(r)
|
||||
if err != nil {
|
||||
log.Fatalf(badVersionNumberFmtErrStr, release.Name, r, err)
|
||||
}
|
||||
|
||||
if c.Check(v) && (max == nil || v.GreaterThan(max)) {
|
||||
selectedRelease = release
|
||||
max = v
|
||||
}
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(sr PackageRelease) {
|
||||
unresolvedQueue <- Dependency{
|
||||
Name: sr.Name,
|
||||
Version: sr.VersionNumber,
|
||||
Integrity: sr.Dist.Sum,
|
||||
Resolved: sr.Dist.Tarball,
|
||||
Requires: sr.Dependencies,
|
||||
}
|
||||
}(selectedRelease)
|
||||
}
|
||||
|
||||
// don't add root dep to the resolve list
|
||||
if unresolvedDep.Name == rootPackageName {
|
||||
wg.Done()
|
||||
continue
|
||||
}
|
||||
|
||||
resolvedQueue <- unresolvedDep
|
||||
}
|
||||
}
|
||||
|
||||
func BuildDependencyTree(rp PackageJSON) (*Package, error) {
|
||||
resolved := &DependencyList{deps: map[string]Dependency{}}
|
||||
wg := &sync.WaitGroup{}
|
||||
resolvedQueue, unresolvedQueue := make(chan Dependency), make(chan Dependency, 1)
|
||||
unresolvedQueue <- Dependency{Name: rp.Name, Requires: rp.Dependencies}
|
||||
wg.Add(1)
|
||||
|
||||
for i := 0; i <= runtime.GOMAXPROCS(-1); i++ {
|
||||
go resolveDependency(rp.Name, resolvedQueue, unresolvedQueue, wg, resolved)
|
||||
}
|
||||
|
||||
go func(rq <-chan Dependency, wg *sync.WaitGroup){
|
||||
for dep := range rq{
|
||||
resolved.Set(dep)
|
||||
wg.Done()
|
||||
}
|
||||
}(resolvedQueue, wg)
|
||||
|
||||
wg.Wait()
|
||||
close(resolvedQueue)
|
||||
close(unresolvedQueue)
|
||||
|
||||
return &Package{
|
||||
Name: rp.Name,
|
||||
Version: rp.Version,
|
||||
LockfileVersion: 1,
|
||||
Requires: true,
|
||||
Dependencies: *resolved,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package lib
|
|||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
)
|
||||
|
||||
const simplePackageJSON = `
|
||||
|
|
@ -27,7 +29,7 @@ func TestBuildDependencyTree(t *testing.T) {
|
|||
name string
|
||||
args PackageJSON
|
||||
depCount int
|
||||
want map[string]Dependency
|
||||
want DependencyList
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
|
|
@ -44,21 +46,9 @@ func TestBuildDependencyTree(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "webpack test",
|
||||
depCount: 13,
|
||||
wantErr: false,
|
||||
args: PackageJSON{
|
||||
Name: "webpack",
|
||||
Dependencies: map[string]string{
|
||||
"webpack": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "react test",
|
||||
depCount: 13,
|
||||
depCount: 6,
|
||||
wantErr: false,
|
||||
args: PackageJSON{
|
||||
Name: "website",
|
||||
|
|
@ -67,6 +57,17 @@ func TestBuildDependencyTree(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "webpack test",
|
||||
depCount: 310,
|
||||
wantErr: false,
|
||||
args: PackageJSON{
|
||||
Name: "webpack",
|
||||
Dependencies: map[string]string{
|
||||
"webpack": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
@ -79,10 +80,27 @@ func TestBuildDependencyTree(t *testing.T) {
|
|||
|
||||
t.Logf("%+v", got)
|
||||
|
||||
if len(got.Dependencies) != tt.depCount {
|
||||
t.Errorf("BuildDependencyTree() = %v, want %v", len(got.Dependencies), tt.depCount)
|
||||
if len(got.Dependencies.deps) != tt.depCount {
|
||||
t.Errorf("BuildDependencyTree() = %v, want %v", len(got.Dependencies.deps), tt.depCount)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSemVerBug(t *testing.T) {
|
||||
c, err := semver.NewConstraint(">= 2.1.2 < 3")
|
||||
if err != nil {
|
||||
t.Errorf("could not create new version constraint: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
v, err := semver.NewVersion("2.2.3")
|
||||
if err != nil {
|
||||
t.Errorf("could not create new version: %v", err)
|
||||
return
|
||||
}
|
||||
if !c.Check(v) {
|
||||
t.Error("could not validate version")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue