github.com/whyrusleeping/gx@v0.14.3/check.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "sort" 6 7 gx "github.com/whyrusleeping/gx/gxutil" 8 9 "github.com/blang/semver" 10 ) 11 12 type pkgImport struct { 13 parents []string 14 version semver.Version 15 } 16 17 func check(pkg *gx.Package) (bool, error) { 18 var failed bool 19 // name -> hash -> path+version 20 packages := make(map[string]map[string]*pkgImport) 21 22 var traverse func(*gx.Package) error 23 traverse = func(pkg *gx.Package) error { 24 return pkg.ForEachDep(func(dep *gx.Dependency, dpkg *gx.Package) error { 25 pkgVersions, ok := packages[dpkg.Name] 26 if !ok { 27 pkgVersions = make(map[string]*pkgImport, 1) 28 packages[dpkg.Name] = pkgVersions 29 } 30 imp, ok := pkgVersions[dep.Hash] 31 if !ok { 32 version, err := semver.Parse(dpkg.Version) 33 if dpkg.Version != "" && err != nil { 34 fmt.Printf( 35 "package %s (%s) has an invalid version '%s': %s\n", 36 dpkg.Name, 37 dep.Hash, 38 dpkg.Version, 39 err, 40 ) 41 } 42 pkgVersions[dep.Hash] = &pkgImport{ 43 version: version, 44 parents: []string{pkg.Name}, 45 } 46 return traverse(dpkg) 47 } 48 imp.parents = append(imp.parents, pkg.Name) 49 return nil 50 }) 51 } 52 53 if err := traverse(pkg); err != nil { 54 return !failed, err 55 } 56 57 var dupes []string 58 for name, pkgVersions := range packages { 59 switch len(pkgVersions) { 60 case 0: 61 panic("must have at least one package version") 62 case 1: 63 continue 64 } 65 dupes = append(dupes, name) 66 } 67 68 if len(dupes) > 0 { 69 failed = true 70 sort.Strings(dupes) 71 72 for _, name := range dupes { 73 pkgVersions := packages[name] 74 75 hashes := make([]string, 0, len(pkgVersions)) 76 for h := range pkgVersions { 77 hashes = append(hashes, h) 78 } 79 80 sort.Slice(hashes, func(i, j int) bool { 81 ih := hashes[i] 82 jh := hashes[j] 83 iv := pkgVersions[ih].version 84 jv := pkgVersions[jh].version 85 if res := iv.Compare(jv); res != 0 { 86 return res < 0 87 } 88 return ih < jh 89 }) 90 91 fmt.Printf("package %s imported as:\n", name) 92 for _, hash := range hashes { 93 imp := pkgVersions[hash] 94 95 fmt.Printf(" - %s %s\n", imp.version, hash) 96 sort.Strings(imp.parents) 97 for _, p := range imp.parents { 98 fmt.Printf(" - %s\n", p) 99 } 100 } 101 } 102 } 103 104 // Finally, check names and versions. 105 if err := pkg.ForEachDep(func(dep *gx.Dependency, dpkg *gx.Package) error { 106 if dep.Name != dpkg.Name { 107 failed = true 108 fmt.Printf( 109 "dependency %s references a package with name %s\n", 110 dep.Name, 111 dpkg.Name, 112 ) 113 } 114 if dep.Version != dpkg.Version { 115 failed = true 116 fmt.Printf( 117 "dependency %s has version %s but the referenced package has version %s\n", 118 dep.Name, 119 dep.Version, 120 dpkg.Version, 121 ) 122 } 123 return nil 124 }); err != nil { 125 return !failed, err 126 } 127 return !failed, nil 128 }