got async working

async
Adam Veldhousen 2020-03-22 18:45:26 -05:00
parent 367880643b
commit 3a29e3b289
Signed by: adam
GPG Key ID: 6DB29003C6DD1E4B
4 changed files with 157 additions and 79 deletions

2
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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
}

View File

@ -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")
}
}