Compare commits

...

21 Commits
0.7.6 ... 0.7.8

Author SHA1 Message Date
Ettore Di Giacinto
8e029a8ee4 Tag 0.7.8 2020-05-16 22:46:04 +02:00
Ettore Di Giacinto
51711dafba Add package_dir to pack a spec dir as the main artifact 2020-05-16 21:34:27 +02:00
Ettore Di Giacinto
2803430515 Add solver test scenario 2020-05-16 11:11:17 +02:00
Daniele Rondina
44213894bc Add commands aliases 2020-05-10 20:24:08 +02:00
Daniele Rondina
a7d1381cb5 cmd/create-repo: Add support for multiple trees 2020-05-10 20:18:10 +02:00
Daniele Rondina
2cb79c0071 cmd/build: Add support for multiple trees 2020-05-10 20:02:12 +02:00
Ettore Di Giacinto
7d17d3babf Merge pull request #109 from mudler/log-cmdline-opts
Log cmdline opts
2020-05-09 11:16:37 +02:00
Daniele Rondina
13df161fc6 logging: permit to disable color and emoji
Now it's possible disable color and emoji on standard
output with:

$> luet <cmd> --color=false --emoji=false

Hereinafter, the list of changes:

* Added logging option logging.color (default true)
* Added logging option logging.enable_emoji (default true)
* Added persistent flag --color
* Added persistent flag --emoji
2020-05-09 10:08:21 +02:00
Daniele Rondina
fe5ab9246f Added option for enable log to file.
Now it's possible logging to file is handled by the enable_logfile
option and by the path.

From cli is now possible:
* enable log to file with the option --enable-logfile
* modify the logfile path with the option --logfile/-l <path>
2020-05-09 10:05:34 +02:00
Daniele Rondina
993bcf9adf tree/validate: Add support for in memory cache with solver check 2020-05-08 20:05:21 +02:00
Ettore Di Giacinto
20cb96e0cc Simplify ordering check
we don't need a map[string]map[string]interface{}, as we don't need to
keep the data around
2020-05-04 17:34:29 +02:00
Daniele Rondina
b68634b58a solver: skip same packages in the order and avoid loop 2020-05-04 12:21:49 +02:00
Ettore Di Giacinto
1b529ea8c5 Add development version 2020-05-03 13:46:53 +02:00
Ettore Di Giacinto
2c2e6065d9 Tag 0.7.7 2020-05-03 13:46:35 +02:00
Ettore Di Giacinto
46014fb9c1 Enhance install output 2020-05-03 13:22:06 +02:00
Ettore Di Giacinto
ada9d886fa Enhance uninstall output 2020-05-03 13:22:00 +02:00
Ettore Di Giacinto
584b980644 Adapt integration test which requires full uninstall 2020-05-03 13:12:14 +02:00
Ettore Di Giacinto
a1d8ef1422 Allow to partially uninstall a package graph, make uninstall --full optional 2020-05-03 13:04:34 +02:00
Ettore Di Giacinto
7b6e4a2176 Add to the Solver the capability to check conflicts with revdeps 2020-05-03 10:34:18 +02:00
Ettore Di Giacinto
3befbfa915 Optimize uninstall computation 2020-05-02 15:43:57 +02:00
Ettore Di Giacinto
8dd756ec96 Add development version 2020-05-02 14:51:08 +02:00
31 changed files with 524 additions and 101 deletions

View File

@@ -62,7 +62,7 @@ var buildCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
clean := viper.GetBool("clean")
src := viper.GetString("tree")
treePaths := viper.GetStringSlice("tree")
dst := viper.GetString("destination")
concurrency := LuetCfg.GetGeneral().Concurrency
backendType := viper.GetString("backend")
@@ -105,14 +105,21 @@ var buildCmd = &cobra.Command{
generalRecipe := tree.NewCompilerRecipe(db)
Info("Loading", src)
Info("Building in", dst)
err := generalRecipe.Load(src)
if err != nil {
Fatal("Error: " + err.Error())
if len(treePaths) <= 0 {
Fatal("No tree path supplied!")
}
for _, src := range treePaths {
Info("Loading tree", src)
err := generalRecipe.Load(src)
if err != nil {
Fatal("Error: " + err.Error())
}
}
Info("Building in", dst)
stype := LuetCfg.Viper.GetString("solver.type")
discount := LuetCfg.Viper.GetFloat64("solver.discount")
rate := LuetCfg.Viper.GetFloat64("solver.rate")
@@ -196,7 +203,7 @@ func init() {
Fatal(err)
}
buildCmd.Flags().Bool("clean", true, "Build all packages without considering the packages present in the build directory")
buildCmd.Flags().String("tree", path, "Source luet tree")
buildCmd.Flags().StringSliceP("tree", "t", []string{}, "Path of the tree to use.")
buildCmd.Flags().String("backend", "docker", "backend used (docker,img)")
buildCmd.Flags().Bool("privileged", false, "Privileged (Keep permissions)")
buildCmd.Flags().String("database", "memory", "database used for solving (memory,boltdb)")

View File

@@ -24,9 +24,10 @@ import (
)
var configCmd = &cobra.Command{
Use: "config",
Short: "Print config",
Long: `Show luet configuration`,
Use: "config",
Short: "Print config",
Long: `Show luet configuration`,
Aliases: []string{"c"},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(config.LuetCfg.GetLogging())
fmt.Println(config.LuetCfg.GetGeneral())

View File

@@ -50,7 +50,7 @@ var createrepoCmd = &cobra.Command{
var err error
var repo installer.Repository
tree := viper.GetString("tree")
treePaths := viper.GetStringSlice("tree")
dst := viper.GetString("output")
packages := viper.GetString("packages")
name := viper.GetString("name")
@@ -74,8 +74,8 @@ var createrepoCmd = &cobra.Command{
Fatal("Error: " + err.Error())
}
if tree == "" {
tree = lrepo.TreePath
if len(treePaths) <= 0 {
treePaths = []string{lrepo.TreePath}
}
if t == "" {
@@ -87,12 +87,12 @@ var createrepoCmd = &cobra.Command{
lrepo.Urls,
lrepo.Priority,
packages,
tree,
treePaths,
pkg.NewInMemoryDatabase(false))
} else {
repo, err = installer.GenerateRepository(name, descr, t, urls, 1, packages,
tree, pkg.NewInMemoryDatabase(false))
treePaths, pkg.NewInMemoryDatabase(false))
}
if err != nil {
@@ -131,7 +131,7 @@ func init() {
Fatal(err)
}
createrepoCmd.Flags().String("packages", path, "Packages folder (output from build)")
createrepoCmd.Flags().String("tree", path, "Source luet tree")
createrepoCmd.Flags().StringSliceP("tree", "t", []string{}, "Path of the source trees to use.")
createrepoCmd.Flags().String("output", path, "Destination folder")
createrepoCmd.Flags().String("name", "luet", "Repository name")
createrepoCmd.Flags().String("descr", "luet", "Repository description")

View File

@@ -29,8 +29,9 @@ import (
)
var installCmd = &cobra.Command{
Use: "install <pkg1> <pkg2> ...",
Short: "Install a package",
Use: "install <pkg1> <pkg2> ...",
Short: "Install a package",
Aliases: []string{"i"},
PreRun: func(cmd *cobra.Command, args []string) {
LuetCfg.Viper.BindPFlag("system.database_path", cmd.Flags().Lookup("system-dbpath"))
LuetCfg.Viper.BindPFlag("system.rootfs", cmd.Flags().Lookup("system-target"))

View File

@@ -35,6 +35,7 @@ $> luet repo update
# Update only repo1 and repo2
$> luet repo update repo1 repo2
`,
Aliases: []string{"up"},
PreRun: func(cmd *cobra.Command, args []string) {
},
Run: func(cmd *cobra.Command, args []string) {

View File

@@ -38,7 +38,7 @@ var Verbose bool
var LockedCommands = []string{"install", "uninstall", "upgrade"}
const (
LuetCLIVersion = "0.7.6"
LuetCLIVersion = "0.7.8"
LuetEnvPrefix = "LUET"
)
@@ -88,11 +88,12 @@ func LoadConfig(c *config.LuetConfig) error {
return err
}
Debug("Using config file:", c.Viper.ConfigFileUsed())
InitAurora()
NewSpinner()
if c.GetLogging().Path != "" {
Debug("Using config file:", c.Viper.ConfigFileUsed())
if c.GetLogging().EnableLogFile && c.GetLogging().Path != "" {
// Init zap logger
err = ZapLogger()
if err != nil {
@@ -152,6 +153,11 @@ func init() {
pflags.StringVar(&cfgFile, "config", "", "config file (default is $HOME/.luet.yaml)")
pflags.BoolP("debug", "d", false, "verbose output")
pflags.Bool("fatal", false, "Enables Warnings to exit")
pflags.Bool("enable-logfile", false, "Enable log to file")
pflags.Bool("color", config.LuetCfg.GetLogging().Color, "Enable/Disable color.")
pflags.Bool("emoji", config.LuetCfg.GetLogging().EnableEmoji, "Enable/Disable emoji.")
pflags.StringP("logfile", "l", config.LuetCfg.GetLogging().Path,
"Logfile path. Empty value disable log to file.")
sameOwner := false
u, err := user.Current()
@@ -166,10 +172,15 @@ func init() {
pflags.Bool("same-owner", sameOwner, "Maintain same owner on uncompress.")
pflags.Int("concurrency", runtime.NumCPU(), "Concurrency")
config.LuetCfg.Viper.BindPFlag("general.same_owner", pflags.Lookup("same-owner"))
config.LuetCfg.Viper.BindPFlag("general.debug", pflags.Lookup("debug"))
config.LuetCfg.Viper.BindPFlag("logging.color", pflags.Lookup("color"))
config.LuetCfg.Viper.BindPFlag("logging.enable_emoji", pflags.Lookup("emoji"))
config.LuetCfg.Viper.BindPFlag("logging.enable_logfile", pflags.Lookup("enable-logfile"))
config.LuetCfg.Viper.BindPFlag("logging.path", pflags.Lookup("logfile"))
config.LuetCfg.Viper.BindPFlag("general.concurrency", pflags.Lookup("concurrency"))
config.LuetCfg.Viper.BindPFlag("general.debug", pflags.Lookup("debug"))
config.LuetCfg.Viper.BindPFlag("general.fatal_warnings", pflags.Lookup("fatal"))
config.LuetCfg.Viper.BindPFlag("general.same_owner", pflags.Lookup("same-owner"))
}
// initConfig reads in config file and ENV variables if set.

View File

@@ -39,9 +39,10 @@ type Results struct {
}
var searchCmd = &cobra.Command{
Use: "search <term>",
Short: "Search packages",
Long: `Search for installed and available packages`,
Use: "search <term>",
Short: "Search packages",
Long: `Search for installed and available packages`,
Aliases: []string{"s"},
PreRun: func(cmd *cobra.Command, args []string) {
LuetCfg.Viper.BindPFlag("system.database_path", cmd.Flags().Lookup("system-dbpath"))
LuetCfg.Viper.BindPFlag("system.rootfs", cmd.Flags().Lookup("system-target"))

View File

@@ -47,6 +47,7 @@ func validateWorker(i int,
defer wg.Done()
var depSolver solver.PackageSolver
var cacheDeps *pkg.InMemoryDatabase
brokenPkgs := 0
brokenDeps := 0
var errstr string
@@ -56,9 +57,14 @@ func validateWorker(i int,
depSolver = solver.NewSolver(pkg.NewInMemoryDatabase(false),
reciper.GetDatabase(),
emptyInstallationDb)
// Use Singleton in memory cache for speedup dependencies
// analysis
cacheDeps = pkg.NewInMemoryDatabase(true).(*pkg.InMemoryDatabase)
}
for p := range c {
found, err := reciper.GetDatabase().FindPackages(
&pkg.DefaultPackage{
Name: p.GetName(),
@@ -119,11 +125,15 @@ func validateWorker(i int,
continue
}
}
Info("Checking package "+fmt.Sprintf("%s/%s-%s", p.GetCategory(), p.GetName(), p.GetVersion()), "with", len(p.GetRequires()), "dependencies.")
Info("Checking package "+
fmt.Sprintf("%s/%s-%s", p.GetCategory(), p.GetName(), p.GetVersion()),
"with", len(p.GetRequires()), "dependencies and", len(p.GetConflicts()), "conflicts.")
all := p.GetRequires()
all = append(all, p.GetConflicts()...)
for _, r := range all {
for idx, r := range all {
var deps pkg.Packages
var err error
if r.IsSelector() {
@@ -166,6 +176,21 @@ func validateWorker(i int,
fmt.Sprintf("%s/%s-%s", r.GetCategory(), r.GetName(), r.GetVersion()))
if withSolver {
Info(fmt.Sprintf(" :soap: [%2d/%2d] %s/%s-%s: %s/%s-%s",
idx+1, len(all),
p.GetCategory(), p.GetName(), p.GetVersion(),
r.GetCategory(), r.GetName(), r.GetVersion(),
))
// Check if the solver is already been done for the deep
_, err := cacheDeps.Get(r.HashFingerprint())
if err == nil {
Debug(" :direct_hit: Cache Hit for dep",
fmt.Sprintf("%s/%s-%s", r.GetCategory(), r.GetName(), r.GetVersion()))
continue
}
Spinner(32)
solution, err := depSolver.Install(pkg.Packages{r})
ass := solution.SearchByName(r.GetPackageName())
@@ -192,6 +217,9 @@ func validateWorker(i int,
validpkg = false
}
// Register the key
cacheDeps.Set(r.HashFingerprint(), "1")
}
}

View File

@@ -28,9 +28,10 @@ import (
)
var uninstallCmd = &cobra.Command{
Use: "uninstall <pkg> <pkg2> ...",
Short: "Uninstall a package or a list of packages",
Long: `Uninstall packages`,
Use: "uninstall <pkg> <pkg2> ...",
Short: "Uninstall a package or a list of packages",
Long: `Uninstall packages`,
Aliases: []string{"rm", "un"},
PreRun: func(cmd *cobra.Command, args []string) {
LuetCfg.Viper.BindPFlag("system.database_path", cmd.Flags().Lookup("system-dbpath"))
LuetCfg.Viper.BindPFlag("system.rootfs", cmd.Flags().Lookup("system-target"))
@@ -57,6 +58,8 @@ var uninstallCmd = &cobra.Command{
attempts := LuetCfg.Viper.GetInt("solver.max_attempts")
force := LuetCfg.Viper.GetBool("force")
nodeps := LuetCfg.Viper.GetBool("nodeps")
full, _ := cmd.Flags().GetBool("full")
checkconflicts, _ := cmd.Flags().GetBool("conflictscheck")
LuetCfg.GetSolverOptions().Type = stype
LuetCfg.GetSolverOptions().LearnRate = float32(rate)
@@ -66,10 +69,12 @@ var uninstallCmd = &cobra.Command{
Debug("Solver", LuetCfg.GetSolverOptions().CompactString())
inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{
Concurrency: LuetCfg.GetGeneral().Concurrency,
SolverOptions: *LuetCfg.GetSolverOptions(),
NoDeps: nodeps,
Force: force,
Concurrency: LuetCfg.GetGeneral().Concurrency,
SolverOptions: *LuetCfg.GetSolverOptions(),
NoDeps: nodeps,
Force: force,
FullUninstall: full,
CheckConflicts: checkconflicts,
})
if LuetCfg.GetSystem().DatabaseEngine == "boltdb" {
@@ -98,8 +103,10 @@ func init() {
uninstallCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate")
uninstallCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate")
uninstallCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts")
uninstallCmd.Flags().Bool("nodeps", false, "Don't consider package dependencies (harmful!)")
uninstallCmd.Flags().Bool("nodeps", false, "Don't consider package dependencies (harmful! overrides checkconflicts and full!)")
uninstallCmd.Flags().Bool("force", false, "Force uninstall")
uninstallCmd.Flags().Bool("full", false, "Attempts to remove as much packages as possible which aren't required (slow)")
uninstallCmd.Flags().Bool("conflictscheck", true, "Check if the package marked for deletion is required by other packages")
RootCmd.AddCommand(uninstallCmd)
}

View File

@@ -27,8 +27,9 @@ import (
)
var upgradeCmd = &cobra.Command{
Use: "upgrade",
Short: "Upgrades the system",
Use: "upgrade",
Short: "Upgrades the system",
Aliases: []string{"u"},
PreRun: func(cmd *cobra.Command, args []string) {
LuetCfg.Viper.BindPFlag("system.database_path", installCmd.Flags().Lookup("system-dbpath"))
LuetCfg.Viper.BindPFlag("system.rootfs", installCmd.Flags().Lookup("system-target"))

View File

@@ -4,8 +4,11 @@
# Logging configuration section:
# ---------------------------------------------
# logging:
# # Enable loggging to file (if path is not empty)
# enable_logfile: false
#
# Leave empty to skip logging to file.
# path: ""
# path: "/var/log/luet.log"
#
# Set logging level: error|warning|info|debug
# level: "info"

View File

@@ -357,8 +357,15 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
var diffs []ArtifactLayer
var artifact Artifact
unpack := p.ImageUnpack()
if !p.ImageUnpack() {
// If package_dir was specified in the spec, we want to treat the content of the directory
// as the root of our archive. ImageUnpack is implied to be true. override it
if p.GetPackageDir() != "" {
unpack = true
}
if !unpack {
// we have to get diffs only if spec is not unpacked
diffs, err = cs.Backend.Changes(p.Rel(p.GetPackage().GetFingerPrint()+"-builder.image.tar"), p.Rel(p.GetPackage().GetFingerPrint()+".image.tar"))
if err != nil {
@@ -395,7 +402,12 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
}
}
if p.ImageUnpack() {
if unpack {
if p.GetPackageDir() != "" {
Info(":tophat: Packing from output dir", p.GetPackageDir())
rootfs = filepath.Join(rootfs, p.GetPackageDir())
}
if len(p.GetIncludes()) > 0 {
// strip from includes

View File

@@ -615,6 +615,61 @@ var _ = Describe("Compiler", func() {
})
})
Context("Packages which conents are a package folder", func() {
It("Compiles it in parallel", func() {
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
err := generalRecipe.Load("../../tests/fixtures/package_dir")
Expect(err).ToNot(HaveOccurred())
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(2))
compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), NewDefaultCompilerOptions())
spec, err := compiler.FromPackage(&pkg.DefaultPackage{
Name: "dironly",
Category: "test",
Version: "1.0",
})
Expect(err).ToNot(HaveOccurred())
spec2, err := compiler.FromPackage(&pkg.DefaultPackage{
Name: "dironly_filter",
Category: "test",
Version: "1.0",
})
Expect(err).ToNot(HaveOccurred())
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
tmpdir, err := ioutil.TempDir("", "tree")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir) // clean up
tmpdir2, err := ioutil.TempDir("", "tree2")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir2) // clean up
spec.SetOutputPath(tmpdir)
spec2.SetOutputPath(tmpdir2)
compiler.SetConcurrency(1)
artifacts, errs := compiler.CompileParallel(false, NewLuetCompilationspecs(spec, spec2))
Expect(errs).To(BeNil())
Expect(len(artifacts)).To(Equal(2))
Expect(len(artifacts[0].GetDependencies())).To(Equal(0))
Expect(helpers.Untar(spec.Rel("dironly-test-1.0.package.tar"), tmpdir, false)).ToNot(HaveOccurred())
Expect(helpers.Exists(spec.Rel("test1"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("test2"))).To(BeTrue())
Expect(helpers.Untar(spec2.Rel("dironly_filter-test-1.0.package.tar"), tmpdir2, false)).ToNot(HaveOccurred())
Expect(helpers.Exists(spec2.Rel("test5"))).To(BeTrue())
Expect(helpers.Exists(spec2.Rel("test6"))).ToNot(BeTrue())
Expect(helpers.Exists(spec2.Rel("artifact42"))).ToNot(BeTrue())
})
})
Context("Compression", func() {
It("Builds packages in gzip", func() {
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))

View File

@@ -168,6 +168,9 @@ type CompilationSpec interface {
GetRetrieve() []string
CopyRetrieves(dest string) error
SetPackageDir(string)
GetPackageDir() string
}
type CompilationSpecs interface {

View File

@@ -95,6 +95,7 @@ type LuetCompilationSpec struct {
Seed string `json:"seed"`
Package *pkg.DefaultPackage `json:"package"`
SourceAssertion solver.PackagesAssertions `json:"-"`
PackageDir string `json:"package_dir" yaml:"package_dir"`
Retrieve []string `json:"retrieve"`
@@ -123,6 +124,14 @@ func (cs *LuetCompilationSpec) GetPackage() pkg.Package {
return cs.Package
}
func (cs *LuetCompilationSpec) GetPackageDir() string {
return cs.PackageDir
}
func (cs *LuetCompilationSpec) SetPackageDir(s string) {
cs.PackageDir = s
}
func (cs *LuetCompilationSpec) BuildSteps() []string {
return cs.Steps
}

View File

@@ -37,9 +37,20 @@ var LuetCfg = NewLuetConfig(v.GetViper())
var AvailableResolvers = strings.Join([]string{solver.QLearningResolverType}, " ")
type LuetLoggingConfig struct {
Path string `mapstructure:"path"`
JsonFormat bool `mapstructure:"json_format"`
Level string `mapstructure:"level"`
// Path of the logfile
Path string `mapstructure:"path"`
// Enable/Disable logging to file
EnableLogFile bool `mapstructure:"enable_logfile"`
// Enable JSON format logging in file
JsonFormat bool `mapstructure:"json_format"`
// Log level
Level string `mapstructure:"level"`
// Enable emoji
EnableEmoji bool `mapstructure:"enable_emoji"`
// Enable/Disable color in logging
Color bool `mapstructure:"color"`
}
type LuetGeneralConfig struct {
@@ -205,8 +216,11 @@ func NewLuetConfig(viper *v.Viper) *LuetConfig {
func GenDefault(viper *v.Viper) {
viper.SetDefault("logging.level", "info")
viper.SetDefault("logging.path", "")
viper.SetDefault("logging.enable_logfile", false)
viper.SetDefault("logging.path", "/var/log/luet.log")
viper.SetDefault("logging.json_format", false)
viper.SetDefault("logging.enable_emoji", true)
viper.SetDefault("logging.color", true)
viper.SetDefault("general.concurrency", runtime.NumCPU())
viper.SetDefault("general.debug", false)
@@ -318,9 +332,13 @@ func (c *LuetLoggingConfig) SetLogLevel(s string) {
func (c *LuetLoggingConfig) String() string {
ans := fmt.Sprintf(`
logging:
enable_logfile: %t
path: %s
json_format: %t
level: %s`, c.Path, c.JsonFormat, c.Level)
color: %t
enable_emoji: %t
level: %s`, c.EnableLogFile, c.Path, c.JsonFormat,
c.Color, c.EnableEmoji, c.Level)
return ans
}

View File

@@ -54,6 +54,13 @@ var _ = Describe("Config", func() {
defer os.Remove(tmpFile.Name())
})
It("Config1", func() {
cfg := config.LuetCfg
cfg.GetLogging().Color = false
Expect(cfg.GetLogging().Color).To(BeFalse())
})
})
})

View File

@@ -41,6 +41,8 @@ type LuetInstallerOptions struct {
OnlyDeps bool
Force bool
PreserveSystemEssentialData bool
FullUninstall bool
CheckConflicts bool
}
type LuetInstaller struct {
@@ -132,14 +134,12 @@ func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove pkg.Packages, to
// if the old A results installed in the system. This is due to the fact that
// now the solver enforces the constraints and explictly denies two packages
// of the same version installed.
forced := false
if l.Options.Force {
forced = true
}
forced := l.Options.Force
l.Options.Force = true
for _, u := range toRemove {
Info(":package: Marked for deletion", u.HumanReadableString())
Info(":package:", u.HumanReadableString(), "Marked for deletion")
err := l.Uninstall(u, s)
if err != nil && !l.Options.Force {
@@ -309,7 +309,7 @@ func (l *LuetInstaller) install(syncedRepos Repositories, cp pkg.Packages, s *Sy
packagesToInstall = append(packagesToInstall, currentPack)
}
}
Info(":deciduous_tree: Finding packages to install")
// Gathers things to install
for _, currentPack := range packagesToInstall {
// Check if package is already installed.
@@ -331,6 +331,7 @@ func (l *LuetInstaller) install(syncedRepos Repositories, cp pkg.Packages, s *Sy
// Filter out already installed
if _, err := s.Database.FindPackage(currentPack); err != nil {
toInstall[currentPack.GetFingerPrint()] = ArtifactMatch{Package: currentPack, Artifact: artefact, Repository: matches[0].Repo}
Info("\t:package:", currentPack.HumanReadableString(), "from repository", matches[0].Repo.GetName())
}
break A
}
@@ -569,17 +570,35 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error {
}
func (l *LuetInstaller) Uninstall(p pkg.Package, s *System) error {
Spinner(32)
defer SpinnerStop()
Info("Uninstalling :package:", p.HumanReadableString(), "hang tight")
// compute uninstall from all world - remove packages in parallel - run uninstall finalizer (in order) TODO - mark the uninstallation in db
// Get installed definition
checkConflicts := true
if l.Options.Force == true {
checkConflicts := l.Options.CheckConflicts
full := l.Options.FullUninstall
if l.Options.Force == true { // IF forced, we want to remove the package and all its requires
checkConflicts = false
full = false
}
// Create a temporary DB with the installed packages
// so the solver is much faster finding the deptree
installedtmp := pkg.NewInMemoryDatabase(false)
for _, i := range s.Database.World() {
_, err := installedtmp.CreatePackage(i)
if err != nil {
return errors.Wrap(err, "Failed create temporary in-memory db")
}
}
if !l.Options.NoDeps {
solv := solver.NewResolver(s.Database, s.Database, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
solution, err := solv.Uninstall(p, checkConflicts)
Info("Finding :package:", p.HumanReadableString(), "dependency graph :deciduous_tree:")
solv := solver.NewResolver(installedtmp, installedtmp, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
solution, err := solv.Uninstall(p, checkConflicts, full)
if err != nil && !l.Options.Force {
return errors.Wrap(err, "Could not solve the uninstall constraints. Tip: try with --solver-type qlearning or with --force, or by removing packages excluding their dependencies with --nodeps")
}
@@ -596,7 +615,7 @@ func (l *LuetInstaller) Uninstall(p pkg.Package, s *System) error {
if err != nil && !l.Options.Force {
return errors.Wrap(err, "Uninstall failed")
}
Info(":package: ", p.HumanReadableString(), "uninstalled")
Info(":package:", p.HumanReadableString(), "uninstalled")
}
return nil

View File

@@ -82,7 +82,7 @@ var _ = Describe("Installer", func() {
Expect(helpers.Exists(spec.Rel("b-test-1.0.package.tar"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("b-test-1.0.metadata.yaml"))).To(BeTrue())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/buildable", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/buildable"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
@@ -198,7 +198,7 @@ urls:
Expect(helpers.Exists(spec.Rel("b-test-1.0.package.tar"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("b-test-1.0.metadata.yaml"))).To(BeTrue())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/buildable", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/buildable"}, pkg.NewInMemoryDatabase(false))
treeFile := NewDefaultTreeRepositoryFile()
treeFile.SetCompressionType(compiler.None)
repo.SetRepositoryFile(REPOFILE_TREE_KEY, treeFile)
@@ -316,7 +316,7 @@ urls:
Expect(helpers.Exists(spec.Rel("b-test-1.0.package.tar"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("b-test-1.0.metadata.yaml"))).To(BeTrue())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/buildable", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/buildable"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
@@ -434,7 +434,7 @@ urls:
Expect(helpers.Exists(spec.Rel("b-test-1.0.package.tar"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("b-test-1.0.metadata.yaml"))).To(BeTrue())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/buildable", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/buildable"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
@@ -500,7 +500,7 @@ urls:
Expect(err).ToNot(HaveOccurred())
Expect(helpers.Exists(artifact.GetPath())).To(BeTrue())
repo, err = GenerateRepository("test", "description", "disk", []string{tmpdir2}, 1, tmpdir2, "../../tests/fixtures/alpine", pkg.NewInMemoryDatabase(false))
repo, err = GenerateRepository("test", "description", "disk", []string{tmpdir2}, 1, tmpdir2, []string{"../../tests/fixtures/alpine"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
err = repo.Write(tmpdir2, false)
Expect(err).ToNot(HaveOccurred())
@@ -569,7 +569,7 @@ urls:
Expect(errs).To(BeEmpty())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/upgrade", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/upgrade"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
@@ -695,7 +695,7 @@ urls:
_, errs = c2.CompileParallel(false, compiler.NewLuetCompilationspecs(spec2))
Expect(errs).To(BeEmpty())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/upgrade_old_repo", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/upgrade_old_repo"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
@@ -704,7 +704,7 @@ urls:
err = repo.Write(tmpdir, false)
Expect(err).ToNot(HaveOccurred())
repoupgrade, err := GenerateRepository("test", "description", "disk", []string{tmpdirnewrepo}, 1, tmpdirnewrepo, "../../tests/fixtures/upgrade_new_repo", pkg.NewInMemoryDatabase(false))
repoupgrade, err := GenerateRepository("test", "description", "disk", []string{tmpdirnewrepo}, 1, tmpdirnewrepo, []string{"../../tests/fixtures/upgrade_new_repo"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
err = repoupgrade.Write(tmpdirnewrepo, false)
Expect(err).ToNot(HaveOccurred())
@@ -818,7 +818,7 @@ urls:
Expect(errs).To(BeEmpty())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/upgrade", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/upgrade"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
@@ -935,7 +935,7 @@ urls:
Expect(errs).To(BeEmpty())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/upgrade", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/upgrade"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
@@ -1037,7 +1037,7 @@ urls:
Expect(errs).To(BeEmpty())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/upgrade_old_repo", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/upgrade_old_repo"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
Expect(helpers.Exists(spec.Rel("repository.yaml"))).ToNot(BeTrue())
@@ -1123,7 +1123,7 @@ urls:
Expect(errs).To(BeEmpty())
repo, err = GenerateRepository("test", "description", "disk", []string{tmpdir2}, 1, tmpdir2, "../../tests/fixtures/upgrade_new_repo", pkg.NewInMemoryDatabase(false))
repo, err = GenerateRepository("test", "description", "disk", []string{tmpdir2}, 1, tmpdir2, []string{"../../tests/fixtures/upgrade_new_repo"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
err = repo.Write(tmpdir2, false)

View File

@@ -35,7 +35,6 @@ import (
tree "github.com/mudler/luet/pkg/tree"
"github.com/ghodss/yaml"
. "github.com/logrusorgru/aurora"
"github.com/pkg/errors"
)
@@ -177,12 +176,15 @@ func (f *LuetRepositoryFile) GetChecksums() compiler.Checksums {
return f.Checksums
}
func GenerateRepository(name, descr, t string, urls []string, priority int, src, treeDir string, db pkg.PackageDatabase) (Repository, error) {
func GenerateRepository(name, descr, t string, urls []string, priority int, src string, treesDir []string, db pkg.PackageDatabase) (Repository, error) {
tr := tree.NewInstallerRecipe(db)
err := tr.Load(treeDir)
if err != nil {
return nil, err
for _, treeDir := range treesDir {
err := tr.Load(treeDir)
if err != nil {
return nil, err
}
}
art, err := buildPackageIndex(src, tr.GetDatabase())
@@ -517,6 +519,7 @@ func (r *LuetSystemRepository) Client() Client {
func (r *LuetSystemRepository) Sync(force bool) (Repository, error) {
var repoUpdated bool = false
var treefs, metafs string
aurora := GetAurora()
Debug("Sync of the repository", r.Name, "in progress...")
c := r.Client()
@@ -648,9 +651,10 @@ func (r *LuetSystemRepository) Sync(force bool) (Repository, error) {
tsec, _ := strconv.ParseInt(repo.GetLastUpdate(), 10, 64)
InfoC(
Bold(Red(":house: Repository "+repo.GetName()+" revision: ")).String() +
Bold(Green(repo.GetRevision())).String() + " - " +
Bold(Green(time.Unix(tsec, 0).String())).String(),
aurora.Bold(
aurora.Red(":house: Repository "+repo.GetName()+" revision: ")).String() +
aurora.Bold(aurora.Green(repo.GetRevision())).String() + " - " +
aurora.Bold(aurora.Green(time.Unix(tsec, 0).String())).String(),
)
} else {
@@ -682,9 +686,10 @@ func (r *LuetSystemRepository) Sync(force bool) (Repository, error) {
repo.SetType(r.GetType())
repo.SetPriority(r.GetPriority())
InfoC(
Bold(Yellow(":information_source: Repository "+repo.GetName()+" priority: ")).String() +
Bold(Green(repo.GetPriority())).String() + " - type " +
Bold(Green(repo.GetType())).String(),
aurora.Bold(
aurora.Yellow(":information_source: Repository "+repo.GetName()+" priority: ")).String() +
aurora.Bold(aurora.Green(repo.GetPriority())).String() + " - type " +
aurora.Bold(aurora.Green(repo.GetType())).String(),
)
return repo, nil
}

View File

@@ -83,7 +83,7 @@ var _ = Describe("Repository", func() {
Expect(helpers.Exists(spec.Rel("b-test-1.0.package.tar"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("b-test-1.0.metadata.yaml"))).To(BeTrue())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/buildable", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/buildable"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
Expect(helpers.Exists(spec.Rel(REPOSITORY_SPECFILE))).ToNot(BeTrue())
@@ -165,7 +165,7 @@ var _ = Describe("Repository", func() {
Expect(helpers.Exists(spec2.Rel("alpine-seed-1.0.package.tar"))).To(BeTrue())
Expect(helpers.Exists(spec2.Rel("alpine-seed-1.0.metadata.yaml"))).To(BeTrue())
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, "../../tests/fixtures/buildable", pkg.NewInMemoryDatabase(false))
repo, err := GenerateRepository("test", "description", "disk", []string{tmpdir}, 1, tmpdir, []string{"../../tests/fixtures/buildable"}, pkg.NewInMemoryDatabase(false))
Expect(err).ToNot(HaveOccurred())
Expect(repo.GetName()).To(Equal("test"))
Expect(helpers.Exists(spec.Rel(REPOSITORY_SPECFILE))).ToNot(BeTrue())

View File

@@ -3,6 +3,7 @@ package logger
import (
"fmt"
"os"
"regexp"
. "github.com/mudler/luet/pkg/config"
@@ -15,6 +16,7 @@ import (
var s *spinner.Spinner = nil
var z *zap.Logger = nil
var aurora Aurora = nil
func NewSpinner() {
if s == nil {
@@ -24,6 +26,16 @@ func NewSpinner() {
}
}
func InitAurora() {
if aurora == nil {
aurora = NewAurora(LuetCfg.GetLogging().Color)
}
}
func GetAurora() Aurora {
return aurora
}
func ZapLogger() error {
var err error
if z == nil {
@@ -158,7 +170,7 @@ func msg(level string, withoutColor bool, msg ...interface{}) {
var levelMsg string
if withoutColor {
if withoutColor || !LuetCfg.GetLogging().Color {
levelMsg = message
} else {
switch level {
@@ -173,7 +185,12 @@ func msg(level string, withoutColor bool, msg ...interface{}) {
}
}
levelMsg = emoji.Sprint(levelMsg)
if LuetCfg.GetLogging().EnableEmoji {
levelMsg = emoji.Sprint(levelMsg)
} else {
re := regexp.MustCompile(`[:][\w]+[:]`)
levelMsg = re.ReplaceAllString(levelMsg, "")
}
if z != nil {
log2File(level, message)

View File

@@ -170,10 +170,10 @@ func (assertions PackagesAssertions) Order(definitiondb pkg.PackageDatabase, fin
sort.Sort(unorderedAssertions)
// Build a topological graph
//graph := toposort.NewGraph(len(unorderedAssertions))
// graph.AddNodes(fingerprints...)
for _, a := range unorderedAssertions {
currentPkg := a.Package
added := map[string]interface{}{}
REQUIRES:
for _, requiredDef := range currentPkg.GetRequires() {
if def, err := definitiondb.FindPackage(requiredDef); err == nil { // Provides: Get a chance of being override here
requiredDef = def.(*pkg.DefaultPackage)
@@ -185,9 +185,12 @@ func (assertions PackagesAssertions) Order(definitiondb pkg.PackageDatabase, fin
if req != nil {
requiredDef = req.Package
}
if _, ok := added[requiredDef.GetFingerPrint()]; ok {
continue REQUIRES
}
// Expand also here, as we need to order them (or instead the solver should give back the dep correctly?)
graph.AddEdge(currentPkg.GetFingerPrint(), requiredDef.GetFingerPrint())
added[requiredDef.GetFingerPrint()] = nil
}
}
result, err := graph.TopSort(fingerprint)

View File

@@ -18,6 +18,8 @@ package solver
import (
//. "github.com/mudler/luet/pkg/logger"
"fmt"
"github.com/pkg/errors"
"github.com/crillab/gophersat/bf"
@@ -28,9 +30,11 @@ import (
type PackageSolver interface {
SetDefinitionDatabase(pkg.PackageDatabase)
Install(p pkg.Packages) (PackagesAssertions, error)
Uninstall(candidate pkg.Package, checkconflicts bool) (pkg.Packages, error)
Uninstall(candidate pkg.Package, checkconflicts, full bool) (pkg.Packages, error)
ConflictsWithInstalled(p pkg.Package) (bool, error)
ConflictsWith(p pkg.Package, ls pkg.Packages) (bool, error)
Conflicts(pack pkg.Package, lsp pkg.Packages) (bool, error)
World() pkg.Packages
Upgrade(checkconflicts bool) (pkg.Packages, PackagesAssertions, error)
@@ -149,6 +153,43 @@ func (s *Solver) getList(db pkg.PackageDatabase, lsp pkg.Packages) (pkg.Packages
return ls, nil
}
// Conflicts acts like ConflictsWith, but uses package's reverse dependencies to
// determine if it conflicts with the given set
func (s *Solver) Conflicts(pack pkg.Package, lsp pkg.Packages) (bool, error) {
p, err := s.DefinitionDatabase.FindPackage(pack)
if err != nil {
p = pack
}
ls, err := s.getList(s.DefinitionDatabase, lsp)
if err != nil {
return false, errors.Wrap(err, "Package not found in definition db")
}
if s.noRulesWorld() {
return false, nil
}
temporarySet := pkg.NewInMemoryDatabase(false)
for _, p := range ls {
temporarySet.CreatePackage(p)
}
visited := make(map[string]interface{})
revdeps := p.ExpandedRevdeps(temporarySet, visited)
var revdepsErr error
for _, r := range revdeps {
if revdepsErr == nil {
revdepsErr = errors.New("")
}
revdepsErr = errors.New(fmt.Sprintf("%s\n%s", revdepsErr.Error(), r.HumanReadableString()))
}
return len(revdeps) != 0, revdepsErr
}
// ConflictsWith return true if a package is part of the requirement set of a list of package
// return false otherwise (and thus it is NOT relevant to the given list)
func (s *Solver) ConflictsWith(pack pkg.Package, lsp pkg.Packages) (bool, error) {
p, err := s.DefinitionDatabase.FindPackage(pack)
if err != nil {
@@ -240,7 +281,7 @@ func (s *Solver) Upgrade(checkconflicts bool) (pkg.Packages, PackagesAssertions,
s2.SetResolver(s.Resolver)
// Then try to uninstall the versions in the system, and store that tree
for _, p := range toUninstall {
r, err := s.Uninstall(p, checkconflicts)
r, err := s.Uninstall(p, checkconflicts, false)
if err != nil {
return nil, nil, errors.Wrap(err, "Could not compute upgrade - couldn't uninstall selected candidate "+p.GetFingerPrint())
}
@@ -261,7 +302,7 @@ func (s *Solver) Upgrade(checkconflicts bool) (pkg.Packages, PackagesAssertions,
// Uninstall takes a candidate package and return a list of packages that would be removed
// in order to purge the candidate. Returns error if unsat.
func (s *Solver) Uninstall(c pkg.Package, checkconflicts bool) (pkg.Packages, error) {
func (s *Solver) Uninstall(c pkg.Package, checkconflicts, full bool) (pkg.Packages, error) {
var res pkg.Packages
candidate, err := s.InstalledDatabase.FindPackage(c)
if err != nil {
@@ -280,6 +321,16 @@ func (s *Solver) Uninstall(c pkg.Package, checkconflicts bool) (pkg.Packages, er
// Build a fake "Installed" - Candidate and its requires tree
var InstalledMinusCandidate pkg.Packages
// We are asked to not perform a full uninstall (checking all the possible requires that could
// be removed). Let's only check if we can remove the selected package
if !full && checkconflicts {
if conflicts, err := s.Conflicts(candidate, s.Installed()); conflicts {
return nil, err
} else {
return pkg.Packages{candidate}, nil
}
}
// TODO: Can be optimized
for _, i := range s.Installed() {
if !i.Matches(candidate) {

View File

@@ -360,6 +360,51 @@ var _ = Describe("Solver", func() {
Expect(err).ToNot(HaveOccurred())
})
It("Install only package requires", func() {
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
C := pkg.NewPackage("C", "1.1", []*pkg.DefaultPackage{&pkg.DefaultPackage{
Name: "A",
Version: ">=1.0",
}}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "1.9", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{
&pkg.DefaultPackage{
Name: "D",
Version: ">=0",
},
}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "1.2", []*pkg.DefaultPackage{
&pkg.DefaultPackage{
Name: "D",
Version: ">=1.0",
},
}, []*pkg.DefaultPackage{})
for _, p := range []pkg.Package{A, B, C, D, E} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Install([]pkg.Package{C})
Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: D, Value: false}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: E, Value: true}))
Expect(len(solution)).To(Equal(4))
Expect(err).ToNot(HaveOccurred())
})
It("Selects best version", func() {
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -547,7 +592,7 @@ var _ = Describe("Solver", func() {
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Uninstall(A, true)
solution, err := s.Uninstall(A, true, true)
Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(A.IsFlagged(false)))
@@ -573,7 +618,7 @@ var _ = Describe("Solver", func() {
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Uninstall(&pkg.DefaultPackage{Name: "A", Version: ">1.0"}, true)
solution, err := s.Uninstall(&pkg.DefaultPackage{Name: "A", Version: ">1.0"}, true, true)
Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(A.IsFlagged(false)))
@@ -672,6 +717,99 @@ var _ = Describe("Solver", func() {
Expect(err).ToNot(HaveOccurred())
Expect(val).ToNot(BeTrue())
})
It("Find conflicts using revdeps", func() {
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{})
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
val, err := s.Conflicts(A, dbInstalled.World())
Expect(err.Error()).To(Equal("\n/B-"))
Expect(val).To(BeTrue())
})
It("Find nested conflicts with revdeps", func() {
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{})
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
val, err := s.Conflicts(D, dbInstalled.World())
Expect(err.Error()).To(Equal("\n/A-\n/B-"))
Expect(val).To(BeTrue())
})
It("Doesn't find nested conflicts with revdeps", func() {
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{})
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
val, err := s.Conflicts(C, dbInstalled.World())
Expect(err).ToNot(HaveOccurred())
Expect(val).ToNot(BeTrue())
})
It("Doesn't find conflicts with revdeps", func() {
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
val, err := s.Conflicts(C, dbInstalled.World())
Expect(err).ToNot(HaveOccurred())
Expect(val).ToNot(BeTrue())
})
It("Uninstalls simple packages not in world correctly", func() {
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -688,7 +826,7 @@ var _ = Describe("Solver", func() {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Uninstall(A, true)
solution, err := s.Uninstall(A, true, true)
Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(A.IsFlagged(false)))
@@ -712,7 +850,7 @@ var _ = Describe("Solver", func() {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Uninstall(A, true)
solution, err := s.Uninstall(A, true, true)
Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(A.IsFlagged(false)))
@@ -735,7 +873,7 @@ var _ = Describe("Solver", func() {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Uninstall(A, true)
solution, err := s.Uninstall(A, true, true)
Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(A.IsFlagged(false)))
@@ -760,7 +898,7 @@ var _ = Describe("Solver", func() {
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Uninstall(A, true)
solution, err := s.Uninstall(A, true, true)
Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(A.IsFlagged(false)))
@@ -786,7 +924,7 @@ var _ = Describe("Solver", func() {
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Uninstall(A, true)
solution, err := s.Uninstall(A, true, true)
Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(A.IsFlagged(false)))

View File

@@ -0,0 +1,7 @@
image: "alpine"
prelude:
- mkdir /foo
steps:
- echo artifact5 > /foo/test1
- echo artifact6 > /foo/test2
package_dir: /foo

View File

@@ -0,0 +1,3 @@
category: "test"
name: "dironly"
version: "1.0"

View File

@@ -0,0 +1,11 @@
image: "alpine"
prelude:
- mkdir /foo
- chmod +x generate.sh
steps:
- echo artifact5 > /foo/test5
- echo artifact6 > /foo/test6
- ./generate.sh
package_dir: /foo
includes:
- /test5

View File

@@ -0,0 +1,3 @@
category: "test"
name: "dironly_filter"
version: "1.0"

View File

@@ -0,0 +1 @@
echo generated > /foo/artifact42

View File

@@ -70,7 +70,7 @@ testInstall() {
testUnInstall() {
luet uninstall --config $tmpdir/luet.yaml test/b
luet uninstall --full --config $tmpdir/luet.yaml test/b
installst=$?
assertEquals 'uninstall test successfully' "$installst" "0"
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/b' ]"