Compare commits

...

16 Commits
0.6 ... 0.6.2

Author SHA1 Message Date
Ettore Di Giacinto
0ce1baa448 Prepare for 0.6.2 tag 2020-02-23 22:41:33 +01:00
Ettore Di Giacinto
07610bc216 Add build option to remove backend artifacts
Add keep-exported-images to build to instruct to remove backend artifacts (docker images)
2020-02-21 22:33:18 +01:00
Daniele Rondina
a04dadf100 Add support for parsing version with build 2020-02-21 21:56:32 +01:00
Daniele Rondina
2f4ce42472 Update vendor github.com/Sabayon/pkgs-checker 2020-02-21 21:55:42 +01:00
Daniele Rondina
def04724d4 Add support for build identifier on version 2020-02-20 17:46:47 +01:00
Ettore Di Giacinto
38296bc5d7 Add test for HashFingerprint() 2020-02-19 18:33:14 +01:00
Ettore Di Giacinto
7e16e0cdb6 Add HashFingerprint() to Package and consume it while generating image names
In this way we don't depend on the package fingerpint characters while generating images, allowing
to support completely semver (e.g. + character is not allowed in docker images tag).

This change is not backward compatible with images currently already built and will invalidate the cache
2020-02-19 18:28:29 +01:00
Ettore Di Giacinto
647ea35983 Add a way to extend the CLI with external binaries
This lets luet to be extended like git does (just by having luet-subcommand binaries under $PATH)
following the UNIX filosophy. It has the downside that we silence the errors from cobra and we handle
them by ourselves.

Also the Exec syscall is not portable, and it should have implementation for each platform (hence why in helpers)
2020-02-18 23:08:14 +01:00
Ettore Di Giacinto
4648dedb55 Add --nodeps, --onlydeps and --force to Installer
This allows also to use it on upgrade and uninstall as it exposes the Installer options to the CLI.

See #48, #49
2020-02-18 18:37:56 +01:00
Ettore Di Giacinto
2ce427d601 Add Nodeps, Onlydeps and Force options to Compiler
See #41
2020-02-18 18:36:44 +01:00
Ettore Di Giacinto
b01c017507 Add HumanReadableString() to Package 2020-02-18 18:20:45 +01:00
Ettore Di Giacinto
189c042fea Add dev version tag 2020-02-17 18:04:36 +01:00
Ettore Di Giacinto
4e675723e8 Prepare for 0.6.1 tag 2020-02-17 18:04:05 +01:00
Ettore Di Giacinto
dd00d491b9 Skip repository if no candidate is found
FindPackageCandidate is idempotent and returns the same definition if no new is found.
This prevents installs from multiple-repos
2020-02-17 17:21:31 +01:00
Ettore Di Giacinto
26b94888c3 Skip image building if we pulled them successfully 2020-02-15 22:53:00 +01:00
Ettore Di Giacinto
01e635bd78 Add dev version tag 2020-02-15 16:52:30 +01:00
19 changed files with 605 additions and 215 deletions

View File

@@ -15,18 +15,17 @@
package cmd package cmd
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/mudler/luet/pkg/compiler" "github.com/mudler/luet/pkg/compiler"
"github.com/mudler/luet/pkg/compiler/backend" "github.com/mudler/luet/pkg/compiler/backend"
. "github.com/mudler/luet/pkg/config" . "github.com/mudler/luet/pkg/config"
helpers "github.com/mudler/luet/pkg/helpers"
. "github.com/mudler/luet/pkg/logger" . "github.com/mudler/luet/pkg/logger"
pkg "github.com/mudler/luet/pkg/package" pkg "github.com/mudler/luet/pkg/package"
tree "github.com/mudler/luet/pkg/tree" tree "github.com/mudler/luet/pkg/tree"
_gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -45,12 +44,16 @@ var buildCmd = &cobra.Command{
viper.BindPFlag("revdeps", cmd.Flags().Lookup("revdeps")) viper.BindPFlag("revdeps", cmd.Flags().Lookup("revdeps"))
viper.BindPFlag("all", cmd.Flags().Lookup("all")) viper.BindPFlag("all", cmd.Flags().Lookup("all"))
viper.BindPFlag("compression", cmd.Flags().Lookup("compression")) viper.BindPFlag("compression", cmd.Flags().Lookup("compression"))
viper.BindPFlag("nodeps", cmd.Flags().Lookup("nodeps"))
viper.BindPFlag("onlydeps", cmd.Flags().Lookup("onlydeps"))
viper.BindPFlag("image-repository", cmd.Flags().Lookup("image-repository")) viper.BindPFlag("image-repository", cmd.Flags().Lookup("image-repository"))
viper.BindPFlag("push", cmd.Flags().Lookup("push")) viper.BindPFlag("push", cmd.Flags().Lookup("push"))
viper.BindPFlag("pull", cmd.Flags().Lookup("pull")) viper.BindPFlag("pull", cmd.Flags().Lookup("pull"))
viper.BindPFlag("keep-images", cmd.Flags().Lookup("keep-images")) viper.BindPFlag("keep-images", cmd.Flags().Lookup("keep-images"))
LuetCfg.Viper.BindPFlag("keep-exported-images", cmd.Flags().Lookup("keep-exported-images"))
LuetCfg.Viper.BindPFlag("solver.type", cmd.Flags().Lookup("solver-type")) LuetCfg.Viper.BindPFlag("solver.type", cmd.Flags().Lookup("solver-type"))
LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount")) LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount"))
LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate")) LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate"))
@@ -72,6 +75,9 @@ var buildCmd = &cobra.Command{
push := viper.GetBool("push") push := viper.GetBool("push")
pull := viper.GetBool("pull") pull := viper.GetBool("pull")
keepImages := viper.GetBool("keep-images") keepImages := viper.GetBool("keep-images")
nodeps := viper.GetBool("nodeps")
onlydeps := viper.GetBool("onlydeps")
keepExportedImages := viper.GetBool("keep-exported-images")
compilerSpecs := compiler.NewLuetCompilationspecs() compilerSpecs := compiler.NewLuetCompilationspecs()
var compilerBackend compiler.CompilerBackend var compilerBackend compiler.CompilerBackend
@@ -126,31 +132,21 @@ var buildCmd = &cobra.Command{
opts.PullFirst = pull opts.PullFirst = pull
opts.KeepImg = keepImages opts.KeepImg = keepImages
opts.Push = push opts.Push = push
opts.OnlyDeps = onlydeps
opts.NoDeps = nodeps
opts.KeepImageExport = keepExportedImages
luetCompiler := compiler.NewLuetCompiler(compilerBackend, generalRecipe.GetDatabase(), opts) luetCompiler := compiler.NewLuetCompiler(compilerBackend, generalRecipe.GetDatabase(), opts)
luetCompiler.SetConcurrency(concurrency) luetCompiler.SetConcurrency(concurrency)
luetCompiler.SetCompressionType(compiler.CompressionImplementation(compressionType)) luetCompiler.SetCompressionType(compiler.CompressionImplementation(compressionType))
if !all { if !all {
for _, a := range args { for _, a := range args {
gp, err := _gentoo.ParsePackageStr(a)
pack, err := helpers.ParsePackageStr(a)
if err != nil { if err != nil {
Fatal("Invalid package string ", a, ": ", err.Error()) Fatal("Invalid package string ", a, ": ", err.Error())
} }
if gp.Version == "" {
gp.Version = "0"
gp.Condition = _gentoo.PkgCondGreaterEqual
}
pack := &pkg.DefaultPackage{
Name: gp.Name,
Version: fmt.Sprintf("%s%s%s",
pkg.PkgSelectorConditionFromInt(gp.Condition.Int()).String(),
gp.Version,
gp.VersionSuffix,
),
Category: gp.Category,
Uri: make([]string, 0),
}
spec, err := luetCompiler.FromPackage(pack) spec, err := luetCompiler.FromPackage(pack)
if err != nil { if err != nil {
Fatal("Error: " + err.Error()) Fatal("Error: " + err.Error())
@@ -212,6 +208,9 @@ func init() {
buildCmd.Flags().Bool("push", false, "Push images to a hub") buildCmd.Flags().Bool("push", false, "Push images to a hub")
buildCmd.Flags().Bool("pull", false, "Pull images from a hub") buildCmd.Flags().Bool("pull", false, "Pull images from a hub")
buildCmd.Flags().Bool("keep-images", true, "Keep built docker images in the host") buildCmd.Flags().Bool("keep-images", true, "Keep built docker images in the host")
buildCmd.Flags().Bool("nodeps", false, "Build only the target packages, skipping deps (it works only if you already built the deps locally, or by using --pull) ")
buildCmd.Flags().Bool("onlydeps", false, "Build only package dependencies")
buildCmd.Flags().Bool("keep-exported-images", false, "Keep exported images used during building")
buildCmd.Flags().String("solver-type", "", "Solver strategy") buildCmd.Flags().String("solver-type", "", "Solver strategy")
buildCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate") buildCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate")

View File

@@ -15,17 +15,16 @@
package cmd package cmd
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
installer "github.com/mudler/luet/pkg/installer" installer "github.com/mudler/luet/pkg/installer"
. "github.com/mudler/luet/pkg/config" . "github.com/mudler/luet/pkg/config"
helpers "github.com/mudler/luet/pkg/helpers"
. "github.com/mudler/luet/pkg/logger" . "github.com/mudler/luet/pkg/logger"
pkg "github.com/mudler/luet/pkg/package" pkg "github.com/mudler/luet/pkg/package"
_gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -39,6 +38,10 @@ var installCmd = &cobra.Command{
LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount")) LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount"))
LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate")) LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate"))
LuetCfg.Viper.BindPFlag("solver.max_attempts", cmd.Flags().Lookup("solver-attempts")) LuetCfg.Viper.BindPFlag("solver.max_attempts", cmd.Flags().Lookup("solver-attempts"))
LuetCfg.Viper.BindPFlag("onlydeps", cmd.Flags().Lookup("onlydeps"))
LuetCfg.Viper.BindPFlag("nodeps", cmd.Flags().Lookup("nodeps"))
LuetCfg.Viper.BindPFlag("force", cmd.Flags().Lookup("force"))
}, },
Long: `Install packages in parallel`, Long: `Install packages in parallel`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
@@ -46,26 +49,10 @@ var installCmd = &cobra.Command{
var systemDB pkg.PackageDatabase var systemDB pkg.PackageDatabase
for _, a := range args { for _, a := range args {
gp, err := _gentoo.ParsePackageStr(a) pack, err := helpers.ParsePackageStr(a)
if err != nil { if err != nil {
Fatal("Invalid package string ", a, ": ", err.Error()) Fatal("Invalid package string ", a, ": ", err.Error())
} }
if gp.Version == "" {
gp.Version = "0"
gp.Condition = _gentoo.PkgCondGreaterEqual
}
pack := &pkg.DefaultPackage{
Name: gp.Name,
Version: fmt.Sprintf("%s%s%s",
pkg.PkgSelectorConditionFromInt(gp.Condition.Int()).String(),
gp.Version,
gp.VersionSuffix,
),
Category: gp.Category,
Uri: make([]string, 0),
}
toInstall = append(toInstall, pack) toInstall = append(toInstall, pack)
} }
@@ -83,6 +70,9 @@ var installCmd = &cobra.Command{
discount := LuetCfg.Viper.GetFloat64("solver.discount") discount := LuetCfg.Viper.GetFloat64("solver.discount")
rate := LuetCfg.Viper.GetFloat64("solver.rate") rate := LuetCfg.Viper.GetFloat64("solver.rate")
attempts := LuetCfg.Viper.GetInt("solver.max_attempts") attempts := LuetCfg.Viper.GetInt("solver.max_attempts")
force := LuetCfg.Viper.GetBool("force")
nodeps := LuetCfg.Viper.GetBool("nodeps")
onlydeps := LuetCfg.Viper.GetBool("onlydeps")
LuetCfg.GetSolverOptions().Type = stype LuetCfg.GetSolverOptions().Type = stype
LuetCfg.GetSolverOptions().LearnRate = float32(rate) LuetCfg.GetSolverOptions().LearnRate = float32(rate)
@@ -91,7 +81,13 @@ var installCmd = &cobra.Command{
Debug("Solver", LuetCfg.GetSolverOptions().CompactString()) Debug("Solver", LuetCfg.GetSolverOptions().CompactString())
inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{Concurrency: LuetCfg.GetGeneral().Concurrency, SolverOptions: *LuetCfg.GetSolverOptions()}) inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{
Concurrency: LuetCfg.GetGeneral().Concurrency,
SolverOptions: *LuetCfg.GetSolverOptions(),
NoDeps: nodeps,
Force: force,
OnlyDeps: onlydeps,
})
inst.Repositories(repos) inst.Repositories(repos)
if LuetCfg.GetSystem().DatabaseEngine == "boltdb" { if LuetCfg.GetSystem().DatabaseEngine == "boltdb" {
@@ -119,6 +115,9 @@ func init() {
installCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate") installCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate")
installCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate") installCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate")
installCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts") installCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts")
installCmd.Flags().Bool("nodeps", false, "Don't consider package dependencies (harmful!)")
installCmd.Flags().Bool("onlydeps", false, "Consider **only** package dependencies")
installCmd.Flags().Bool("force", false, "Skip errors and keep going (potentially harmful)")
RootCmd.AddCommand(installCmd) RootCmd.AddCommand(installCmd)
} }

View File

@@ -16,6 +16,7 @@
package cmd package cmd
import ( import (
"fmt"
"os" "os"
"os/user" "os/user"
"path/filepath" "path/filepath"
@@ -24,6 +25,7 @@ import (
"github.com/marcsauter/single" "github.com/marcsauter/single"
config "github.com/mudler/luet/pkg/config" config "github.com/mudler/luet/pkg/config"
helpers "github.com/mudler/luet/pkg/helpers"
. "github.com/mudler/luet/pkg/logger" . "github.com/mudler/luet/pkg/logger"
repo "github.com/mudler/luet/pkg/repository" repo "github.com/mudler/luet/pkg/repository"
@@ -35,7 +37,7 @@ var cfgFile string
var Verbose bool var Verbose bool
const ( const (
LuetCLIVersion = "0.6" LuetCLIVersion = "0.6.2"
LuetEnvPrefix = "LUET" LuetEnvPrefix = "LUET"
) )
@@ -51,12 +53,13 @@ var RootCmd = &cobra.Command{
Fatal("failed to load configuration:", err.Error()) Fatal("failed to load configuration:", err.Error())
} }
}, },
SilenceErrors: true,
} }
func LoadConfig(c *config.LuetConfig) error { func LoadConfig(c *config.LuetConfig) error {
// If a config file is found, read it in. // If a config file is found, read it in.
if err := c.Viper.ReadInConfig(); err != nil { if err := c.Viper.ReadInConfig(); err != nil {
Warning(err) Debug(err)
} }
err := c.Viper.Unmarshal(&config.LuetCfg) err := c.Viper.Unmarshal(&config.LuetCfg)
@@ -99,8 +102,18 @@ func Execute() {
} }
defer s.TryUnlock() defer s.TryUnlock()
} }
if err := RootCmd.Execute(); err != nil { if err := RootCmd.Execute(); err != nil {
Error(err) if len(os.Args) > 0 {
for _, c := range RootCmd.Commands() {
if c.Name() == os.Args[1] {
os.Exit(-1) // Something failed
}
}
// Try to load a bin from path.
helpers.Exec("luet-"+os.Args[1], os.Args[1:], os.Environ())
}
fmt.Println(err)
os.Exit(-1) os.Exit(-1)
} }
} }

View File

@@ -15,16 +15,15 @@
package cmd package cmd
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
. "github.com/mudler/luet/pkg/config" . "github.com/mudler/luet/pkg/config"
helpers "github.com/mudler/luet/pkg/helpers"
installer "github.com/mudler/luet/pkg/installer" installer "github.com/mudler/luet/pkg/installer"
. "github.com/mudler/luet/pkg/logger" . "github.com/mudler/luet/pkg/logger"
pkg "github.com/mudler/luet/pkg/package" pkg "github.com/mudler/luet/pkg/package"
_gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -39,34 +38,25 @@ var uninstallCmd = &cobra.Command{
LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount")) LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount"))
LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate")) LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate"))
LuetCfg.Viper.BindPFlag("solver.max_attempts", cmd.Flags().Lookup("solver-attempts")) LuetCfg.Viper.BindPFlag("solver.max_attempts", cmd.Flags().Lookup("solver-attempts"))
LuetCfg.Viper.BindPFlag("nodeps", cmd.Flags().Lookup("nodeps"))
LuetCfg.Viper.BindPFlag("force", cmd.Flags().Lookup("force"))
}, },
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
var systemDB pkg.PackageDatabase var systemDB pkg.PackageDatabase
for _, a := range args { for _, a := range args {
gp, err := _gentoo.ParsePackageStr(a)
pack, err := helpers.ParsePackageStr(a)
if err != nil { if err != nil {
Fatal("Invalid package string ", a, ": ", err.Error()) Fatal("Invalid package string ", a, ": ", err.Error())
} }
if gp.Version == "" {
gp.Version = "0"
gp.Condition = _gentoo.PkgCondGreaterEqual
}
pack := &pkg.DefaultPackage{
Name: gp.Name,
Version: fmt.Sprintf("%s%s%s",
pkg.PkgSelectorConditionFromInt(gp.Condition.Int()).String(),
gp.Version,
gp.VersionSuffix,
),
Category: gp.Category,
Uri: make([]string, 0),
}
stype := LuetCfg.Viper.GetString("solver.type") stype := LuetCfg.Viper.GetString("solver.type")
discount := LuetCfg.Viper.GetFloat64("solver.discount") discount := LuetCfg.Viper.GetFloat64("solver.discount")
rate := LuetCfg.Viper.GetFloat64("solver.rate") rate := LuetCfg.Viper.GetFloat64("solver.rate")
attempts := LuetCfg.Viper.GetInt("solver.max_attempts") attempts := LuetCfg.Viper.GetInt("solver.max_attempts")
force := LuetCfg.Viper.GetBool("force")
nodeps := LuetCfg.Viper.GetBool("nodeps")
LuetCfg.GetSolverOptions().Type = stype LuetCfg.GetSolverOptions().Type = stype
LuetCfg.GetSolverOptions().LearnRate = float32(rate) LuetCfg.GetSolverOptions().LearnRate = float32(rate)
@@ -75,7 +65,12 @@ var uninstallCmd = &cobra.Command{
Debug("Solver", LuetCfg.GetSolverOptions().CompactString()) Debug("Solver", LuetCfg.GetSolverOptions().CompactString())
inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{Concurrency: LuetCfg.GetGeneral().Concurrency, SolverOptions: *LuetCfg.GetSolverOptions()}) inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{
Concurrency: LuetCfg.GetGeneral().Concurrency,
SolverOptions: *LuetCfg.GetSolverOptions(),
NoDeps: nodeps,
Force: force,
})
if LuetCfg.GetSystem().DatabaseEngine == "boltdb" { if LuetCfg.GetSystem().DatabaseEngine == "boltdb" {
systemDB = pkg.NewBoltDatabase( systemDB = pkg.NewBoltDatabase(
@@ -103,5 +98,8 @@ func init() {
uninstallCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate") uninstallCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate")
uninstallCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate") uninstallCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate")
uninstallCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts") uninstallCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts")
uninstallCmd.Flags().Bool("nodeps", false, "Don't consider package dependencies (harmful!)")
uninstallCmd.Flags().Bool("force", false, "Force uninstall")
RootCmd.AddCommand(uninstallCmd) RootCmd.AddCommand(uninstallCmd)
} }

View File

@@ -36,6 +36,7 @@ var upgradeCmd = &cobra.Command{
LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount")) LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount"))
LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate")) LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate"))
LuetCfg.Viper.BindPFlag("solver.max_attempts", cmd.Flags().Lookup("solver-attempts")) LuetCfg.Viper.BindPFlag("solver.max_attempts", cmd.Flags().Lookup("solver-attempts"))
LuetCfg.Viper.BindPFlag("force", cmd.Flags().Lookup("force"))
}, },
Long: `Upgrades packages in parallel`, Long: `Upgrades packages in parallel`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
@@ -55,6 +56,7 @@ var upgradeCmd = &cobra.Command{
discount := LuetCfg.Viper.GetFloat64("solver.discount") discount := LuetCfg.Viper.GetFloat64("solver.discount")
rate := LuetCfg.Viper.GetFloat64("solver.rate") rate := LuetCfg.Viper.GetFloat64("solver.rate")
attempts := LuetCfg.Viper.GetInt("solver.max_attempts") attempts := LuetCfg.Viper.GetInt("solver.max_attempts")
force := LuetCfg.Viper.GetBool("force")
LuetCfg.GetSolverOptions().Type = stype LuetCfg.GetSolverOptions().Type = stype
LuetCfg.GetSolverOptions().LearnRate = float32(rate) LuetCfg.GetSolverOptions().LearnRate = float32(rate)
@@ -63,7 +65,11 @@ var upgradeCmd = &cobra.Command{
Debug("Solver", LuetCfg.GetSolverOptions().String()) Debug("Solver", LuetCfg.GetSolverOptions().String())
inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{Concurrency: LuetCfg.GetGeneral().Concurrency, SolverOptions: *LuetCfg.GetSolverOptions()}) inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{
Concurrency: LuetCfg.GetGeneral().Concurrency,
SolverOptions: *LuetCfg.GetSolverOptions(),
Force: force,
})
inst.Repositories(repos) inst.Repositories(repos)
_, err := inst.SyncRepositories(false) _, err := inst.SyncRepositories(false)
if err != nil { if err != nil {
@@ -95,5 +101,7 @@ func init() {
upgradeCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate") upgradeCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate")
upgradeCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate") upgradeCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate")
upgradeCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts") upgradeCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts")
upgradeCmd.Flags().Bool("force", false, "Force upgrade by ignoring errors")
RootCmd.AddCommand(upgradeCmd) RootCmd.AddCommand(upgradeCmd)
} }

4
go.mod
View File

@@ -4,7 +4,8 @@ go 1.12
require ( require (
github.com/DataDog/zstd v1.4.4 // indirect github.com/DataDog/zstd v1.4.4 // indirect
github.com/Sabayon/pkgs-checker v0.4.2-0.20200101193228-1d500105afb7 github.com/MottainaiCI/simplestreams-builder v0.0.0-20190710131531-efb382161f56 // indirect
github.com/Sabayon/pkgs-checker v0.5.1-0.20200221202320-073693f2c657
github.com/asdine/storm v0.0.0-20190418133842-e0f77eada154 github.com/asdine/storm v0.0.0-20190418133842-e0f77eada154
github.com/briandowns/spinner v1.7.0 github.com/briandowns/spinner v1.7.0
github.com/cavaliercoder/grab v2.0.0+incompatible github.com/cavaliercoder/grab v2.0.0+incompatible
@@ -12,6 +13,7 @@ require (
github.com/docker/docker v0.7.3-0.20180827131323-0c5f8d2b9b23 github.com/docker/docker v0.7.3-0.20180827131323-0c5f8d2b9b23
github.com/ecooper/qlearning v0.0.0-20160612200101-3075011a69fd github.com/ecooper/qlearning v0.0.0-20160612200101-3075011a69fd
github.com/ghodss/yaml v1.0.0 github.com/ghodss/yaml v1.0.0
github.com/go-yaml/yaml v2.1.0+incompatible // indirect
github.com/hashicorp/go-version v1.2.0 github.com/hashicorp/go-version v1.2.0
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3
github.com/klauspost/pgzip v1.2.1 github.com/klauspost/pgzip v1.2.1

7
go.sum
View File

@@ -9,11 +9,16 @@ github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA= github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/MottainaiCI/simplestreams-builder v0.0.0-20190710131531-efb382161f56 h1:XCZM9J5KqLsr5NqtrZuXiD3X5fe5IfgU7IIUZzpeFBk=
github.com/MottainaiCI/simplestreams-builder v0.0.0-20190710131531-efb382161f56/go.mod h1:+Gbv6dg6TPHWq4oDjZY1vn978PLCEZ2hOu8kvn+S7t4=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Sabayon/pkgs-checker v0.4.2-0.20200101193228-1d500105afb7 h1:Vf80sSLu1ZWjjMmUKhw0FqM43lEOvT8O5B22NaHB6AQ= github.com/Sabayon/pkgs-checker v0.4.2-0.20200101193228-1d500105afb7 h1:Vf80sSLu1ZWjjMmUKhw0FqM43lEOvT8O5B22NaHB6AQ=
github.com/Sabayon/pkgs-checker v0.4.2-0.20200101193228-1d500105afb7/go.mod h1:GFGM6ZzSE5owdGgjLnulj0+Vt9UTd5LFGmB2AOVPYrE= github.com/Sabayon/pkgs-checker v0.4.2-0.20200101193228-1d500105afb7/go.mod h1:GFGM6ZzSE5owdGgjLnulj0+Vt9UTd5LFGmB2AOVPYrE=
github.com/Sabayon/pkgs-checker v0.5.0 h1:VRyyAxo6ox41Dytyl+K+QC+Tps0IxvqYbidu+AH+HUQ=
github.com/Sabayon/pkgs-checker v0.5.1-0.20200221202320-073693f2c657 h1:VK5S2Gh9kPUxX81zCFUgKVQn+hFy6VgyZMD3QLm76u8=
github.com/Sabayon/pkgs-checker v0.5.1-0.20200221202320-073693f2c657/go.mod h1:GFGM6ZzSE5owdGgjLnulj0+Vt9UTd5LFGmB2AOVPYrE=
github.com/Sereal/Sereal v0.0.0-20181211220259-509a78ddbda3 h1:Xu7z47ZiE/J+sKXHZMGxEor/oY2q6dq51fkO0JqdSwY= github.com/Sereal/Sereal v0.0.0-20181211220259-509a78ddbda3 h1:Xu7z47ZiE/J+sKXHZMGxEor/oY2q6dq51fkO0JqdSwY=
github.com/Sereal/Sereal v0.0.0-20181211220259-509a78ddbda3/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM= github.com/Sereal/Sereal v0.0.0-20181211220259-509a78ddbda3/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -91,6 +96,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=

View File

@@ -265,17 +265,12 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
} }
} }
fp := p.GetPackage().HashFingerprint()
if buildertaggedImage == "" { if buildertaggedImage == "" {
buildertaggedImage = cs.ImageRepository + "-" + p.GetPackage().GetFingerPrint() + "-builder" buildertaggedImage = cs.ImageRepository + "-" + fp + "-builder"
} }
if packageImage == "" { if packageImage == "" {
packageImage = cs.ImageRepository + "-" + p.GetPackage().GetFingerPrint() packageImage = cs.ImageRepository + "-" + fp
}
if cs.Options.PullFirst {
//Best effort pull
cs.Backend.DownloadImage(CompilerBackendOptions{ImageName: buildertaggedImage})
cs.Backend.DownloadImage(CompilerBackendOptions{ImageName: packageImage})
} }
Info(pkgTag, "Generating :whale: definition for builder image from", image) Info(pkgTag, "Generating :whale: definition for builder image from", image)
@@ -289,19 +284,29 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
Destination: p.Rel(p.GetPackage().GetFingerPrint() + "-builder.image.tar"), Destination: p.Rel(p.GetPackage().GetFingerPrint() + "-builder.image.tar"),
} }
err = cs.Backend.BuildImage(builderOpts) buildBuilderImage := true
if err != nil { if cs.Options.PullFirst {
return nil, errors.Wrap(err, "Could not build image: "+image+" "+builderOpts.DockerFileName) if err := cs.Backend.DownloadImage(builderOpts); err == nil {
buildBuilderImage = false
}
} }
err = cs.Backend.ExportImage(builderOpts) if buildBuilderImage {
if err != nil { if err = cs.Backend.BuildImage(builderOpts); err != nil {
return nil, errors.Wrap(err, "Could not build image: "+image+" "+builderOpts.DockerFileName)
}
}
if err = cs.Backend.ExportImage(builderOpts); err != nil {
return nil, errors.Wrap(err, "Could not export image") return nil, errors.Wrap(err, "Could not export image")
} }
if cs.Options.Push { if !cs.Options.KeepImageExport {
err = cs.Backend.Push(builderOpts) defer os.Remove(builderOpts.Destination)
if err != nil { }
if cs.Options.Push && buildBuilderImage {
if err = cs.Backend.Push(builderOpts); err != nil {
return nil, errors.Wrap(err, "Could not push image: "+image+" "+builderOpts.DockerFileName) return nil, errors.Wrap(err, "Could not push image: "+image+" "+builderOpts.DockerFileName)
} }
} }
@@ -320,14 +325,29 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
// return nil, errors.Wrap(err, "Could not export image to tar") // return nil, errors.Wrap(err, "Could not export image to tar")
// } // }
// } else { // } else {
if err := cs.Backend.BuildImage(runnerOpts); err != nil { buildPackageImage := true
return nil, errors.Wrap(err, "Failed building image for "+runnerOpts.ImageName+" "+runnerOpts.DockerFileName) if cs.Options.PullFirst {
//Best effort pull
if err := cs.Backend.DownloadImage(runnerOpts); err == nil {
buildPackageImage = false
}
} }
if buildPackageImage {
if err := cs.Backend.BuildImage(runnerOpts); err != nil {
return nil, errors.Wrap(err, "Failed building image for "+runnerOpts.ImageName+" "+runnerOpts.DockerFileName)
}
}
if err := cs.Backend.ExportImage(runnerOpts); err != nil { if err := cs.Backend.ExportImage(runnerOpts); err != nil {
return nil, errors.Wrap(err, "Failed exporting image") return nil, errors.Wrap(err, "Failed exporting image")
} }
if cs.Options.Push { if !cs.Options.KeepImageExport {
defer os.Remove(runnerOpts.Destination)
}
if cs.Options.Push && buildPackageImage {
err = cs.Backend.Push(runnerOpts) err = cs.Backend.Push(runnerOpts)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Could not push image: "+image+" "+builderOpts.DockerFileName) return nil, errors.Wrap(err, "Could not push image: "+image+" "+builderOpts.DockerFileName)
@@ -416,7 +436,7 @@ func (cs *LuetCompiler) packageFromImage(p CompilationSpec, tag string, keepPerm
return art, err return art, err
} }
} }
pkgTag := ":package: " + p.GetPackage().GetName() pkgTag := ":package: " + p.GetPackage().HumanReadableString()
Info(pkgTag, " 🍩 Build starts 🔨 🔨 🔨 ") Info(pkgTag, " 🍩 Build starts 🔨 🔨 🔨 ")
@@ -440,6 +460,10 @@ func (cs *LuetCompiler) packageFromImage(p CompilationSpec, tag string, keepPerm
return nil, errors.Wrap(err, "Could not export image") return nil, errors.Wrap(err, "Could not export image")
} }
if !cs.Options.KeepImageExport {
defer os.Remove(builderOpts.Destination)
}
rootfs, err := ioutil.TempDir(p.GetOutputPath(), "rootfs") rootfs, err := ioutil.TempDir(p.GetOutputPath(), "rootfs")
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Could not create tempdir") return nil, errors.Wrap(err, "Could not create tempdir")
@@ -472,7 +496,7 @@ func (cs *LuetCompiler) packageFromImage(p CompilationSpec, tag string, keepPerm
} }
} }
Info(pkgTag, " :white_check_mark: Done") Info(pkgTag, " :white_check_mark: Done")
err = artifact.WriteYaml(p.GetOutputPath()) err = artifact.WriteYaml(p.GetOutputPath())
if err != nil { if err != nil {
@@ -487,7 +511,7 @@ func (cs *LuetCompiler) ComputeDepTree(p CompilationSpec) (solver.PackagesAssert
solution, err := s.Install([]pkg.Package{p.GetPackage()}) solution, err := s.Install([]pkg.Package{p.GetPackage()})
if err != nil { if err != nil {
return nil, errors.Wrap(err, "While computing a solution for "+p.GetPackage().GetName()) return nil, errors.Wrap(err, "While computing a solution for "+p.GetPackage().HumanReadableString())
} }
dependencies := solution.Order(cs.Database, p.GetPackage().GetFingerPrint()) dependencies := solution.Order(cs.Database, p.GetPackage().GetFingerPrint())
@@ -519,7 +543,7 @@ func (cs *LuetCompiler) Compile(keepPermissions bool, p CompilationSpec) (Artifa
} }
func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p CompilationSpec) (Artifact, error) { func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p CompilationSpec) (Artifact, error) {
Info(":package: Compiling", p.GetPackage().GetName(), "version", p.GetPackage().GetVersion(), ".... :coffee:") Info(":package: Compiling", p.GetPackage().HumanReadableString(), ".... :coffee:")
if len(p.GetPackage().GetRequires()) == 0 && p.GetImage() == "" { if len(p.GetPackage().GetRequires()) == 0 && p.GetImage() == "" {
Error("Package with no deps and no seed image supplied, bailing out") Error("Package with no deps and no seed image supplied, bailing out")
@@ -547,74 +571,82 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p Compila
depsN := 0 depsN := 0
currentN := 0 currentN := 0
Info(":deciduous_tree: Build dependencies for " + p.GetPackage().GetName()) if !cs.Options.NoDeps {
for _, assertion := range dependencies { //highly dependent on the order Info(":deciduous_tree: Build dependencies for " + p.GetPackage().HumanReadableString())
depsN++ for _, assertion := range dependencies { //highly dependent on the order
Info(" :arrow_right_hook:", assertion.Package.GetName(), ":leaves:", assertion.Package.GetVersion(), "(", assertion.Package.GetCategory(), ")") depsN++
Info(" :arrow_right_hook:", assertion.Package.HumanReadableString(), ":leaves:")
}
for _, assertion := range dependencies { //highly dependent on the order
currentN++
pkgTag := fmt.Sprintf(":package: %d/%d %s ⤑ %s", currentN, depsN, p.GetPackage().GetName(), assertion.Package.GetName())
Info(pkgTag, " :zap: Building dependency")
compileSpec, err := cs.FromPackage(assertion.Package)
if err != nil {
return nil, errors.Wrap(err, "Error while generating compilespec for "+assertion.Package.GetName())
} }
compileSpec.SetOutputPath(p.GetOutputPath())
buildImageHash := cs.ImageRepository + ":" + assertion.Hash.BuildHash for _, assertion := range dependencies { //highly dependent on the order
currentPackageImageHash := cs.ImageRepository + ":" + assertion.Hash.PackageHash currentN++
Debug(pkgTag, " :arrow_right_hook: :whale: Builder image from", buildImageHash) pkgTag := fmt.Sprintf(":package: %d/%d %s ⤑ %s", currentN, depsN, p.GetPackage().HumanReadableString(), assertion.Package.HumanReadableString())
Debug(pkgTag, " :arrow_right_hook: :whale: Package image name", currentPackageImageHash) Info(pkgTag, " :zap: Building dependency")
compileSpec, err := cs.FromPackage(assertion.Package)
if err != nil {
return nil, errors.Wrap(err, "Error while generating compilespec for "+assertion.Package.GetName())
}
compileSpec.SetOutputPath(p.GetOutputPath())
lastHash = currentPackageImageHash buildImageHash := cs.ImageRepository + ":" + assertion.Hash.BuildHash
if compileSpec.GetImage() != "" { currentPackageImageHash := cs.ImageRepository + ":" + assertion.Hash.PackageHash
// TODO: Refactor this Debug(pkgTag, " :arrow_right_hook: :whale: Builder image from", buildImageHash)
if compileSpec.ImageUnpack() { // If it is just an entire image, create a package from it Debug(pkgTag, " :arrow_right_hook: :whale: Package image name", currentPackageImageHash)
if compileSpec.GetImage() == "" {
return nil, errors.New("No image defined for package: " + assertion.Package.GetName()) lastHash = currentPackageImageHash
if compileSpec.GetImage() != "" {
// TODO: Refactor this
if compileSpec.ImageUnpack() { // If it is just an entire image, create a package from it
if compileSpec.GetImage() == "" {
return nil, errors.New("No image defined for package: " + assertion.Package.HumanReadableString())
}
Info(pkgTag, ":whale: Sourcing package from image", compileSpec.GetImage())
artifact, err := cs.packageFromImage(compileSpec, currentPackageImageHash, keepPermissions, cs.KeepImg, concurrency)
if err != nil {
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString())
}
departifacts = append(departifacts, artifact)
continue
} }
Info(pkgTag, ":whale: Sourcing package from image", compileSpec.GetImage())
artifact, err := cs.packageFromImage(compileSpec, currentPackageImageHash, keepPermissions, cs.KeepImg, concurrency) Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from image")
artifact, err := cs.compileWithImage(compileSpec.GetImage(), buildImageHash, currentPackageImageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().GetName()) return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString())
} }
departifacts = append(departifacts, artifact) departifacts = append(departifacts, artifact)
Info(pkgTag, ":white_check_mark: Done")
continue continue
} }
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().GetFingerPrint()+" from image") Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from tree")
artifact, err := cs.compileWithImage(compileSpec.GetImage(), buildImageHash, currentPackageImageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec) artifact, err := cs.compileWithImage(buildImageHash, "", currentPackageImageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().GetName()) return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString())
// deperrs = append(deperrs, err)
// break // stop at first error
} }
departifacts = append(departifacts, artifact) departifacts = append(departifacts, artifact)
Info(pkgTag, ":white_check_mark: Done") Info(pkgTag, ":collision: Done")
continue
} }
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().GetFingerPrint()+" from tree") } else if len(dependencies) > 0 {
artifact, err := cs.compileWithImage(buildImageHash, "", currentPackageImageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec) lastHash = dependencies[len(dependencies)-1].Hash.PackageHash
}
if !cs.Options.OnlyDeps {
Info(":package:", p.GetPackage().HumanReadableString(), ":cyclone: Building package target from:", lastHash)
artifact, err := cs.compileWithImage(lastHash, "", "", concurrency, keepPermissions, cs.KeepImg, p)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().GetName()) return artifact, err
// deperrs = append(deperrs, err)
// break // stop at first error
} }
departifacts = append(departifacts, artifact) artifact.SetDependencies(departifacts)
Info(pkgTag, ":collision: Done") artifact.SetSourceAssertion(p.GetSourceAssertion())
}
Info(":package:", p.GetPackage().GetName(), ":cyclone: Building package target from:", lastHash)
artifact, err := cs.compileWithImage(lastHash, "", "", concurrency, keepPermissions, cs.KeepImg, p)
if err != nil {
return artifact, err return artifact, err
} else {
return departifacts[len(departifacts)-1], nil
} }
artifact.SetDependencies(departifacts)
artifact.SetSourceAssertion(p.GetSourceAssertion())
return artifact, err
} }
func (cs *LuetCompiler) FromPackage(p pkg.Package) (CompilationSpec, error) { func (cs *LuetCompiler) FromPackage(p pkg.Package) (CompilationSpec, error) {

View File

@@ -49,7 +49,10 @@ type CompilerOptions struct {
Concurrency int Concurrency int
CompressionType CompressionImplementation CompressionType CompressionImplementation
Clean bool Clean bool
KeepImageExport bool
OnlyDeps bool
NoDeps bool
SolverOptions config.LuetSolverOptions SolverOptions config.LuetSolverOptions
} }
@@ -62,6 +65,8 @@ func NewDefaultCompilerOptions() *CompilerOptions {
KeepImg: true, KeepImg: true,
Concurrency: runtime.NumCPU(), Concurrency: runtime.NumCPU(),
Clean: true, Clean: true,
OnlyDeps: false,
NoDeps: false,
} }
} }

60
pkg/helpers/cli.go Normal file
View File

@@ -0,0 +1,60 @@
// Copyright © 2020 Ettore Di Giacinto <mudler@gentoo.org>
// Daniele Rondina <geaaru@sabayonlinux.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 helpers
import (
"fmt"
_gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
pkg "github.com/mudler/luet/pkg/package"
)
func ParsePackageStr(p string) (*pkg.DefaultPackage, error) {
gp, err := _gentoo.ParsePackageStr(p)
if err != nil {
return nil, err
}
if gp.Version == "" {
gp.Version = "0"
gp.Condition = _gentoo.PkgCondGreaterEqual
}
pkgVersion := ""
if gp.VersionBuild != "" {
pkgVersion = fmt.Sprintf("%s%s%s+%s",
pkg.PkgSelectorConditionFromInt(gp.Condition.Int()).String(),
gp.Version,
gp.VersionSuffix,
gp.VersionBuild,
)
} else {
pkgVersion = fmt.Sprintf("%s%s%s",
pkg.PkgSelectorConditionFromInt(gp.Condition.Int()).String(),
gp.Version,
gp.VersionSuffix,
)
}
pack := &pkg.DefaultPackage{
Name: gp.Name,
Category: gp.Category,
Version: pkgVersion,
Uri: make([]string, 0),
}
return pack, nil
}

32
pkg/helpers/sys.go Normal file
View File

@@ -0,0 +1,32 @@
// Copyright © 2020 Ettore Di Giacinto <mudler@gentoo.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 helpers
import (
"os/exec"
"syscall"
"github.com/pkg/errors"
)
// This allows a multi-platform switch in the future
func Exec(cmd string, args []string, env []string) error {
path, err := exec.LookPath(cmd)
if err != nil {
return errors.Wrap(err, "Could not find binary in path: "+cmd)
}
return syscall.Exec(path, args, env)
}

View File

@@ -38,6 +38,9 @@ import (
type LuetInstallerOptions struct { type LuetInstallerOptions struct {
SolverOptions config.LuetSolverOptions SolverOptions config.LuetSolverOptions
Concurrency int Concurrency int
NoDeps bool
OnlyDeps bool
Force bool
} }
type LuetInstaller struct { type LuetInstaller struct {
@@ -115,8 +118,9 @@ func (l *LuetInstaller) Upgrade(s *System) error {
for _, u := range uninstall { for _, u := range uninstall {
err := l.Uninstall(u, s) err := l.Uninstall(u, s)
if err != nil { if err != nil && !l.Options.Force {
Warning("Failed uninstall for ", u.GetFingerPrint()) Error("Failed uninstall for ", u.HumanReadableString())
return errors.Wrap(err, "uninstalling "+u.HumanReadableString())
} }
} }
@@ -161,7 +165,7 @@ func (l *LuetInstaller) Install(cp []pkg.Package, s *System) error {
vers, _ := s.Database.FindPackageVersions(pi) vers, _ := s.Database.FindPackageVersions(pi)
if len(vers) >= 1 { if len(vers) >= 1 {
Warning("Filtering out package " + pi.GetFingerPrint() + ", it has other versions already installed. Uninstall one of them first ") Warning("Filtering out package " + pi.HumanReadableString() + ", it has other versions already installed. Uninstall one of them first ")
continue continue
//return errors.New("Package " + pi.GetFingerPrint() + " has other versions already installed. Uninstall one of them first: " + strings.Join(vers, " ")) //return errors.New("Package " + pi.GetFingerPrint() + " has other versions already installed. Uninstall one of them first: " + strings.Join(vers, " "))
@@ -186,38 +190,50 @@ func (l *LuetInstaller) Install(cp []pkg.Package, s *System) error {
allRepos := pkg.NewInMemoryDatabase(false) allRepos := pkg.NewInMemoryDatabase(false)
syncedRepos.SyncDatabase(allRepos) syncedRepos.SyncDatabase(allRepos)
p = syncedRepos.ResolveSelectors(p) p = syncedRepos.ResolveSelectors(p)
solv := solver.NewResolver(s.Database, allRepos, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
solution, err := solv.Install(p)
if err != nil {
return errors.Wrap(err, "Failed solving solution for package")
}
// Gathers things to install
toInstall := map[string]ArtifactMatch{} toInstall := map[string]ArtifactMatch{}
for _, assertion := range solution { var packagesToInstall []pkg.Package
if assertion.Value {
matches := syncedRepos.PackageMatches([]pkg.Package{assertion.Package})
if len(matches) == 0 {
return errors.New("Failed matching solutions against repository - where are definitions coming from?!")
}
A:
for _, artefact := range matches[0].Repo.GetIndex() {
if artefact.GetCompileSpec().GetPackage() == nil {
return errors.New("Package in compilespec empty")
} var solution solver.PackagesAssertions
if matches[0].Package.Matches(artefact.GetCompileSpec().GetPackage()) {
// Filter out already installed if !l.Options.NoDeps {
if _, err := s.Database.FindPackage(assertion.Package); err != nil { solv := solver.NewResolver(s.Database, allRepos, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
toInstall[assertion.Package.GetFingerPrint()] = ArtifactMatch{Package: assertion.Package, Artifact: artefact, Repository: matches[0].Repo} solution, err = solv.Install(p)
} if err != nil && !l.Options.Force {
break A return errors.Wrap(err, "Failed solving solution for package")
} }
// Gathers things to install
for _, assertion := range solution {
if assertion.Value {
packagesToInstall = append(packagesToInstall, assertion.Package)
} }
} }
} else if !l.Options.OnlyDeps {
for _, currentPack := range p {
packagesToInstall = append(packagesToInstall, currentPack)
}
} }
// Gathers things to install
for _, currentPack := range packagesToInstall {
matches := syncedRepos.PackageMatches([]pkg.Package{currentPack})
if len(matches) == 0 {
return errors.New("Failed matching solutions against repository for " + currentPack.HumanReadableString() + " where are definitions coming from?!")
}
A:
for _, artefact := range matches[0].Repo.GetIndex() {
if artefact.GetCompileSpec().GetPackage() == nil {
return errors.New("Package in compilespec empty")
}
if matches[0].Package.Matches(artefact.GetCompileSpec().GetPackage()) {
// Filter out already installed
if _, err := s.Database.FindPackage(currentPack); err != nil {
toInstall[currentPack.GetFingerPrint()] = ArtifactMatch{Package: currentPack, Artifact: artefact, Repository: matches[0].Repo}
}
break A
}
}
}
// Install packages into rootfs in parallel. // Install packages into rootfs in parallel.
all := make(chan ArtifactMatch) all := make(chan ArtifactMatch)
@@ -242,40 +258,39 @@ func (l *LuetInstaller) Install(cp []pkg.Package, s *System) error {
for _, ass := range ordered { for _, ass := range ordered {
if ass.Value { if ass.Value {
// Annotate to the system that the package was installed // Annotate to the system that the package was installed
// TODO: Annotate also files that belong to the package, somewhere to uninstall
if _, err := s.Database.FindPackage(ass.Package); err == nil { if _, err := s.Database.FindPackage(ass.Package); err == nil {
err := s.Database.UpdatePackage(ass.Package) err := s.Database.UpdatePackage(ass.Package)
if err != nil { if err != nil && !l.Options.Force {
return errors.Wrap(err, "Failed updating package") return errors.Wrap(err, "Failed updating package")
} }
} else { } else {
_, err := s.Database.CreatePackage(ass.Package) _, err := s.Database.CreatePackage(ass.Package)
if err != nil { if err != nil && !l.Options.Force {
return errors.Wrap(err, "Failed creating package") return errors.Wrap(err, "Failed creating package")
} }
} }
installed, ok := toInstall[ass.Package.GetFingerPrint()] installed, ok := toInstall[ass.Package.GetFingerPrint()]
if !ok { if !ok {
return errors.New("Couldn't find ArtifactMatch for " + ass.Package.GetFingerPrint()) return errors.New("Couldn't find ArtifactMatch for " + ass.Package.HumanReadableString())
} }
treePackage, err := installed.Repository.GetTree().GetDatabase().FindPackage(ass.Package) treePackage, err := installed.Repository.GetTree().GetDatabase().FindPackage(ass.Package)
if err != nil { if err != nil {
return errors.Wrap(err, "Error getting package "+ass.Package.GetFingerPrint()) return errors.Wrap(err, "Error getting package "+ass.Package.HumanReadableString())
} }
if helpers.Exists(treePackage.Rel(tree.FinalizerFile)) { if helpers.Exists(treePackage.Rel(tree.FinalizerFile)) {
Info("Executing finalizer for " + ass.Package.GetName()) Info("Executing finalizer for " + ass.Package.HumanReadableString())
finalizerRaw, err := ioutil.ReadFile(treePackage.Rel(tree.FinalizerFile)) finalizerRaw, err := ioutil.ReadFile(treePackage.Rel(tree.FinalizerFile))
if err != nil { if err != nil && !l.Options.Force {
return errors.Wrap(err, "Error reading file "+treePackage.Rel(tree.FinalizerFile)) return errors.Wrap(err, "Error reading file "+treePackage.Rel(tree.FinalizerFile))
} }
if _, exists := executedFinalizer[ass.Package.GetFingerPrint()]; !exists { if _, exists := executedFinalizer[ass.Package.GetFingerPrint()]; !exists {
finalizer, err := NewLuetFinalizerFromYaml(finalizerRaw) finalizer, err := NewLuetFinalizerFromYaml(finalizerRaw)
if err != nil { if err != nil && !l.Options.Force {
return errors.Wrap(err, "Error reading finalizer "+treePackage.Rel(tree.FinalizerFile)) return errors.Wrap(err, "Error reading finalizer "+treePackage.Rel(tree.FinalizerFile))
} }
err = finalizer.RunInstall() err = finalizer.RunInstall()
if err != nil { if err != nil && !l.Options.Force {
return errors.Wrap(err, "Error executing install finalizer "+treePackage.Rel(tree.FinalizerFile)) return errors.Wrap(err, "Error executing install finalizer "+treePackage.Rel(tree.FinalizerFile))
} }
executedFinalizer[ass.Package.GetFingerPrint()] = true executedFinalizer[ass.Package.GetFingerPrint()] = true
@@ -285,7 +300,6 @@ func (l *LuetInstaller) Install(cp []pkg.Package, s *System) error {
} }
} }
return nil return nil
} }
@@ -298,17 +312,17 @@ func (l *LuetInstaller) installPackage(a ArtifactMatch, s *System) error {
} }
err = artifact.Verify() err = artifact.Verify()
if err != nil { if err != nil && !l.Options.Force {
return errors.Wrap(err, "Artifact integrity check failure") return errors.Wrap(err, "Artifact integrity check failure")
} }
files, err := artifact.FileList() files, err := artifact.FileList()
if err != nil { if err != nil && !l.Options.Force {
return errors.Wrap(err, "Could not open package archive") return errors.Wrap(err, "Could not open package archive")
} }
err = artifact.Unpack(s.Target, true) err = artifact.Unpack(s.Target, true)
if err != nil { if err != nil && !l.Options.Force {
return errors.Wrap(err, "Error met while unpacking rootfs") return errors.Wrap(err, "Error met while unpacking rootfs")
} }
@@ -323,11 +337,16 @@ func (l *LuetInstaller) installerWorker(i int, wg *sync.WaitGroup, c <-chan Arti
for p := range c { for p := range c {
// TODO: Keep trace of what was added from the tar, and save it into system // TODO: Keep trace of what was added from the tar, and save it into system
err := l.installPackage(p, s) err := l.installPackage(p, s)
if err != nil { if err != nil && !l.Options.Force {
//TODO: Uninstall, rollback. //TODO: Uninstall, rollback.
Fatal("Failed installing package "+p.Package.GetName(), err.Error()) Fatal("Failed installing package "+p.Package.GetName(), err.Error())
return errors.Wrap(err, "Failed installing package "+p.Package.GetName()) return errors.Wrap(err, "Failed installing package "+p.Package.GetName())
} }
if err == nil {
Info(":package: ", p.Package.HumanReadableString(), "installed")
} else if err != nil && l.Options.Force {
Info(":package: ", p.Package.HumanReadableString(), "installed with failures (force install)")
}
} }
return nil return nil
@@ -364,17 +383,27 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error {
func (l *LuetInstaller) Uninstall(p pkg.Package, s *System) error { func (l *LuetInstaller) Uninstall(p pkg.Package, s *System) error {
// compute uninstall from all world - remove packages in parallel - run uninstall finalizer (in order) - mark the uninstallation in db // compute uninstall from all world - remove packages in parallel - run uninstall finalizer (in order) - mark the uninstallation in db
// Get installed definition // Get installed definition
solv := solver.NewResolver(s.Database, s.Database, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
solution, err := solv.Uninstall(p) if !l.Options.NoDeps {
if err != nil { solv := solver.NewResolver(s.Database, s.Database, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
return errors.Wrap(err, "Uninstall failed") solution, err := solv.Uninstall(p)
} if err != nil && !l.Options.Force {
for _, p := range solution { 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")
Info("Uninstalling", p.GetFingerPrint()) }
for _, p := range solution {
Info("Uninstalling", p.HumanReadableString())
err := l.uninstall(p, s)
if err != nil && !l.Options.Force {
return errors.Wrap(err, "Uninstall failed")
}
}
} else {
Info("Uninstalling", p.HumanReadableString(), "without deps")
err := l.uninstall(p, s) err := l.uninstall(p, s)
if err != nil { if err != nil && !l.Options.Force {
return errors.Wrap(err, "Uninstall failed") return errors.Wrap(err, "Uninstall failed")
} }
Info(":package: ", p.HumanReadableString(), "uninstalled")
} }
return nil return nil

View File

@@ -530,14 +530,21 @@ func (re Repositories) ResolveSelectors(p []pkg.Package) []pkg.Package {
var matches []pkg.Package var matches []pkg.Package
PACKAGE: PACKAGE:
for _, pack := range p { for _, pack := range p {
REPOSITORY:
for _, r := range re { for _, r := range re {
if pack.IsSelector() { if pack.IsSelector() {
c, err := r.GetTree().GetDatabase().FindPackageCandidate(pack) c, err := r.GetTree().GetDatabase().FindPackageCandidate(pack)
// If FindPackageCandidate returns the same package, it means it couldn't find one.
// Skip this repository and keep looking.
if c.String() == pack.String() {
continue REPOSITORY
}
if err == nil { if err == nil {
matches = append(matches, c) matches = append(matches, c)
continue PACKAGE continue PACKAGE
} }
} else { } else {
// If it's not a selector, just append it
matches = append(matches, pack) matches = append(matches, pack)
} }
} }

View File

@@ -17,8 +17,10 @@ package pkg
import ( import (
"bytes" "bytes"
"crypto/md5"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"path/filepath" "path/filepath"
"sort" "sort"
"strings" "strings"
@@ -87,6 +89,8 @@ type Package interface {
SelectorMatchVersion(string) (bool, error) SelectorMatchVersion(string) (bool, error)
String() string String() string
HumanReadableString() string
HashFingerprint() string
} }
type Tree interface { type Tree interface {
@@ -173,6 +177,16 @@ func (p *DefaultPackage) GetFingerPrint() string {
return fmt.Sprintf("%s-%s-%s", p.Name, p.Category, p.Version) return fmt.Sprintf("%s-%s-%s", p.Name, p.Category, p.Version)
} }
func (p *DefaultPackage) HashFingerprint() string {
h := md5.New()
io.WriteString(h, p.GetFingerPrint())
return fmt.Sprintf("%x", h.Sum(nil))
}
func (p *DefaultPackage) HumanReadableString() string {
return fmt.Sprintf("%s/%s-%s", p.Category, p.Name, p.Version)
}
func FromString(s string) Package { func FromString(s string) Package {
var unescaped DefaultPackage var unescaped DefaultPackage

View File

@@ -25,11 +25,18 @@ var _ = Describe("Package", func() {
Context("Encoding/Decoding", func() { Context("Encoding/Decoding", func() {
a := &DefaultPackage{Name: "test", Version: "1", Category: "t"} a := &DefaultPackage{Name: "test", Version: "1", Category: "t"}
a1 := NewPackage("A", "1.0", []*DefaultPackage{}, []*DefaultPackage{})
It("Encodes and decodes correctly", func() { It("Encodes and decodes correctly", func() {
Expect(a.String()).ToNot(Equal("")) Expect(a.String()).ToNot(Equal(""))
p := FromString(a.String()) p := FromString(a.String())
Expect(p).To(Equal(a)) Expect(p).To(Equal(a))
}) })
It("Generates packages fingerprint's hashes", func() {
Expect(a.HashFingerprint()).ToNot(Equal(a1.HashFingerprint()))
Expect(a.HashFingerprint()).To(Equal("c64caa391b79adb598ad98e261aa79a0"))
})
}) })
Context("Simple package", func() { Context("Simple package", func() {

View File

@@ -161,6 +161,35 @@ func ParseVersion(v string) (PkgVersionSelector, error) {
ans.Condition = PkgCondNot ans.Condition = PkgCondNot
} }
// Check if build number is present
buildIdx := strings.Index(v, "+")
buildVersion := ""
if buildIdx > 0 {
// <pre-release> ::= <dot-separated pre-release identifiers>
//
// <dot-separated pre-release identifiers> ::=
// <pre-release identifier> | <pre-release identifier> "."
// <dot-separated pre-release identifiers>
//
// <build> ::= <dot-separated build identifiers>
//
// <dot-separated build identifiers> ::= <build identifier>
// | <build identifier> "." <dot-separated build identifiers>
//
// <pre-release identifier> ::= <alphanumeric identifier>
// | <numeric identifier>
//
// <build identifier> ::= <alphanumeric identifier>
// | <digits>
//
// <alphanumeric identifier> ::= <non-digit>
// | <non-digit> <identifier characters>
// | <identifier characters> <non-digit>
// | <identifier characters> <non-digit> <identifier characters>
buildVersion = v[buildIdx:]
v = v[0:buildIdx]
}
regexPkg := regexp.MustCompile( regexPkg := regexp.MustCompile(
fmt.Sprintf("(%s|%s|%s|%s|%s|%s)((%s|%s|%s|%s|%s|%s|%s)+)*$", fmt.Sprintf("(%s|%s|%s|%s|%s|%s)((%s|%s|%s|%s|%s|%s|%s)+)*$",
// Version regex // Version regex
@@ -216,6 +245,8 @@ func ParseVersion(v string) (PkgVersionSelector, error) {
ans.Condition = PkgCondEqual ans.Condition = PkgCondEqual
} }
ans.Version += buildVersion
// NOTE: Now suffix complex like _alpha_rc1 are not supported. // NOTE: Now suffix complex like _alpha_rc1 are not supported.
return ans, nil return ans, nil
} }

View File

@@ -136,6 +136,61 @@ var _ = Describe("Versions", func() {
}) })
}) })
Context("Versions Parser11 - semver", func() {
v, err := ParseVersion("0.1.0+0")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("0.1.0+0"))
Expect(v.VersionSuffix).Should(Equal(""))
Expect(v.Condition).Should(Equal(c))
})
})
Context("Versions Parser12 - semver", func() {
v, err := ParseVersion(">=0.1.0_alpha+AB")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondGreaterEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("0.1.0+AB"))
Expect(v.VersionSuffix).Should(Equal("_alpha"))
Expect(v.Condition).Should(Equal(c))
})
})
Context("Versions Parser13 - semver", func() {
v, err := ParseVersion(">=0.1.0_alpha+0.1.22")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondGreaterEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("0.1.0+0.1.22"))
Expect(v.VersionSuffix).Should(Equal("_alpha"))
Expect(v.Condition).Should(Equal(c))
})
})
Context("Versions Parser14 - semver", func() {
v, err := ParseVersion(">=0.1.0_alpha+0.1.22")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondGreaterEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("0.1.0+0.1.22"))
Expect(v.VersionSuffix).Should(Equal("_alpha"))
Expect(v.Condition).Should(Equal(c))
})
})
Context("Versions Parser15 - semver", func() {
v, err := ParseVersion("<=0.3.222.4.5+AB")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondLessEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("0.3.222.4.5+AB"))
Expect(v.VersionSuffix).Should(Equal(""))
Expect(v.Condition).Should(Equal(c))
})
})
Context("Selector1", func() { Context("Selector1", func() {
v1, err := ParseVersion(">=0.0.20190406.4.9.172-r1") v1, err := ParseVersion(">=0.0.20190406.4.9.172-r1")
v2, err2 := ParseVersion("1.0.111") v2, err2 := ParseVersion("1.0.111")
@@ -184,6 +239,42 @@ var _ = Describe("Versions", func() {
}) })
}) })
Context("Selector5", func() {
v1, err := ParseVersion(">0.1.0+0.4")
v2, err2 := ParseVersion("0.1.0+0.3")
match, err3 := PackageAdmit(v1, v2)
It("Selector5", func() {
Expect(err).Should(BeNil())
Expect(err2).Should(BeNil())
Expect(err3).Should(BeNil())
Expect(match).Should(Equal(false))
})
})
Context("Selector6", func() {
v1, err := ParseVersion(">=0.1.0+0.4")
v2, err2 := ParseVersion("0.1.0+0.5")
match, err3 := PackageAdmit(v1, v2)
It("Selector6", func() {
Expect(err).Should(BeNil())
Expect(err2).Should(BeNil())
Expect(err3).Should(BeNil())
Expect(match).Should(Equal(true))
})
})
PContext("Selector7", func() {
v1, err := ParseVersion(">0.1.0+0.4")
v2, err2 := ParseVersion("0.1.0+0.5")
match, err3 := PackageAdmit(v1, v2)
It("Selector7", func() {
Expect(err).Should(BeNil())
Expect(err2).Should(BeNil())
Expect(err3).Should(BeNil())
Expect(match).Should(Equal(true))
})
})
Context("Condition Converter 1", func() { Context("Condition Converter 1", func() {
gp, err := gentoo.ParsePackageStr("=layer/build-1.0") gp, err := gentoo.ParsePackageStr("=layer/build-1.0")
var cond gentoo.PackageCond = gentoo.PkgCondEqual var cond gentoo.PackageCond = gentoo.PkgCondEqual

View File

@@ -54,11 +54,17 @@ const (
PkgCondMatchVersion = 8 PkgCondMatchVersion = 8
) )
const (
RegexCatString = `(^[a-z]+[0-9]*[a-z]*[-][a-z]+[0-9]*[a-z]*|^virtual)`
RegexPkgNameString = `([a-z]+[0-9a-zA-Z\-[+]*]*[+]*)`
)
type GentooPackage struct { type GentooPackage struct {
Name string `json:"name",omitempty"` Name string `json:"name",omitempty"`
Category string `json:"category",omitempty"` Category string `json:"category",omitempty"`
Version string `json:"version",omitempty"` Version string `json:"version",omitempty"`
VersionSuffix string `json:"version_suffix",omitempty"` VersionSuffix string `json:"version_suffix",omitempty"`
VersionBuild string `json:"version_build",omitempty"`
Slot string `json:"slot",omitempty"` Slot string `json:"slot",omitempty"`
Condition PackageCond Condition PackageCond
Repository string `json:"repository",omitempty"` Repository string `json:"repository",omitempty"`
@@ -191,14 +197,23 @@ func (p *GentooPackage) Admit(i *GentooPackage) (bool, error) {
fmt.Sprintf("Wrong name for package %s", i.Name)) fmt.Sprintf("Wrong name for package %s", i.Name))
} }
if p.Version != "" { v1s := p.Version
v1, err = version.NewVersion(p.Version) v2s := i.Version
if v1s != "" {
if p.VersionBuild != "" {
v1s = p.Version + "+" + p.VersionBuild
}
v1, err = version.NewVersion(v1s)
if err != nil { if err != nil {
return false, err return false, err
} }
} }
if i.Version != "" { if v2s != "" {
v2, err = version.NewVersion(i.Version) if i.VersionBuild != "" {
v2s = i.Version + "+" + i.VersionBuild
}
v2, err = version.NewVersion(v2s)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -210,7 +225,8 @@ func (p *GentooPackage) Admit(i *GentooPackage) (bool, error) {
} else { } else {
if p.Condition == PkgCondInvalid || p.Condition == PkgCondEqual { if p.Condition == PkgCondInvalid || p.Condition == PkgCondEqual {
// case 1: source-pkg-1.0 and dest-pkg-1.0 or dest-pkg without version // case 1: source-pkg-1.0 and dest-pkg-1.0 or dest-pkg without version
if i.Version != "" && i.Version == p.Version && p.VersionSuffix == i.VersionSuffix { if i.Version != "" && i.Version == p.Version && p.VersionSuffix == i.VersionSuffix &&
p.VersionBuild == i.VersionBuild {
ans = true ans = true
} }
} else if p.Condition == PkgCondAnyRevision { } else if p.Condition == PkgCondAnyRevision {
@@ -270,8 +286,9 @@ func ParsePackageStr(pkg string) (*GentooPackage, error) {
} }
ans := GentooPackage{ ans := GentooPackage{
Slot: "0", Slot: "0",
Condition: PkgCondInvalid, Condition: PkgCondInvalid,
VersionBuild: "",
} }
// Check if pkg string contains inline use flags // Check if pkg string contains inline use flags
@@ -315,6 +332,67 @@ func ParsePackageStr(pkg string) (*GentooPackage, error) {
ans.Condition = PkgCondNot ans.Condition = PkgCondNot
} }
regexVerString := fmt.Sprintf("[-](%s|%s|%s|%s|%s|%s)((%s|%s|%s|%s|%s|%s|%s)+)*",
// Version regex
// 1.1
"[0-9]+[.][0-9]+[a-z]*",
// 1
"[0-9]+[a-z]*",
// 1.1.1
"[0-9]+[.][0-9]+[.][0-9]+[a-z]*",
// 1.1.1.1
"[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[a-z]*",
// 1.1.1.1.1
"[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[a-z]*",
// 1.1.1.1.1.1
"[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[a-z]*",
// suffix
"-r[0-9]+",
"_p[0-9]+",
"_pre[0-9]*",
"_rc[0-9]+",
// handle also rc without number
"_rc",
"_alpha",
"_beta",
)
hasBuild, _ := regexp.MatchString(
fmt.Sprintf("(%s[/]%s%s([[:]{1,2}[0-9a-zA-Z]*]*)*[+])",
RegexCatString, RegexPkgNameString, regexVerString),
pkg,
)
if hasBuild {
// Check if build number is present
buildIdx := strings.LastIndex(pkg, "+")
if buildIdx > 0 {
// <pre-release> ::= <dot-separated pre-release identifiers>
//
// <dot-separated pre-release identifiers> ::=
// <pre-release identifier> | <pre-release identifier> "."
// <dot-separated pre-release identifiers>
//
// <build> ::= <dot-separated build identifiers>
//
// <dot-separated build identifiers> ::= <build identifier>
// | <build identifier> "." <dot-separated build identifiers>
//
// <pre-release identifier> ::= <alphanumeric identifier>
// | <numeric identifier>
//
// <build identifier> ::= <alphanumeric identifier>
// | <digits>
//
// <alphanumeric identifier> ::= <non-digit>
// | <non-digit> <identifier characters>
// | <identifier characters> <non-digit>
// | <identifier characters> <non-digit> <identifier characters>
ans.VersionBuild = pkg[buildIdx+1:]
pkg = pkg[0:buildIdx]
}
}
words := strings.Split(pkg, "/") words := strings.Split(pkg, "/")
if len(words) != 2 { if len(words) != 2 {
return nil, errors.New(fmt.Sprintf("Invalid package string %s", pkg)) return nil, errors.New(fmt.Sprintf("Invalid package string %s", pkg))
@@ -337,31 +415,9 @@ func ParsePackageStr(pkg string) (*GentooPackage, error) {
} }
regexPkg := regexp.MustCompile( regexPkg := regexp.MustCompile(
fmt.Sprintf("[-](%s|%s|%s|%s|%s|%s)((%s|%s|%s|%s|%s|%s|%s)+)*$", fmt.Sprintf("%s$", regexVerString),
// Version regex
// 1.1
"[0-9]+[.][0-9]+[a-z]*",
// 1
"[0-9]+[a-z]*",
// 1.1.1
"[0-9]+[.][0-9]+[.][0-9]+[a-z]*",
// 1.1.1.1
"[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[a-z]*",
// 1.1.1.1.1
"[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[a-z]*",
// 1.1.1.1.1.1
"[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[a-z]*",
// suffix
"-r[0-9]+",
"_p[0-9]+",
"_pre[0-9]*",
"_rc[0-9]+",
// handle also rc without number
"_rc",
"_alpha",
"_beta",
),
) )
matches := regexPkg.FindAllString(pkgname, -1) matches := regexPkg.FindAllString(pkgname, -1)
// NOTE: Now suffix comples like _alpha_rc1 are not supported. // NOTE: Now suffix comples like _alpha_rc1 are not supported.

2
vendor/modules.txt vendored
View File

@@ -23,7 +23,7 @@ github.com/Microsoft/hcsshim/internal/longpath
github.com/Microsoft/hcsshim/internal/safefile github.com/Microsoft/hcsshim/internal/safefile
# github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 # github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5
github.com/Nvveen/Gotty github.com/Nvveen/Gotty
# github.com/Sabayon/pkgs-checker v0.4.2-0.20200101193228-1d500105afb7 # github.com/Sabayon/pkgs-checker v0.5.1-0.20200221202320-073693f2c657
github.com/Sabayon/pkgs-checker/pkg/gentoo github.com/Sabayon/pkgs-checker/pkg/gentoo
# github.com/apex/log v1.1.1 # github.com/apex/log v1.1.1
github.com/apex/log github.com/apex/log