Compare commits

..

13 Commits

Author SHA1 Message Date
mudler
d5d21653d7 ⬆️ Tag 0.32.5 2022-06-08 00:13:36 +02:00
mudler
913462b81c 🎨 Swap toposort implementation 2022-06-08 00:13:36 +02:00
Ettore Di Giacinto
aeb686f426 ⬆️ Tag 0.32.4 2022-06-07 20:22:44 +02:00
Ettore Di Giacinto
f98cd401be 🐛 Fixup bad return on first cycle 2022-06-07 20:21:37 +02:00
Ettore Di Giacinto
70f99b6bb7 ⬆️ Tag 0.32.3 2022-06-07 13:10:22 +02:00
Ettore Di Giacinto
cfbd8bf708 🐛 Fixup finalizer detection
This caused finalizers to run also for already-installed packages
2022-06-07 13:09:52 +02:00
mudler
4cb21a3e02 🎨 Match exit status with panic 2022-06-06 23:33:55 +02:00
mudler
3a31639897 🎨 Don't panic on Fatal 2022-06-06 23:09:39 +02:00
Ettore Di Giacinto
bac9bac25f ⬆️ Tag 0.32.2 2022-06-06 17:39:58 +02:00
Ettore Di Giacinto
ce95b3ada4 🎨 Cleanups 2022-06-06 17:39:16 +02:00
mudler
49d8c2b972 🎨 Add test-integration-docker target 2022-06-06 17:39:16 +02:00
mudler
2b3a1555f0 🎨 Refactor, use ensureoder where necessary 2022-06-06 17:39:16 +02:00
Itxaka
03e72653c7 Fill referenceID on repo sync (#300)
Signed-off-by: Itxaka <igarcia@suse.com>
2022-06-06 17:36:19 +02:00
16 changed files with 330 additions and 239 deletions

View File

@@ -30,7 +30,7 @@ var cfgFile string
var Verbose bool var Verbose bool
const ( const (
LuetCLIVersion = "0.32.1" LuetCLIVersion = "0.32.5"
LuetEnvPrefix = "LUET" LuetEnvPrefix = "LUET"
) )

3
go.mod
View File

@@ -28,6 +28,7 @@ require (
github.com/imdario/mergo v0.3.12 github.com/imdario/mergo v0.3.12
github.com/ipfs/go-log/v2 v2.4.0 github.com/ipfs/go-log/v2 v2.4.0
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3
github.com/kendru/darwin/go/depgraph v0.0.0-20220319173517-8abc3541da93
github.com/klauspost/compress v1.15.1 github.com/klauspost/compress v1.15.1
github.com/klauspost/pgzip v1.2.5 github.com/klauspost/pgzip v1.2.5
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
@@ -49,11 +50,9 @@ require (
github.com/otiai10/copy v1.2.1-0.20200916181228-26f84a0b1578 github.com/otiai10/copy v1.2.1-0.20200916181228-26f84a0b1578
github.com/pelletier/go-toml v1.9.4 github.com/pelletier/go-toml v1.9.4
github.com/peterbourgon/diskv v2.0.1+incompatible github.com/peterbourgon/diskv v2.0.1+incompatible
github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/pterm/pterm v0.12.32-0.20211002183613-ada9ef6790c3 github.com/pterm/pterm v0.12.32-0.20211002183613-ada9ef6790c3
github.com/rancher-sandbox/gofilecache v0.0.0-20210330135715-becdeff5df15 github.com/rancher-sandbox/gofilecache v0.0.0-20210330135715-becdeff5df15
github.com/scrohde/go-toposort v0.0.0-20170629203416-a9a902e065a3 // indirect
github.com/spf13/cast v1.4.1 // indirect github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.2.1 github.com/spf13/cobra v1.2.1
github.com/spf13/viper v1.8.1 github.com/spf13/viper v1.8.1

6
go.sum
View File

@@ -927,6 +927,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kendru/darwin/go/depgraph v0.0.0-20220319173517-8abc3541da93 h1:bnXl8jWYsxRiO4Jc70GDKH2KhB4yRDlFAxjGng4v8+0=
github.com/kendru/darwin/go/depgraph v0.0.0-20220319173517-8abc3541da93/go.mod h1:VOfm8h1NySetVlpHDSnbpCMsvCgYaU+YDn4XezUy2+4=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@@ -1201,8 +1203,6 @@ github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw=
github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f h1:WyCn68lTiytVSkk7W1K9nBiSGTSRlUOdyTnSjwrIlok=
github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f/go.mod h1:/iRjX3DdSK956SzsUdV55J+wIsQ+2IBWmBrB4RvZfk4=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -1300,8 +1300,6 @@ github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
github.com/scrohde/go-toposort v0.0.0-20170629203416-a9a902e065a3 h1:i8yAzeysv+UgLJ0O8usGQHvtyM0AbPHlI03l5OnWD4A=
github.com/scrohde/go-toposort v0.0.0-20170629203416-a9a902e065a3/go.mod h1:FzYqW619hxj8ogwgAr2ENoIELLwatZvaBnWdTquP99U=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=

View File

@@ -17,6 +17,7 @@ package logger
import ( import (
"fmt" "fmt"
"os"
"path" "path"
"regexp" "regexp"
"runtime" "runtime"
@@ -254,7 +255,7 @@ func (l *Logger) Tracef(t string, args ...interface{}) {
func (l *Logger) Fatal(args ...interface{}) { func (l *Logger) Fatal(args ...interface{}) {
l.send(log.LevelFatal, "", args...) l.send(log.LevelFatal, "", args...)
panic("fatal error") os.Exit(2)
} }
func (l *Logger) Info(args ...interface{}) { func (l *Logger) Info(args ...interface{}) {

View File

@@ -6,10 +6,9 @@ import (
"sort" "sort"
"unicode" "unicode"
"github.com/mudler/luet/pkg/helpers" "github.com/kendru/darwin/go/depgraph"
"github.com/mudler/topsort" "github.com/mudler/topsort"
"github.com/pkg/errors" "github.com/pkg/errors"
toposort "github.com/scrohde/go-toposort"
) )
// PackageAssert represent a package assertion. // PackageAssert represent a package assertion.
@@ -36,42 +35,31 @@ func (assertions PackagesAssertions) EnsureOrder(definitiondb PackageDatabase) (
allAssertions := assertions allAssertions := assertions
orderedAssertions := PackagesAssertions{} orderedAssertions := PackagesAssertions{}
tmpMap := map[string]PackageAssert{} tmpMap := map[string]PackageAssert{}
g := depgraph.New()
graph := toposort.NewGraph(len(allAssertions))
for _, a := range assertions { for _, a := range assertions {
tmpMap[a.Package.GetPackageName()] = a tmpMap[a.Package.GetPackageName()] = a
graph.AddNode(a.Package.GetPackageName())
} }
edges := map[string]string{}
// Build a topological graph // Build a topological graph
for _, a := range allAssertions { for _, a := range allAssertions {
for _, req := range a.Package.GetRequires() { for _, req := range a.Package.GetRequires() {
if def, err := definitiondb.FindPackage(req); err == nil { // Provides: Get a chance of being override here if def, err := definitiondb.FindPackage(req); err == nil { // Provides: Get a chance of being override here
req = def req = def
} }
edges[a.Package.GetPackageName()] = req.GetPackageName() g.DependOn(a.Package.GetPackageName(), req.GetPackageName())
graph.AddNode(req.GetPackageName())
} }
} }
for k, v := range edges { for _, res := range g.TopoSortedLayers() {
graph.AddEdge(k, v) for _, r := range res {
} a, ok := tmpMap[r]
if ok {
result, ok := graph.ToposortStable() orderedAssertions = append(orderedAssertions, a)
if !ok { }
return nil, fmt.Errorf("cycle found")
}
for _, res := range result {
a, ok := tmpMap[res]
if ok {
orderedAssertions = append(orderedAssertions, a)
} }
} }
helpers.ReverseAny(orderedAssertions) // helpers.ReverseAny(orderedAssertions)
return orderedAssertions, nil return orderedAssertions, nil
} }

View File

@@ -82,5 +82,35 @@ var _ = Describe("Assertions", func() {
Expect(ordered[0].Package.Name).To(Equal("bar")) Expect(ordered[0].Package.Name).To(Equal("bar"))
Expect(ordered[1].Package.Name).To(Equal("foobaz")) Expect(ordered[1].Package.Name).To(Equal("foobaz"))
}) })
It("orders them correctly", func() {
foo := &types.Package{Name: "foo", PackageRequires: []*types.Package{{Name: "bar"}}}
assertions := types.PackagesAssertions{
{Package: foo},
{Package: &types.Package{Name: "bazbaz2", PackageRequires: []*types.Package{{Name: "baz2"}}}},
{Package: &types.Package{Name: "baz2", PackageRequires: []*types.Package{{Name: "foobaz"}, {Name: "baz"}}}},
{Package: &types.Package{Name: "baz", PackageRequires: []*types.Package{{Name: "bar"}}}},
{Package: &types.Package{Name: "bar", PackageRequires: []*types.Package{{}}}},
{Package: &types.Package{Name: "foobaz", PackageRequires: []*types.Package{{}}}},
}
ordered_old, err := assertions.Order(database.NewInMemoryDatabase(false), foo.GetFingerPrint())
Expect(err).ShouldNot(HaveOccurred())
Expect(ordered_old[0].Package.Name).To(Equal("bar"))
Expect(ordered_old[1].Package.Name).ToNot(Equal("foobaz"))
ordered, err := assertions.EnsureOrder(database.NewInMemoryDatabase(false))
Expect(err).ShouldNot(HaveOccurred())
Expect(len(ordered)).To(Equal(6))
Expect(ordered[0].Package.Name).To(Or(Equal("foobaz"), Equal("bar")))
Expect(ordered[1].Package.Name).To(Or(Equal("foobaz"), Equal("bar")))
Expect(ordered[2].Package.Name).To(Or(Equal("foo"), Equal("baz")))
Expect(ordered[3].Package.Name).To(Or(Equal("foo"), Equal("baz")))
Expect(ordered[4].Package.Name).To(Equal("baz2"))
Expect(ordered[5].Package.Name).To(Equal("bazbaz2"))
})
}) })
}) })

View File

@@ -95,6 +95,26 @@ func NewLuetFinalizerFromYaml(data []byte) (*LuetFinalizer, error) {
func OrderFinalizers(allRepos types.PackageDatabase, toInstall map[string]ArtifactMatch, solution types.PackagesAssertions) ([]*types.Package, error) { func OrderFinalizers(allRepos types.PackageDatabase, toInstall map[string]ArtifactMatch, solution types.PackagesAssertions) ([]*types.Package, error) {
var toFinalize []*types.Package var toFinalize []*types.Package
populate := func(ordered types.PackagesAssertions) error {
for _, ass := range ordered {
if ass.Value {
installed, ok := toInstall[ass.Package.GetFingerPrint()]
if !ok {
// It was a dep already installed in the system, so we can skip it safely
continue
}
treePackage, err := installed.Repository.GetTree().GetDatabase().FindPackage(ass.Package)
if err != nil {
return errors.Wrap(err, "Error getting package "+ass.Package.HumanReadableString())
}
toFinalize = append(toFinalize, treePackage)
}
}
return nil
}
if len(toInstall) == 1 { if len(toInstall) == 1 {
for _, w := range toInstall { for _, w := range toInstall {
if fileHelper.Exists(w.Package.Rel(tree.FinalizerFile)) { if fileHelper.Exists(w.Package.Rel(tree.FinalizerFile)) {
@@ -103,21 +123,8 @@ func OrderFinalizers(allRepos types.PackageDatabase, toInstall map[string]Artifa
if err != nil { if err != nil {
return toFinalize, errors.Wrap(err, "While order a solution for "+w.Package.HumanReadableString()) return toFinalize, errors.Wrap(err, "While order a solution for "+w.Package.HumanReadableString())
} }
ORDER: if err := populate(ordered); err != nil {
for _, ass := range ordered { return toFinalize, err
if ass.Value {
installed, ok := toInstall[ass.Package.GetFingerPrint()]
if !ok {
// It was a dep already installed in the system, so we can skip it safely
continue ORDER
}
treePackage, err := installed.Repository.GetTree().GetDatabase().FindPackage(ass.Package)
if err != nil {
return toFinalize, errors.Wrap(err, "Error getting package "+ass.Package.HumanReadableString())
}
toFinalize = append(toFinalize, treePackage)
}
} }
} }
} }
@@ -127,10 +134,8 @@ func OrderFinalizers(allRepos types.PackageDatabase, toInstall map[string]Artifa
return toFinalize, err return toFinalize, err
} }
for _, o := range assertions { if err := populate(assertions); err != nil {
if o.Value { return toFinalize, err
toFinalize = append(toFinalize, o.Package)
}
} }
} }

View File

@@ -457,6 +457,14 @@ func (r *LuetSystemRepository) SetVerify(p bool) {
r.LuetRepository.Verify = p r.LuetRepository.Verify = p
} }
func (r *LuetSystemRepository) GetReferenceID() string {
return r.LuetRepository.ReferenceID
}
func (r *LuetSystemRepository) SetReferenceID(ref string) {
r.LuetRepository.ReferenceID = ref
}
func (r *LuetSystemRepository) GetBackend() compiler.CompilerBackend { func (r *LuetSystemRepository) GetBackend() compiler.CompilerBackend {
return r.Backend return r.Backend
} }
@@ -1051,6 +1059,7 @@ func (r *LuetSystemRepository) fill(r2 *LuetSystemRepository) {
r2.SetPriority(r.GetPriority()) r2.SetPriority(r.GetPriority())
r2.SetName(r.GetName()) r2.SetName(r.GetName())
r2.SetVerify(r.GetVerify()) r2.SetVerify(r.GetVerify())
r2.SetReferenceID(r.GetReferenceID())
} }
func (r *LuetSystemRepository) Serialize() (*LuetSystemRepositoryMetadata, LuetSystemRepository) { func (r *LuetSystemRepository) Serialize() (*LuetSystemRepositoryMetadata, LuetSystemRepository) {

232
vendor/github.com/kendru/darwin/go/depgraph/depgraph.go generated vendored Normal file
View File

@@ -0,0 +1,232 @@
package depgraph
import (
"errors"
)
// A node in this graph is just a string, so a nodeset is a map whose
// keys are the nodes that are present.
type nodeset map[string]struct{}
// depmap tracks the nodes that have some dependency relationship to
// some other node, represented by the key of the map.
type depmap map[string]nodeset
type Graph struct {
nodes nodeset
// Maintain dependency relationships in both directions. These
// data structures are the edges of the graph.
// `dependencies` tracks child -> parents.
dependencies depmap
// `dependents` tracks parent -> children.
dependents depmap
// Keep track of the nodes of the graph themselves.
}
func New() *Graph {
return &Graph{
dependencies: make(depmap),
dependents: make(depmap),
nodes: make(nodeset),
}
}
func (g *Graph) DependOn(child, parent string) error {
if child == parent {
return errors.New("self-referential dependencies not allowed")
}
if g.DependsOn(parent, child) {
return errors.New("circular dependencies not allowed")
}
// Add nodes.
g.nodes[parent] = struct{}{}
g.nodes[child] = struct{}{}
// Add edges.
addNodeToNodeset(g.dependents, parent, child)
addNodeToNodeset(g.dependencies, child, parent)
return nil
}
func (g *Graph) DependsOn(child, parent string) bool {
deps := g.Dependencies(child)
_, ok := deps[parent]
return ok
}
func (g *Graph) HasDependent(parent, child string) bool {
deps := g.Dependents(parent)
_, ok := deps[child]
return ok
}
func (g *Graph) Leaves() []string {
leaves := make([]string, 0)
for node := range g.nodes {
if _, ok := g.dependencies[node]; !ok {
leaves = append(leaves, node)
}
}
return leaves
}
// TopoSortedLayers returns a slice of all of the graph nodes in topological sort order. That is,
// if `B` depends on `A`, then `A` is guaranteed to come before `B` in the sorted output.
// The graph is guaranteed to be cycle-free because cycles are detected while building the
// graph. Additionally, the output is grouped into "layers", which are guaranteed to not have
// any dependencies within each layer. This is useful, e.g. when building an execution plan for
// some DAG, in which case each element within each layer could be executed in parallel. If you
// do not need this layered property, use `Graph.TopoSorted()`, which flattens all elements.
func (g *Graph) TopoSortedLayers() [][]string {
layers := [][]string{}
// Copy the graph
shrinkingGraph := g.clone()
for {
leaves := shrinkingGraph.Leaves()
if len(leaves) == 0 {
break
}
layers = append(layers, leaves)
for _, leafNode := range leaves {
shrinkingGraph.remove(leafNode)
}
}
return layers
}
func removeFromDepmap(dm depmap, key, node string) {
nodes := dm[key]
if len(nodes) == 1 {
// The only element in the nodeset must be `node`, so we
// can delete the entry entirely.
delete(dm, key)
} else {
// Otherwise, remove the single node from the nodeset.
delete(nodes, node)
}
}
func (g *Graph) remove(node string) {
// Remove edges from things that depend on `node`.
for dependent := range g.dependents[node] {
removeFromDepmap(g.dependencies, dependent, node)
}
delete(g.dependents, node)
// Remove all edges from node to the things it depends on.
for dependency := range g.dependencies[node] {
removeFromDepmap(g.dependents, dependency, node)
}
delete(g.dependencies, node)
// Finally, remove the node itself.
delete(g.nodes, node)
}
// TopoSorted returns all the nodes in the graph is topological sort order.
// See also `Graph.TopoSortedLayers()`.
func (g *Graph) TopoSorted() []string {
nodeCount := 0
layers := g.TopoSortedLayers()
for _, layer := range layers {
nodeCount += len(layer)
}
allNodes := make([]string, 0, nodeCount)
for _, layer := range layers {
for _, node := range layer {
allNodes = append(allNodes, node)
}
}
return allNodes
}
func (g *Graph) Dependencies(child string) nodeset {
return g.buildTransitive(child, g.immediateDependencies)
}
func (g *Graph) immediateDependencies(node string) nodeset {
return g.dependencies[node]
}
func (g *Graph) Dependents(parent string) nodeset {
return g.buildTransitive(parent, g.immediateDependents)
}
func (g *Graph) immediateDependents(node string) nodeset {
return g.dependents[node]
}
func (g *Graph) clone() *Graph {
return &Graph{
dependencies: copyDepmap(g.dependencies),
dependents: copyDepmap(g.dependents),
nodes: copyNodeset(g.nodes),
}
}
// buildTransitive starts at `root` and continues calling `nextFn` to keep discovering more nodes until
// the graph cannot produce any more. It returns the set of all discovered nodes.
func (g *Graph) buildTransitive(root string, nextFn func(string) nodeset) nodeset {
if _, ok := g.nodes[root]; !ok {
return nil
}
out := make(nodeset)
searchNext := []string{root}
for len(searchNext) > 0 {
// List of new nodes from this layer of the dependency graph. This is
// assigned to `searchNext` at the end of the outer "discovery" loop.
discovered := []string{}
for _, node := range searchNext {
// For each node to discover, find the next nodes.
for nextNode := range nextFn(node) {
// If we have not seen the node before, add it to the output as well
// as the list of nodes to traverse in the next iteration.
if _, ok := out[nextNode]; !ok {
out[nextNode] = struct{}{}
discovered = append(discovered, nextNode)
}
}
}
searchNext = discovered
}
return out
}
func copyNodeset(s nodeset) nodeset {
out := make(nodeset, len(s))
for k, v := range s {
out[k] = v
}
return out
}
func copyDepmap(m depmap) depmap {
out := make(depmap, len(m))
for k, v := range m {
out[k] = copyNodeset(v)
}
return out
}
func addNodeToNodeset(dm depmap, key, node string) {
nodes, ok := dm[key]
if !ok {
nodes = make(nodeset)
dm[key] = nodes
}
nodes[node] = struct{}{}
}

5
vendor/github.com/kendru/darwin/go/depgraph/go.mod generated vendored Normal file
View File

@@ -0,0 +1,5 @@
module github.com/kendru/darwin/go/depgraph
go 1.16
require github.com/stretchr/testify v1.7.0

11
vendor/github.com/kendru/darwin/go/depgraph/go.sum generated vendored Normal file
View File

@@ -0,0 +1,11 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -1,6 +0,0 @@
language: go
go:
- 1.5
- 1.6
- 1.7
- master

View File

@@ -1,7 +0,0 @@
Copyright 2017 Hirotomo Moriwaki
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,53 +0,0 @@
go-toposort
==
[![Build Status](https://travis-ci.org/philopon/go-toposort.svg?branch=master)](https://travis-ci.org/philopon/go-toposort)
[![GoDoc](https://godoc.org/github.com/philopon/go-toposort?status.svg)](https://godoc.org/github.com/philopon/go-toposort)
deterministic topological sort implementation for golang
Example
--
```.go
package main
import (
"fmt"
toposort "github.com/philopon/go-toposort"
)
func main() {
graph := toposort.NewGraph(8)
graph.AddNodes("2", "3", "5", "7", "8", "9", "10", "11")
graph.AddEdge("7", "8")
graph.AddEdge("7", "11")
graph.AddEdge("5", "11")
graph.AddEdge("3", "8")
graph.AddEdge("3", "10")
graph.AddEdge("11", "2")
graph.AddEdge("11", "9")
graph.AddEdge("11", "10")
graph.AddEdge("8", "9")
result, ok := graph.Toposort()
if !ok {
panic("cycle detected")
}
fmt.Println(result)
}
```
```
[3 5 7 8 11 2 9 10]
```
License
--
MIT

View File

@@ -1,119 +0,0 @@
package toposort
import "sort"
type Graph struct {
nodes []string
outputs map[string]map[string]int
inputs map[string]int
}
func NewGraph(cap int) *Graph {
return &Graph{
nodes: make([]string, 0, cap),
inputs: make(map[string]int),
outputs: make(map[string]map[string]int),
}
}
func (g *Graph) AddNode(name string) bool {
g.nodes = append(g.nodes, name)
if _, ok := g.outputs[name]; ok {
return false
}
g.outputs[name] = make(map[string]int)
g.inputs[name] = 0
return true
}
func (g *Graph) AddNodes(names ...string) bool {
for _, name := range names {
if ok := g.AddNode(name); !ok {
return false
}
}
return true
}
func (g *Graph) AddEdge(from, to string) bool {
m, ok := g.outputs[from]
if !ok {
return false
}
m[to] = len(m) + 1
g.inputs[to]++
return true
}
func (g *Graph) unsafeRemoveEdge(from, to string) {
delete(g.outputs[from], to)
g.inputs[to]--
}
func (g *Graph) RemoveEdge(from, to string) bool {
if _, ok := g.outputs[from]; !ok {
return false
}
g.unsafeRemoveEdge(from, to)
return true
}
func (g *Graph) toposort(stable bool) ([]string, bool) {
L := make([]string, 0, len(g.nodes))
S := make([]string, 0, len(g.nodes))
for _, n := range g.nodes {
if g.inputs[n] == 0 {
S = append(S, n)
}
}
if stable {
sort.Strings(S)
}
for len(S) > 0 {
var n string
n, S = S[0], S[1:]
L = append(L, n)
ms := make([]string, len(g.outputs[n]))
for m, i := range g.outputs[n] {
ms[i-1] = m
}
if stable {
sort.Strings(ms)
}
for _, m := range ms {
g.unsafeRemoveEdge(n, m)
if g.inputs[m] == 0 {
S = append(S, m)
}
}
}
N := 0
for _, v := range g.inputs {
N += v
}
if N > 0 {
return L, false
}
return L, true
}
func (g *Graph) Toposort() ([]string, bool) {
return g.toposort(false)
}
func (g *Graph) ToposortStable() ([]string, bool) {
return g.toposort(true)
}

8
vendor/modules.txt vendored
View File

@@ -257,6 +257,9 @@ github.com/ipfs/go-log/v2
# github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 # github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3
## explicit ## explicit
github.com/jinzhu/copier github.com/jinzhu/copier
# github.com/kendru/darwin/go/depgraph v0.0.0-20220319173517-8abc3541da93
## explicit
github.com/kendru/darwin/go/depgraph
# github.com/klauspost/compress v1.15.1 # github.com/klauspost/compress v1.15.1
## explicit ## explicit
github.com/klauspost/compress github.com/klauspost/compress
@@ -368,8 +371,6 @@ github.com/pelletier/go-toml
# github.com/peterbourgon/diskv v2.0.1+incompatible # github.com/peterbourgon/diskv v2.0.1+incompatible
## explicit ## explicit
github.com/peterbourgon/diskv github.com/peterbourgon/diskv
# github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f
## explicit
# github.com/pkg/errors v0.9.1 # github.com/pkg/errors v0.9.1
## explicit ## explicit
github.com/pkg/errors github.com/pkg/errors
@@ -401,9 +402,6 @@ github.com/rogpeppe/go-internal/internal/syscall/windows
github.com/rogpeppe/go-internal/internal/syscall/windows/sysdll github.com/rogpeppe/go-internal/internal/syscall/windows/sysdll
github.com/rogpeppe/go-internal/lockedfile github.com/rogpeppe/go-internal/lockedfile
github.com/rogpeppe/go-internal/lockedfile/internal/filelock github.com/rogpeppe/go-internal/lockedfile/internal/filelock
# github.com/scrohde/go-toposort v0.0.0-20170629203416-a9a902e065a3
## explicit
github.com/scrohde/go-toposort
# github.com/shopspring/decimal v1.2.0 # github.com/shopspring/decimal v1.2.0
github.com/shopspring/decimal github.com/shopspring/decimal
# github.com/sirupsen/logrus v1.8.1 # github.com/sirupsen/logrus v1.8.1