mirror of
https://github.com/mudler/luet.git
synced 2025-09-02 15:54:39 +00:00
Compare commits
3 Commits
0.35.0
...
glob_final
Author | SHA1 | Date | |
---|---|---|---|
|
288ac086ec | ||
|
45a28112ef | ||
|
2765f817be |
6
Makefile
6
Makefile
@@ -81,6 +81,12 @@ test-docker:
|
||||
--workdir /go/src/github.com/mudler/luet -ti golang:latest \
|
||||
bash -c "make test"
|
||||
|
||||
.PHONY: test-integration-docker
|
||||
test-integration-docker:
|
||||
docker run -v $(ROOT_DIR):/go/src/github.com/mudler/luet -v /var/run/docker.sock:/var/run/docker.sock \
|
||||
--workdir /go/src/github.com/mudler/luet -ti golang:latest \
|
||||
bash -c "apt-get update && apt-get install docker.io && make test-integration"
|
||||
|
||||
multiarch-build:
|
||||
goreleaser build --snapshot --rm-dist
|
||||
|
||||
|
1
go.mod
1
go.mod
@@ -53,6 +53,7 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pterm/pterm v0.12.32-0.20211002183613-ada9ef6790c3
|
||||
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/cobra v1.2.1
|
||||
github.com/spf13/viper v1.8.1
|
||||
|
2
go.sum
2
go.sum
@@ -1300,6 +1300,8 @@ 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/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/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/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=
|
||||
|
@@ -6,9 +6,10 @@ import (
|
||||
"sort"
|
||||
"unicode"
|
||||
|
||||
"github.com/mudler/luet/pkg/helpers"
|
||||
"github.com/mudler/topsort"
|
||||
"github.com/philopon/go-toposort"
|
||||
"github.com/pkg/errors"
|
||||
toposort "github.com/scrohde/go-toposort"
|
||||
)
|
||||
|
||||
// PackageAssert represent a package assertion.
|
||||
@@ -30,51 +31,48 @@ func (a *PackageAssert) String() string {
|
||||
return fmt.Sprintf("%s/%s %s %s", a.Package.GetCategory(), a.Package.GetName(), a.Package.GetVersion(), msg)
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) EnsureOrder() PackagesAssertions {
|
||||
func (assertions PackagesAssertions) EnsureOrder(definitiondb PackageDatabase) (PackagesAssertions, error) {
|
||||
|
||||
allAssertions := assertions
|
||||
orderedAssertions := PackagesAssertions{}
|
||||
unorderedAssertions := PackagesAssertions{}
|
||||
fingerprints := []string{}
|
||||
|
||||
tmpMap := map[string]PackageAssert{}
|
||||
|
||||
for _, a := range assertions {
|
||||
tmpMap[a.Package.GetFingerPrint()] = a
|
||||
fingerprints = append(fingerprints, a.Package.GetFingerPrint())
|
||||
unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered
|
||||
graph := toposort.NewGraph(len(allAssertions))
|
||||
|
||||
if a.Value {
|
||||
unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered
|
||||
} else {
|
||||
orderedAssertions = append(orderedAssertions, a) // Keep last the ones which are not meant to be installed
|
||||
}
|
||||
for _, a := range assertions {
|
||||
tmpMap[a.Package.GetPackageName()] = a
|
||||
graph.AddNode(a.Package.GetPackageName())
|
||||
}
|
||||
|
||||
sort.Sort(unorderedAssertions)
|
||||
edges := map[string]string{}
|
||||
|
||||
// Build a topological graph
|
||||
graph := toposort.NewGraph(len(unorderedAssertions))
|
||||
graph.AddNodes(fingerprints...)
|
||||
for _, a := range unorderedAssertions {
|
||||
for _, a := range allAssertions {
|
||||
for _, req := range a.Package.GetRequires() {
|
||||
graph.AddEdge(a.Package.GetFingerPrint(), req.GetFingerPrint())
|
||||
if def, err := definitiondb.FindPackage(req); err == nil { // Provides: Get a chance of being override here
|
||||
req = def
|
||||
}
|
||||
edges[a.Package.GetPackageName()] = req.GetPackageName()
|
||||
graph.AddNode(req.GetPackageName())
|
||||
}
|
||||
}
|
||||
result, ok := graph.Toposort()
|
||||
|
||||
for k, v := range edges {
|
||||
graph.AddEdge(k, v)
|
||||
}
|
||||
|
||||
result, ok := graph.ToposortStable()
|
||||
if !ok {
|
||||
panic("Cycle found")
|
||||
return nil, fmt.Errorf("cycle found")
|
||||
}
|
||||
for _, res := range result {
|
||||
a, ok := tmpMap[res]
|
||||
if !ok {
|
||||
panic("fail")
|
||||
// continue
|
||||
if ok {
|
||||
orderedAssertions = append(orderedAssertions, a)
|
||||
}
|
||||
orderedAssertions = append(orderedAssertions, a)
|
||||
// orderedAssertions = append(PackagesAssertions{a}, orderedAssertions...) // push upfront
|
||||
}
|
||||
//helpers.ReverseAny(orderedAssertions)
|
||||
return orderedAssertions
|
||||
helpers.ReverseAny(orderedAssertions)
|
||||
return orderedAssertions, nil
|
||||
}
|
||||
|
||||
// SearchByName searches a string matching a package in the assetion list
|
||||
|
86
pkg/api/core/types/assertion_test.go
Normal file
86
pkg/api/core/types/assertion_test.go
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types_test
|
||||
|
||||
import (
|
||||
types "github.com/mudler/luet/pkg/api/core/types"
|
||||
"github.com/mudler/luet/pkg/database"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Assertions", func() {
|
||||
Context("Ordering", func() {
|
||||
It("orders them correctly", func() {
|
||||
foo := &types.Package{Name: "foo", PackageRequires: []*types.Package{{Name: "bar"}}}
|
||||
assertions := types.PackagesAssertions{
|
||||
{Package: foo},
|
||||
{Package: &types.Package{Name: "baz", PackageRequires: []*types.Package{{Name: "bar"}}}},
|
||||
{Package: &types.Package{Name: "bar", 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"))
|
||||
|
||||
ordered, err := assertions.EnsureOrder(database.NewInMemoryDatabase(false))
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(len(ordered)).To(Equal(3))
|
||||
|
||||
Expect(ordered[0].Package.Name).To(Equal("bar"))
|
||||
})
|
||||
|
||||
It("errors on cycles", func() {
|
||||
foo := &types.Package{Name: "foo", PackageRequires: []*types.Package{{Name: "bar"}}}
|
||||
assertions := types.PackagesAssertions{
|
||||
{Package: foo},
|
||||
{Package: &types.Package{Name: "baz", PackageRequires: []*types.Package{{Name: "bar"}}}},
|
||||
{Package: &types.Package{Name: "bar", PackageRequires: []*types.Package{{Name: "baz"}}}},
|
||||
}
|
||||
|
||||
_, err := assertions.Order(database.NewInMemoryDatabase(false), foo.GetFingerPrint())
|
||||
Expect(err).Should(HaveOccurred())
|
||||
|
||||
_, err = assertions.EnsureOrder(database.NewInMemoryDatabase(false))
|
||||
Expect(err).Should(HaveOccurred())
|
||||
})
|
||||
|
||||
It("orders them correctly", func() {
|
||||
foo := &types.Package{Name: "foo", PackageRequires: []*types.Package{{Name: "bar"}}}
|
||||
assertions := types.PackagesAssertions{
|
||||
{Package: foo},
|
||||
{Package: &types.Package{Name: "baz2", PackageRequires: []*types.Package{{Name: "foobaz"}}}},
|
||||
{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(5))
|
||||
|
||||
Expect(ordered[0].Package.Name).To(Equal("bar"))
|
||||
Expect(ordered[1].Package.Name).To(Equal("foobaz"))
|
||||
})
|
||||
})
|
||||
})
|
@@ -22,6 +22,8 @@ import (
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
box "github.com/mudler/luet/pkg/box"
|
||||
fileHelper "github.com/mudler/luet/pkg/helpers/file"
|
||||
"github.com/mudler/luet/pkg/tree"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -90,3 +92,47 @@ func NewLuetFinalizerFromYaml(data []byte) (*LuetFinalizer, error) {
|
||||
}
|
||||
return &p, err
|
||||
}
|
||||
|
||||
func OrderFinalizers(allRepos types.PackageDatabase, toInstall map[string]ArtifactMatch, solution types.PackagesAssertions) ([]*types.Package, error) {
|
||||
var toFinalize []*types.Package
|
||||
if len(toInstall) == 1 {
|
||||
for _, w := range toInstall {
|
||||
if fileHelper.Exists(w.Package.Rel(tree.FinalizerFile)) {
|
||||
// Finalizers needs to run in order and in sequence.
|
||||
ordered, err := solution.Order(allRepos, w.Package.GetFingerPrint())
|
||||
if err != nil {
|
||||
return toFinalize, errors.Wrap(err, "While order a solution for "+w.Package.HumanReadableString())
|
||||
}
|
||||
ORDER:
|
||||
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 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assertions, err := solution.EnsureOrder(allRepos)
|
||||
if err != nil {
|
||||
return toFinalize, err
|
||||
}
|
||||
|
||||
for _, o := range assertions {
|
||||
if o.Value {
|
||||
toFinalize = append(toFinalize, o.Package)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toFinalize, nil
|
||||
}
|
||||
|
@@ -816,33 +816,7 @@ func (l *LuetInstaller) computeInstall(o Option, syncedRepos Repositories, cp ty
|
||||
func (l *LuetInstaller) getFinalizers(allRepos types.PackageDatabase, solution types.PackagesAssertions, toInstall map[string]ArtifactMatch, nodeps bool) ([]*types.Package, error) {
|
||||
var toFinalize []*types.Package
|
||||
if !nodeps {
|
||||
// TODO: Lower those errors as l.Options.Context.Warning
|
||||
for _, w := range toInstall {
|
||||
if !fileHelper.Exists(w.Package.Rel(tree.FinalizerFile)) {
|
||||
continue
|
||||
}
|
||||
// Finalizers needs to run in order and in sequence.
|
||||
ordered, err := solution.Order(allRepos, w.Package.GetFingerPrint())
|
||||
if err != nil {
|
||||
return toFinalize, errors.Wrap(err, "While order a solution for "+w.Package.HumanReadableString())
|
||||
}
|
||||
ORDER:
|
||||
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 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
return OrderFinalizers(allRepos, toInstall, solution)
|
||||
} else {
|
||||
for _, c := range toInstall {
|
||||
if !fileHelper.Exists(c.Package.Rel(tree.FinalizerFile)) {
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package toposort
|
||||
|
||||
import "sort"
|
||||
|
||||
type Graph struct {
|
||||
nodes []string
|
||||
outputs map[string]map[string]int
|
||||
@@ -59,7 +61,7 @@ func (g *Graph) RemoveEdge(from, to string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *Graph) Toposort() ([]string, bool) {
|
||||
func (g *Graph) toposort(stable bool) ([]string, bool) {
|
||||
L := make([]string, 0, len(g.nodes))
|
||||
S := make([]string, 0, len(g.nodes))
|
||||
|
||||
@@ -69,6 +71,10 @@ func (g *Graph) Toposort() ([]string, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if stable {
|
||||
sort.Strings(S)
|
||||
}
|
||||
|
||||
for len(S) > 0 {
|
||||
var n string
|
||||
n, S = S[0], S[1:]
|
||||
@@ -79,6 +85,10 @@ func (g *Graph) Toposort() ([]string, bool) {
|
||||
ms[i-1] = m
|
||||
}
|
||||
|
||||
if stable {
|
||||
sort.Strings(ms)
|
||||
}
|
||||
|
||||
for _, m := range ms {
|
||||
g.unsafeRemoveEdge(n, m)
|
||||
|
||||
@@ -99,3 +109,11 @@ func (g *Graph) Toposort() ([]string, bool) {
|
||||
|
||||
return L, true
|
||||
}
|
||||
|
||||
func (g *Graph) Toposort() ([]string, bool) {
|
||||
return g.toposort(false)
|
||||
}
|
||||
|
||||
func (g *Graph) ToposortStable() ([]string, bool) {
|
||||
return g.toposort(true)
|
||||
}
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@@ -370,7 +370,6 @@ github.com/pelletier/go-toml
|
||||
github.com/peterbourgon/diskv
|
||||
# github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f
|
||||
## explicit
|
||||
github.com/philopon/go-toposort
|
||||
# github.com/pkg/errors v0.9.1
|
||||
## explicit
|
||||
github.com/pkg/errors
|
||||
@@ -402,6 +401,9 @@ github.com/rogpeppe/go-internal/internal/syscall/windows
|
||||
github.com/rogpeppe/go-internal/internal/syscall/windows/sysdll
|
||||
github.com/rogpeppe/go-internal/lockedfile
|
||||
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
|
||||
# github.com/sirupsen/logrus v1.8.1
|
||||
|
Reference in New Issue
Block a user