mirror of
https://github.com/mudler/luet.git
synced 2025-09-02 15:54:39 +00:00
Compare commits
64 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3c5e144b8d | ||
|
44aa69928a | ||
|
c7652c8a70 | ||
|
fab2d21ac1 | ||
|
487239334f | ||
|
69477a0c36 | ||
|
67362a3bc1 | ||
|
302d18e749 | ||
|
9047e13d21 | ||
|
0249c0fa4a | ||
|
fc40c770ab | ||
|
4357ee45e9 | ||
|
6ce9a86245 | ||
|
853a1995b4 | ||
|
039b77fdfd | ||
|
050d9b3095 | ||
|
4985ff7b5a | ||
|
6f138811dd | ||
|
f02c54a274 | ||
|
d6182cba3b | ||
|
bc5c0fa0cf | ||
|
dc64dbff75 | ||
|
a94e430a3b | ||
|
93f8f0dd0f | ||
|
7bdcc72dd3 | ||
|
e47c07d438 | ||
|
6fc5d1a97b | ||
|
f4a5a97cff | ||
|
8c972403a3 | ||
|
82a17a1a22 | ||
|
17238d187a | ||
|
ad011e937f | ||
|
25c796c430 | ||
|
df5499393f | ||
|
026ddf6fc9 | ||
|
ec0b83a811 | ||
|
765261f233 | ||
|
6c7e24fadf | ||
|
de23e0d5b1 | ||
|
8572aa5222 | ||
|
0e0c2f21a6 | ||
|
575079bb77 | ||
|
5bcc8d112a | ||
|
65b17f5283 | ||
|
a0618107a8 | ||
|
25f2abf103 | ||
|
e3ebfd6bfe | ||
|
48df98bcae | ||
|
0ce1baa448 | ||
|
07610bc216 | ||
|
a04dadf100 | ||
|
2f4ce42472 | ||
|
def04724d4 | ||
|
38296bc5d7 | ||
|
7e16e0cdb6 | ||
|
647ea35983 | ||
|
4648dedb55 | ||
|
2ce427d601 | ||
|
b01c017507 | ||
|
189c042fea | ||
|
4e675723e8 | ||
|
dd00d491b9 | ||
|
26b94888c3 | ||
|
01e635bd78 |
35
cmd/build.go
35
cmd/build.go
@@ -15,18 +15,17 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/mudler/luet/pkg/compiler"
|
||||
"github.com/mudler/luet/pkg/compiler/backend"
|
||||
. "github.com/mudler/luet/pkg/config"
|
||||
helpers "github.com/mudler/luet/pkg/helpers"
|
||||
. "github.com/mudler/luet/pkg/logger"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
tree "github.com/mudler/luet/pkg/tree"
|
||||
|
||||
_gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
@@ -45,12 +44,16 @@ var buildCmd = &cobra.Command{
|
||||
viper.BindPFlag("revdeps", cmd.Flags().Lookup("revdeps"))
|
||||
viper.BindPFlag("all", cmd.Flags().Lookup("all"))
|
||||
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("push", cmd.Flags().Lookup("push"))
|
||||
viper.BindPFlag("pull", cmd.Flags().Lookup("pull"))
|
||||
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.discount", cmd.Flags().Lookup("solver-discount"))
|
||||
LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate"))
|
||||
@@ -72,6 +75,9 @@ var buildCmd = &cobra.Command{
|
||||
push := viper.GetBool("push")
|
||||
pull := viper.GetBool("pull")
|
||||
keepImages := viper.GetBool("keep-images")
|
||||
nodeps := viper.GetBool("nodeps")
|
||||
onlydeps := viper.GetBool("onlydeps")
|
||||
keepExportedImages := viper.GetBool("keep-exported-images")
|
||||
|
||||
compilerSpecs := compiler.NewLuetCompilationspecs()
|
||||
var compilerBackend compiler.CompilerBackend
|
||||
@@ -126,31 +132,21 @@ var buildCmd = &cobra.Command{
|
||||
opts.PullFirst = pull
|
||||
opts.KeepImg = keepImages
|
||||
opts.Push = push
|
||||
opts.OnlyDeps = onlydeps
|
||||
opts.NoDeps = nodeps
|
||||
opts.KeepImageExport = keepExportedImages
|
||||
|
||||
luetCompiler := compiler.NewLuetCompiler(compilerBackend, generalRecipe.GetDatabase(), opts)
|
||||
luetCompiler.SetConcurrency(concurrency)
|
||||
luetCompiler.SetCompressionType(compiler.CompressionImplementation(compressionType))
|
||||
if !all {
|
||||
for _, a := range args {
|
||||
gp, err := _gentoo.ParsePackageStr(a)
|
||||
|
||||
pack, err := helpers.ParsePackageStr(a)
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
Fatal("Error: " + err.Error())
|
||||
@@ -212,6 +208,9 @@ func init() {
|
||||
buildCmd.Flags().Bool("push", false, "Push images to 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("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().Float32("solver-rate", 0.7, "Solver learning rate")
|
||||
|
@@ -15,17 +15,16 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
installer "github.com/mudler/luet/pkg/installer"
|
||||
|
||||
. "github.com/mudler/luet/pkg/config"
|
||||
helpers "github.com/mudler/luet/pkg/helpers"
|
||||
. "github.com/mudler/luet/pkg/logger"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
|
||||
_gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -39,6 +38,11 @@ var installCmd = &cobra.Command{
|
||||
LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount"))
|
||||
LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate"))
|
||||
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"))
|
||||
LuetCfg.Viper.BindPFlag("download-only", cmd.Flags().Lookup("download-only"))
|
||||
|
||||
},
|
||||
Long: `Install packages in parallel`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
@@ -46,26 +50,10 @@ var installCmd = &cobra.Command{
|
||||
var systemDB pkg.PackageDatabase
|
||||
|
||||
for _, a := range args {
|
||||
gp, err := _gentoo.ParsePackageStr(a)
|
||||
pack, err := helpers.ParsePackageStr(a)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -83,7 +71,10 @@ var installCmd = &cobra.Command{
|
||||
discount := LuetCfg.Viper.GetFloat64("solver.discount")
|
||||
rate := LuetCfg.Viper.GetFloat64("solver.rate")
|
||||
attempts := LuetCfg.Viper.GetInt("solver.max_attempts")
|
||||
|
||||
force := LuetCfg.Viper.GetBool("force")
|
||||
nodeps := LuetCfg.Viper.GetBool("nodeps")
|
||||
onlydeps := LuetCfg.Viper.GetBool("onlydeps")
|
||||
downloadOnly := LuetCfg.Viper.GetBool("download-only")
|
||||
LuetCfg.GetSolverOptions().Type = stype
|
||||
LuetCfg.GetSolverOptions().LearnRate = float32(rate)
|
||||
LuetCfg.GetSolverOptions().Discount = float32(discount)
|
||||
@@ -91,7 +82,14 @@ var installCmd = &cobra.Command{
|
||||
|
||||
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,
|
||||
PreserveSystemEssentialData: true,
|
||||
})
|
||||
inst.Repositories(repos)
|
||||
|
||||
if LuetCfg.GetSystem().DatabaseEngine == "boltdb" {
|
||||
@@ -101,7 +99,7 @@ var installCmd = &cobra.Command{
|
||||
systemDB = pkg.NewInMemoryDatabase(true)
|
||||
}
|
||||
system := &installer.System{Database: systemDB, Target: LuetCfg.GetSystem().Rootfs}
|
||||
err := inst.Install(toInstall, system)
|
||||
err := inst.Install(toInstall, system, downloadOnly)
|
||||
if err != nil {
|
||||
Fatal("Error: " + err.Error())
|
||||
}
|
||||
@@ -119,6 +117,10 @@ func init() {
|
||||
installCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate")
|
||||
installCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate")
|
||||
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)")
|
||||
installCmd.Flags().Bool("download-only", false, "Download dependencies only")
|
||||
|
||||
RootCmd.AddCommand(installCmd)
|
||||
}
|
||||
|
24
cmd/root.go
24
cmd/root.go
@@ -16,6 +16,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
@@ -24,6 +25,7 @@ import (
|
||||
|
||||
"github.com/marcsauter/single"
|
||||
config "github.com/mudler/luet/pkg/config"
|
||||
helpers "github.com/mudler/luet/pkg/helpers"
|
||||
. "github.com/mudler/luet/pkg/logger"
|
||||
repo "github.com/mudler/luet/pkg/repository"
|
||||
|
||||
@@ -35,7 +37,7 @@ var cfgFile string
|
||||
var Verbose bool
|
||||
|
||||
const (
|
||||
LuetCLIVersion = "0.6"
|
||||
LuetCLIVersion = "0.7"
|
||||
LuetEnvPrefix = "LUET"
|
||||
)
|
||||
|
||||
@@ -51,12 +53,13 @@ var RootCmd = &cobra.Command{
|
||||
Fatal("failed to load configuration:", err.Error())
|
||||
}
|
||||
},
|
||||
SilenceErrors: true,
|
||||
}
|
||||
|
||||
func LoadConfig(c *config.LuetConfig) error {
|
||||
// If a config file is found, read it in.
|
||||
if err := c.Viper.ReadInConfig(); err != nil {
|
||||
Warning(err)
|
||||
Debug(err)
|
||||
}
|
||||
|
||||
err := c.Viper.Unmarshal(&config.LuetCfg)
|
||||
@@ -99,8 +102,18 @@ func Execute() {
|
||||
}
|
||||
defer s.TryUnlock()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -109,7 +122,7 @@ func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
pflags := RootCmd.PersistentFlags()
|
||||
pflags.StringVar(&cfgFile, "config", "", "config file (default is $HOME/.luet.yaml)")
|
||||
pflags.BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
|
||||
pflags.BoolP("debug", "d", false, "verbose output")
|
||||
pflags.Bool("fatal", false, "Enables Warnings to exit")
|
||||
|
||||
u, err := user.Current()
|
||||
@@ -124,7 +137,7 @@ func init() {
|
||||
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("verbose"))
|
||||
config.LuetCfg.Viper.BindPFlag("general.debug", pflags.Lookup("debug"))
|
||||
config.LuetCfg.Viper.BindPFlag("general.concurrency", pflags.Lookup("concurrency"))
|
||||
config.LuetCfg.Viper.BindPFlag("general.fatal_warnings", pflags.Lookup("fatal"))
|
||||
}
|
||||
@@ -141,7 +154,6 @@ func initConfig() {
|
||||
viper.SetConfigType("yaml")
|
||||
viper.SetConfigName(".luet") // name of config file (without extension)
|
||||
if cfgFile != "" { // enable ability to specify config file via flag
|
||||
Info(">>> cfgFile: ", cfgFile)
|
||||
viper.SetConfigFile(cfgFile)
|
||||
} else {
|
||||
viper.AddConfigPath(dir)
|
||||
|
@@ -17,7 +17,6 @@ package cmd
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
. "github.com/mudler/luet/pkg/config"
|
||||
installer "github.com/mudler/luet/pkg/installer"
|
||||
@@ -51,6 +50,8 @@ var searchCmd = &cobra.Command{
|
||||
discount := LuetCfg.Viper.GetFloat64("solver.discount")
|
||||
rate := LuetCfg.Viper.GetFloat64("solver.rate")
|
||||
attempts := LuetCfg.Viper.GetInt("solver.max_attempts")
|
||||
searchWithLabel, _ := cmd.Flags().GetBool("by-label")
|
||||
searchWithLabelMatch, _ := cmd.Flags().GetBool("by-label-regex")
|
||||
|
||||
LuetCfg.GetSolverOptions().Type = stype
|
||||
LuetCfg.GetSolverOptions().LearnRate = float32(rate)
|
||||
@@ -70,8 +71,12 @@ var searchCmd = &cobra.Command{
|
||||
repos = append(repos, r)
|
||||
}
|
||||
|
||||
inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{Concurrency: LuetCfg.GetGeneral().Concurrency, SolverOptions: *LuetCfg.GetSolverOptions()})
|
||||
|
||||
inst := installer.NewLuetInstaller(
|
||||
installer.LuetInstallerOptions{
|
||||
Concurrency: LuetCfg.GetGeneral().Concurrency,
|
||||
SolverOptions: *LuetCfg.GetSolverOptions(),
|
||||
},
|
||||
)
|
||||
inst.Repositories(repos)
|
||||
synced, err := inst.SyncRepositories(false)
|
||||
if err != nil {
|
||||
@@ -80,7 +85,14 @@ var searchCmd = &cobra.Command{
|
||||
|
||||
Info("--- Search results: ---")
|
||||
|
||||
matches := synced.Search(args[0])
|
||||
matches := []installer.PackageMatch{}
|
||||
if searchWithLabel {
|
||||
matches = synced.SearchLabel(args[0])
|
||||
} else if searchWithLabelMatch {
|
||||
matches = synced.SearchLabelMatch(args[0])
|
||||
} else {
|
||||
matches = synced.Search(args[0])
|
||||
}
|
||||
for _, m := range matches {
|
||||
Info(":package:", m.Package.GetCategory(), m.Package.GetName(),
|
||||
m.Package.GetVersion(), "repository:", m.Repo.GetName())
|
||||
@@ -94,14 +106,25 @@ var searchCmd = &cobra.Command{
|
||||
systemDB = pkg.NewInMemoryDatabase(true)
|
||||
}
|
||||
system := &installer.System{Database: systemDB, Target: LuetCfg.GetSystem().Rootfs}
|
||||
var term = regexp.MustCompile(args[0])
|
||||
|
||||
for _, k := range system.Database.GetPackages() {
|
||||
pack, err := system.Database.GetPackage(k)
|
||||
if err == nil && term.MatchString(pack.GetName()) {
|
||||
Info(":package:", pack.GetCategory(), pack.GetName(), pack.GetVersion())
|
||||
}
|
||||
var err error
|
||||
iMatches := []pkg.Package{}
|
||||
if searchWithLabel {
|
||||
iMatches, err = system.Database.FindPackageLabel(args[0])
|
||||
} else if searchWithLabelMatch {
|
||||
iMatches, err = system.Database.FindPackageLabelMatch(args[0])
|
||||
} else {
|
||||
iMatches, err = system.Database.FindPackageMatch(args[0])
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
Fatal("Error: " + err.Error())
|
||||
}
|
||||
|
||||
for _, pack := range iMatches {
|
||||
Info(":package:", pack.GetCategory(), pack.GetName(), pack.GetVersion())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
@@ -119,5 +142,7 @@ func init() {
|
||||
searchCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate")
|
||||
searchCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate")
|
||||
searchCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts")
|
||||
searchCmd.Flags().Bool("by-label", false, "Search packages through label")
|
||||
searchCmd.Flags().Bool("by-label-regex", false, "Search packages through label regex")
|
||||
RootCmd.AddCommand(searchCmd)
|
||||
}
|
||||
|
38
cmd/tree.go
Normal file
38
cmd/tree.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
. "github.com/mudler/luet/cmd/tree"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var treeGroupCmd = &cobra.Command{
|
||||
Use: "tree [command] [OPTIONS]",
|
||||
Short: "Tree operations",
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(treeGroupCmd)
|
||||
|
||||
treeGroupCmd.AddCommand(
|
||||
NewTreePkglistCommand(),
|
||||
NewTreeValidateCommand(),
|
||||
NewTreeBumpCommand(),
|
||||
)
|
||||
}
|
67
cmd/tree/bump.go
Normal file
67
cmd/tree/bump.go
Normal file
@@ -0,0 +1,67 @@
|
||||
// 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 cmd_tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
//"os"
|
||||
//"sort"
|
||||
|
||||
. "github.com/mudler/luet/pkg/logger"
|
||||
tree "github.com/mudler/luet/pkg/tree"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewTreeBumpCommand() *cobra.Command {
|
||||
|
||||
var ans = &cobra.Command{
|
||||
Use: "bump [OPTIONS]",
|
||||
Short: "Bump a new package build version.",
|
||||
Args: cobra.OnlyValidArgs,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
df, _ := cmd.Flags().GetString("definition-file")
|
||||
if df == "" {
|
||||
Fatal("Mandatory definition.yaml path missing.")
|
||||
}
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
spec, _ := cmd.Flags().GetString("definition-file")
|
||||
pack, err := tree.ReadDefinitionFile(spec)
|
||||
if err != nil {
|
||||
Fatal(err.Error())
|
||||
}
|
||||
|
||||
// Retrieve version build section with Gentoo parser
|
||||
err = pack.BumpBuildVersion()
|
||||
if err != nil {
|
||||
Fatal("Error on increment build version: " + err.Error())
|
||||
}
|
||||
|
||||
err = tree.WriteDefinitionFile(&pack, spec)
|
||||
if err != nil {
|
||||
Fatal("Error on write definition file: " + err.Error())
|
||||
}
|
||||
|
||||
fmt.Printf("Bumped package %s/%s-%s.\n", pack.Category, pack.Name, pack.Version)
|
||||
},
|
||||
}
|
||||
|
||||
ans.Flags().StringP("definition-file", "f", "", "Path of the definition to bump.")
|
||||
|
||||
return ans
|
||||
}
|
140
cmd/tree/pkglist.go
Normal file
140
cmd/tree/pkglist.go
Normal file
@@ -0,0 +1,140 @@
|
||||
// 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 cmd_tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
//. "github.com/mudler/luet/pkg/config"
|
||||
helpers "github.com/mudler/luet/pkg/helpers"
|
||||
. "github.com/mudler/luet/pkg/logger"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
tree "github.com/mudler/luet/pkg/tree"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func pkgDetail(pkg pkg.Package) string {
|
||||
ans := fmt.Sprintf(`
|
||||
@@ Package: %s/%s-%s
|
||||
Description: %s
|
||||
License: %s`,
|
||||
pkg.GetCategory(), pkg.GetName(), pkg.GetVersion(),
|
||||
pkg.GetDescription(), pkg.GetLicense())
|
||||
|
||||
for idx, u := range pkg.GetURI() {
|
||||
if idx == 0 {
|
||||
ans += fmt.Sprintf(" URLs: %s", u)
|
||||
} else {
|
||||
ans += fmt.Sprintf(" %s", u)
|
||||
}
|
||||
}
|
||||
|
||||
return ans
|
||||
}
|
||||
|
||||
func NewTreePkglistCommand() *cobra.Command {
|
||||
var excludes []string
|
||||
var matches []string
|
||||
|
||||
var ans = &cobra.Command{
|
||||
Use: "pkglist [OPTIONS]",
|
||||
Short: "List of the packages found in tree.",
|
||||
Args: cobra.OnlyValidArgs,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
t, _ := cmd.Flags().GetString("tree")
|
||||
if t == "" {
|
||||
Fatal("Mandatory tree param missing.")
|
||||
}
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
treePath, _ := cmd.Flags().GetString("tree")
|
||||
verbose, _ := cmd.Flags().GetBool("verbose")
|
||||
full, _ := cmd.Flags().GetBool("full")
|
||||
reciper := tree.NewInstallerRecipe(pkg.NewInMemoryDatabase(false))
|
||||
err := reciper.Load(treePath)
|
||||
if err != nil {
|
||||
Fatal("Error on load tree ", err)
|
||||
}
|
||||
|
||||
regExcludes, err := helpers.CreateRegexArray(excludes)
|
||||
if err != nil {
|
||||
Fatal(err.Error())
|
||||
}
|
||||
regMatches, err := helpers.CreateRegexArray(matches)
|
||||
if err != nil {
|
||||
Fatal(err.Error())
|
||||
}
|
||||
|
||||
plist := make([]string, 0)
|
||||
for _, p := range reciper.GetDatabase().World() {
|
||||
pkgstr := ""
|
||||
addPkg := true
|
||||
if full {
|
||||
pkgstr = pkgDetail(p)
|
||||
} else if verbose {
|
||||
pkgstr = fmt.Sprintf("%s/%s-%s", p.GetCategory(), p.GetName(), p.GetVersion())
|
||||
} else {
|
||||
pkgstr = fmt.Sprintf("%s/%s", p.GetCategory(), p.GetName())
|
||||
}
|
||||
|
||||
if len(matches) > 0 {
|
||||
matched := false
|
||||
for _, rgx := range regMatches {
|
||||
if rgx.MatchString(pkgstr) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
addPkg = false
|
||||
}
|
||||
}
|
||||
|
||||
if len(excludes) > 0 && addPkg {
|
||||
for _, rgx := range regExcludes {
|
||||
if rgx.MatchString(pkgstr) {
|
||||
addPkg = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if addPkg {
|
||||
plist = append(plist, pkgstr)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(plist)
|
||||
for _, p := range plist {
|
||||
fmt.Println(p)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
ans.Flags().BoolP("verbose", "v", false, "Add package version")
|
||||
ans.Flags().BoolP("full", "f", false, "Show package detail")
|
||||
ans.Flags().StringP("tree", "t", "", "Path of the tree to use.")
|
||||
ans.Flags().StringSliceVarP(&matches, "matches", "m", []string{},
|
||||
"Include only matched packages from list. (Use string as regex).")
|
||||
ans.Flags().StringSliceVarP(&excludes, "exclude", "e", []string{},
|
||||
"Exclude matched packages from list. (Use string as regex).")
|
||||
|
||||
return ans
|
||||
}
|
212
cmd/tree/validate.go
Normal file
212
cmd/tree/validate.go
Normal file
@@ -0,0 +1,212 @@
|
||||
// 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 cmd_tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
//. "github.com/mudler/luet/pkg/config"
|
||||
helpers "github.com/mudler/luet/pkg/helpers"
|
||||
. "github.com/mudler/luet/pkg/logger"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/luet/pkg/solver"
|
||||
tree "github.com/mudler/luet/pkg/tree"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewTreeValidateCommand() *cobra.Command {
|
||||
var excludes []string
|
||||
var matches []string
|
||||
var treePaths []string
|
||||
|
||||
var ans = &cobra.Command{
|
||||
Use: "validate [OPTIONS]",
|
||||
Short: "Validate a tree or a list of packages",
|
||||
Args: cobra.OnlyValidArgs,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
if len(treePaths) < 1 {
|
||||
Fatal("Mandatory tree param missing.")
|
||||
}
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var depSolver solver.PackageSolver
|
||||
var errstr string
|
||||
|
||||
errors := make([]string, 0)
|
||||
|
||||
brokenPkgs := 0
|
||||
brokenDeps := 0
|
||||
withSolver, _ := cmd.Flags().GetBool("with-solver")
|
||||
|
||||
reciper := tree.NewInstallerRecipe(pkg.NewInMemoryDatabase(false))
|
||||
for _, treePath := range treePaths {
|
||||
err := reciper.Load(treePath)
|
||||
if err != nil {
|
||||
Fatal("Error on load tree ", err)
|
||||
}
|
||||
}
|
||||
|
||||
emptyInstallationDb := pkg.NewInMemoryDatabase(false)
|
||||
if withSolver {
|
||||
depSolver = solver.NewSolver(pkg.NewInMemoryDatabase(false),
|
||||
reciper.GetDatabase(),
|
||||
emptyInstallationDb)
|
||||
}
|
||||
|
||||
regExcludes, err := helpers.CreateRegexArray(excludes)
|
||||
if err != nil {
|
||||
Fatal(err.Error())
|
||||
}
|
||||
regMatches, err := helpers.CreateRegexArray(matches)
|
||||
if err != nil {
|
||||
Fatal(err.Error())
|
||||
}
|
||||
|
||||
for _, p := range reciper.GetDatabase().World() {
|
||||
|
||||
pkgstr := fmt.Sprintf("%s/%s-%s", p.GetCategory(), p.GetName(),
|
||||
p.GetVersion())
|
||||
|
||||
validpkg := true
|
||||
|
||||
if len(matches) > 0 {
|
||||
matched := false
|
||||
for _, rgx := range regMatches {
|
||||
if rgx.MatchString(pkgstr) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if len(excludes) > 0 {
|
||||
excluded := false
|
||||
for _, rgx := range regExcludes {
|
||||
if rgx.MatchString(pkgstr) {
|
||||
excluded = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if excluded {
|
||||
continue
|
||||
}
|
||||
}
|
||||
Info("Checking package "+fmt.Sprintf("%s/%s-%s", p.GetCategory(), p.GetName(), p.GetVersion()), "with", len(p.GetRequires()), "dependencies.")
|
||||
|
||||
for _, r := range p.GetRequires() {
|
||||
|
||||
deps, err := reciper.GetDatabase().FindPackages(
|
||||
&pkg.DefaultPackage{
|
||||
Name: r.GetName(),
|
||||
Category: r.GetCategory(),
|
||||
Version: r.GetVersion(),
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil || len(deps) < 1 {
|
||||
if err != nil {
|
||||
errstr = err.Error()
|
||||
} else {
|
||||
errstr = "No packages"
|
||||
}
|
||||
Error(fmt.Sprintf("%s/%s-%s: Broken Dep %s/%s-%s - %s",
|
||||
p.GetCategory(), p.GetName(), p.GetVersion(),
|
||||
r.GetCategory(), r.GetName(), r.GetVersion(),
|
||||
errstr,
|
||||
))
|
||||
|
||||
errors = append(errors,
|
||||
fmt.Sprintf("%s/%s-%s: Broken Dep %s/%s-%s - %s",
|
||||
p.GetCategory(), p.GetName(), p.GetVersion(),
|
||||
r.GetCategory(), r.GetName(), r.GetVersion(),
|
||||
errstr))
|
||||
|
||||
brokenDeps++
|
||||
|
||||
validpkg = false
|
||||
|
||||
} else {
|
||||
|
||||
Debug("Find packages for dep",
|
||||
fmt.Sprintf("%s/%s-%s", r.GetCategory(), r.GetName(), r.GetVersion()))
|
||||
|
||||
if withSolver {
|
||||
Spinner(32)
|
||||
_, err := depSolver.Install([]pkg.Package{r})
|
||||
SpinnerStop()
|
||||
|
||||
if err != nil {
|
||||
|
||||
Error(fmt.Sprintf("%s/%s-%s: solver broken for dep %s/%s-%s - %s",
|
||||
p.GetCategory(), p.GetName(), p.GetVersion(),
|
||||
r.GetCategory(), r.GetName(), r.GetVersion(),
|
||||
err.Error(),
|
||||
))
|
||||
|
||||
errors = append(errors,
|
||||
fmt.Sprintf("%s/%s-%s: solver broken for Dep %s/%s-%s - %s",
|
||||
p.GetCategory(), p.GetName(), p.GetVersion(),
|
||||
r.GetCategory(), r.GetName(), r.GetVersion(),
|
||||
err.Error()))
|
||||
|
||||
brokenDeps++
|
||||
validpkg = false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if !validpkg {
|
||||
brokenPkgs++
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(errors)
|
||||
for _, e := range errors {
|
||||
fmt.Println(e)
|
||||
}
|
||||
fmt.Println("Broken packages:", brokenPkgs, "(", brokenDeps, "deps ).")
|
||||
|
||||
if brokenPkgs > 0 {
|
||||
os.Exit(1)
|
||||
} else {
|
||||
os.Exit(0)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
ans.Flags().BoolP("with-solver", "s", false,
|
||||
"Enable check of requires also with solver.")
|
||||
ans.Flags().StringSliceVarP(&treePaths, "tree", "t", []string{},
|
||||
"Path of the tree to use.")
|
||||
ans.Flags().StringSliceVarP(&excludes, "exclude", "e", []string{},
|
||||
"Exclude matched packages from analysis. (Use string as regex).")
|
||||
ans.Flags().StringSliceVarP(&matches, "matches", "m", []string{},
|
||||
"Analyze only matched packages. (Use string as regex).")
|
||||
|
||||
return ans
|
||||
}
|
@@ -15,16 +15,15 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/mudler/luet/pkg/config"
|
||||
helpers "github.com/mudler/luet/pkg/helpers"
|
||||
installer "github.com/mudler/luet/pkg/installer"
|
||||
. "github.com/mudler/luet/pkg/logger"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
|
||||
_gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
|
||||
"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.rate", cmd.Flags().Lookup("solver-rate"))
|
||||
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) {
|
||||
var systemDB pkg.PackageDatabase
|
||||
|
||||
for _, a := range args {
|
||||
gp, err := _gentoo.ParsePackageStr(a)
|
||||
|
||||
pack, err := helpers.ParsePackageStr(a)
|
||||
if err != nil {
|
||||
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")
|
||||
discount := LuetCfg.Viper.GetFloat64("solver.discount")
|
||||
rate := LuetCfg.Viper.GetFloat64("solver.rate")
|
||||
attempts := LuetCfg.Viper.GetInt("solver.max_attempts")
|
||||
force := LuetCfg.Viper.GetBool("force")
|
||||
nodeps := LuetCfg.Viper.GetBool("nodeps")
|
||||
|
||||
LuetCfg.GetSolverOptions().Type = stype
|
||||
LuetCfg.GetSolverOptions().LearnRate = float32(rate)
|
||||
@@ -75,7 +65,12 @@ var uninstallCmd = &cobra.Command{
|
||||
|
||||
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" {
|
||||
systemDB = pkg.NewBoltDatabase(
|
||||
@@ -103,5 +98,8 @@ 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("force", false, "Force uninstall")
|
||||
|
||||
RootCmd.AddCommand(uninstallCmd)
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ var upgradeCmd = &cobra.Command{
|
||||
LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount"))
|
||||
LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate"))
|
||||
LuetCfg.Viper.BindPFlag("solver.max_attempts", cmd.Flags().Lookup("solver-attempts"))
|
||||
LuetCfg.Viper.BindPFlag("force", cmd.Flags().Lookup("force"))
|
||||
},
|
||||
Long: `Upgrades packages in parallel`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
@@ -55,6 +56,7 @@ var upgradeCmd = &cobra.Command{
|
||||
discount := LuetCfg.Viper.GetFloat64("solver.discount")
|
||||
rate := LuetCfg.Viper.GetFloat64("solver.rate")
|
||||
attempts := LuetCfg.Viper.GetInt("solver.max_attempts")
|
||||
force := LuetCfg.Viper.GetBool("force")
|
||||
|
||||
LuetCfg.GetSolverOptions().Type = stype
|
||||
LuetCfg.GetSolverOptions().LearnRate = float32(rate)
|
||||
@@ -63,7 +65,11 @@ var upgradeCmd = &cobra.Command{
|
||||
|
||||
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)
|
||||
_, err := inst.SyncRepositories(false)
|
||||
if err != nil {
|
||||
@@ -95,5 +101,7 @@ func init() {
|
||||
upgradeCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate")
|
||||
upgradeCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate")
|
||||
upgradeCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts")
|
||||
upgradeCmd.Flags().Bool("force", false, "Force upgrade by ignoring errors")
|
||||
|
||||
RootCmd.AddCommand(upgradeCmd)
|
||||
}
|
||||
|
5
go.mod
5
go.mod
@@ -4,7 +4,8 @@ go 1.12
|
||||
|
||||
require (
|
||||
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.6.2-0.20200315232328-b6efed54b4b1
|
||||
github.com/asdine/storm v0.0.0-20190418133842-e0f77eada154
|
||||
github.com/briandowns/spinner v1.7.0
|
||||
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/ecooper/qlearning v0.0.0-20160612200101-3075011a69fd
|
||||
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/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3
|
||||
github.com/klauspost/pgzip v1.2.1
|
||||
@@ -20,6 +22,7 @@ require (
|
||||
github.com/logrusorgru/aurora v0.0.0-20190417123914-21d75270181e
|
||||
github.com/marcsauter/single v0.0.0-20181104081128-f8bf46f26ec0
|
||||
github.com/mattn/go-isatty v0.0.10 // indirect
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/mudler/docker-companion v0.4.6-0.20191110154655-b8b364100616
|
||||
github.com/onsi/ginkgo v1.10.1
|
||||
github.com/onsi/gomega v1.7.0
|
||||
|
17
go.sum
17
go.sum
@@ -9,11 +9,24 @@ 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/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA=
|
||||
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/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
|
||||
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/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/Sabayon/pkgs-checker v0.6.1 h1:7HIrrAQujfEQ0+vPjb1Px4AdUY7KWQPn8W0NjKMoGLI=
|
||||
github.com/Sabayon/pkgs-checker v0.6.1/go.mod h1:GFGM6ZzSE5owdGgjLnulj0+Vt9UTd5LFGmB2AOVPYrE=
|
||||
github.com/Sabayon/pkgs-checker v0.6.2-0.20200310081024-935615ba9d27 h1:+5UCxj8bQHrcjuZumsX+E4mvol2F2dW8lXb1K+A/VlM=
|
||||
github.com/Sabayon/pkgs-checker v0.6.2-0.20200310081024-935615ba9d27/go.mod h1:GFGM6ZzSE5owdGgjLnulj0+Vt9UTd5LFGmB2AOVPYrE=
|
||||
github.com/Sabayon/pkgs-checker v0.6.2-0.20200311072754-f4e0aec412f0 h1:C8pSo4uPvXcb5X2ai5oxuABdsOI1mlNNBaw2oxLbzy4=
|
||||
github.com/Sabayon/pkgs-checker v0.6.2-0.20200311072754-f4e0aec412f0/go.mod h1:GFGM6ZzSE5owdGgjLnulj0+Vt9UTd5LFGmB2AOVPYrE=
|
||||
github.com/Sabayon/pkgs-checker v0.6.2-0.20200315232328-b6efed54b4b1 h1:0hkt4Na3ZDZO6e9hCKATOki+zBKOdRa0LxUtYlm9oyE=
|
||||
github.com/Sabayon/pkgs-checker v0.6.2-0.20200315232328-b6efed54b4b1/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/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@@ -91,6 +104,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.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
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.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||
@@ -170,6 +185,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
|
@@ -265,17 +265,12 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
|
||||
}
|
||||
}
|
||||
|
||||
fp := p.GetPackage().HashFingerprint()
|
||||
if buildertaggedImage == "" {
|
||||
buildertaggedImage = cs.ImageRepository + "-" + p.GetPackage().GetFingerPrint() + "-builder"
|
||||
buildertaggedImage = cs.ImageRepository + "-" + fp + "-builder"
|
||||
}
|
||||
if packageImage == "" {
|
||||
packageImage = cs.ImageRepository + "-" + p.GetPackage().GetFingerPrint()
|
||||
}
|
||||
|
||||
if cs.Options.PullFirst {
|
||||
//Best effort pull
|
||||
cs.Backend.DownloadImage(CompilerBackendOptions{ImageName: buildertaggedImage})
|
||||
cs.Backend.DownloadImage(CompilerBackendOptions{ImageName: packageImage})
|
||||
packageImage = cs.ImageRepository + "-" + fp
|
||||
}
|
||||
|
||||
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"),
|
||||
}
|
||||
|
||||
err = cs.Backend.BuildImage(builderOpts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not build image: "+image+" "+builderOpts.DockerFileName)
|
||||
buildBuilderImage := true
|
||||
if cs.Options.PullFirst {
|
||||
if err := cs.Backend.DownloadImage(builderOpts); err == nil {
|
||||
buildBuilderImage = false
|
||||
}
|
||||
}
|
||||
|
||||
err = cs.Backend.ExportImage(builderOpts)
|
||||
if err != nil {
|
||||
if buildBuilderImage {
|
||||
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")
|
||||
}
|
||||
|
||||
if cs.Options.Push {
|
||||
err = cs.Backend.Push(builderOpts)
|
||||
if err != nil {
|
||||
if !cs.Options.KeepImageExport {
|
||||
defer os.Remove(builderOpts.Destination)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -320,14 +325,29 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
|
||||
// return nil, errors.Wrap(err, "Could not export image to tar")
|
||||
// }
|
||||
// } else {
|
||||
if err := cs.Backend.BuildImage(runnerOpts); err != nil {
|
||||
return nil, errors.Wrap(err, "Failed building image for "+runnerOpts.ImageName+" "+runnerOpts.DockerFileName)
|
||||
buildPackageImage := true
|
||||
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 {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not push image: "+image+" "+builderOpts.DockerFileName)
|
||||
@@ -409,85 +429,13 @@ func (cs *LuetCompiler) compileWithImage(image, buildertaggedImage, packageImage
|
||||
return artifact, nil
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) packageFromImage(p CompilationSpec, tag string, keepPermissions, keepImg bool, concurrency int) (Artifact, error) {
|
||||
if !cs.Clean {
|
||||
if art, err := LoadArtifactFromYaml(p); err == nil {
|
||||
Debug("Artifact reloaded. Skipping build")
|
||||
return art, err
|
||||
}
|
||||
}
|
||||
pkgTag := ":package: " + p.GetPackage().GetName()
|
||||
|
||||
Info(pkgTag, " 🍩 Build starts 🔨 🔨 🔨 ")
|
||||
|
||||
builderOpts := CompilerBackendOptions{
|
||||
ImageName: p.GetImage(),
|
||||
Destination: p.Rel(p.GetPackage().GetFingerPrint() + ".image.tar"),
|
||||
}
|
||||
err := cs.Backend.DownloadImage(builderOpts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not download image")
|
||||
}
|
||||
|
||||
if tag != "" {
|
||||
err = cs.Backend.CopyImage(p.GetImage(), tag)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not download image")
|
||||
}
|
||||
}
|
||||
err = cs.Backend.ExportImage(builderOpts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not export image")
|
||||
}
|
||||
|
||||
rootfs, err := ioutil.TempDir(p.GetOutputPath(), "rootfs")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not create tempdir")
|
||||
}
|
||||
defer os.RemoveAll(rootfs) // clean up
|
||||
|
||||
// TODO: Compression and such
|
||||
err = cs.Backend.ExtractRootfs(CompilerBackendOptions{
|
||||
ImageName: p.GetImage(),
|
||||
SourcePath: builderOpts.Destination, Destination: rootfs}, keepPermissions)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not extract rootfs")
|
||||
}
|
||||
artifact := NewPackageArtifact(p.Rel(p.GetPackage().GetFingerPrint() + ".package.tar"))
|
||||
artifact.SetCompileSpec(p)
|
||||
artifact.SetCompressionType(cs.CompressionType)
|
||||
|
||||
err = artifact.Compress(rootfs, concurrency)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error met while creating package archive")
|
||||
}
|
||||
|
||||
if !keepImg {
|
||||
// We keep them around, so to not reload them from the tar (which should be the "correct way") and we automatically share the same layers
|
||||
// TODO: Handle caching and optionally do not remove things
|
||||
err = cs.Backend.RemoveImage(builderOpts)
|
||||
if err != nil {
|
||||
Warning("Could not remove image ", builderOpts.ImageName)
|
||||
// return nil, errors.Wrap(err, "Could not remove image")
|
||||
}
|
||||
}
|
||||
|
||||
Info(pkgTag, " :white_check_mark: Done")
|
||||
|
||||
err = artifact.WriteYaml(p.GetOutputPath())
|
||||
if err != nil {
|
||||
return artifact, err
|
||||
}
|
||||
return artifact, nil
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) ComputeDepTree(p CompilationSpec) (solver.PackagesAssertions, error) {
|
||||
|
||||
s := solver.NewResolver(pkg.NewInMemoryDatabase(false), cs.Database, pkg.NewInMemoryDatabase(false), cs.Options.SolverOptions.Resolver())
|
||||
|
||||
solution, err := s.Install([]pkg.Package{p.GetPackage()})
|
||||
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())
|
||||
@@ -519,21 +467,20 @@ func (cs *LuetCompiler) Compile(keepPermissions bool, p CompilationSpec) (Artifa
|
||||
}
|
||||
|
||||
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() == "" {
|
||||
Error("Package with no deps and no seed image supplied, bailing out")
|
||||
return nil, errors.New("Package " + p.GetPackage().GetFingerPrint() + "with no deps and no seed image supplied, bailing out")
|
||||
}
|
||||
|
||||
targetAssertion := p.GetSourceAssertion().Search(p.GetPackage().GetFingerPrint())
|
||||
targetPackageHash := cs.ImageRepository + ":" + targetAssertion.Hash.PackageHash
|
||||
|
||||
// - If image is set we just generate a plain dockerfile
|
||||
// Treat last case (easier) first. The image is provided and we just compute a plain dockerfile with the images listed as above
|
||||
if p.GetImage() != "" {
|
||||
if p.ImageUnpack() { // If it is just an entire image, create a package from it
|
||||
return cs.packageFromImage(p, "", keepPermissions, cs.KeepImg, concurrency)
|
||||
}
|
||||
|
||||
return cs.compileWithImage(p.GetImage(), "", "", concurrency, keepPermissions, cs.KeepImg, p)
|
||||
return cs.compileWithImage(p.GetImage(), "", targetPackageHash, concurrency, keepPermissions, cs.KeepImg, p)
|
||||
}
|
||||
|
||||
// - If image is not set, we read a base_image. Then we will build one image from it to kick-off our build based
|
||||
@@ -547,74 +494,68 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, p Compila
|
||||
depsN := 0
|
||||
currentN := 0
|
||||
|
||||
Info(":deciduous_tree: Build dependencies for " + p.GetPackage().GetName())
|
||||
for _, assertion := range dependencies { //highly dependent on the order
|
||||
depsN++
|
||||
Info(" :arrow_right_hook:", assertion.Package.GetName(), ":leaves:", assertion.Package.GetVersion(), "(", assertion.Package.GetCategory(), ")")
|
||||
|
||||
}
|
||||
|
||||
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())
|
||||
if !cs.Options.NoDeps {
|
||||
Info(":deciduous_tree: Build dependencies for " + p.GetPackage().HumanReadableString())
|
||||
for _, assertion := range dependencies { //highly dependent on the order
|
||||
depsN++
|
||||
Info(" :arrow_right_hook:", assertion.Package.HumanReadableString(), ":leaves:")
|
||||
}
|
||||
compileSpec.SetOutputPath(p.GetOutputPath())
|
||||
|
||||
buildImageHash := cs.ImageRepository + ":" + assertion.Hash.BuildHash
|
||||
currentPackageImageHash := cs.ImageRepository + ":" + assertion.Hash.PackageHash
|
||||
Debug(pkgTag, " :arrow_right_hook: :whale: Builder image from", buildImageHash)
|
||||
Debug(pkgTag, " :arrow_right_hook: :whale: Package image name", currentPackageImageHash)
|
||||
for _, assertion := range dependencies { //highly dependent on the order
|
||||
currentN++
|
||||
pkgTag := fmt.Sprintf(":package: %d/%d %s ⤑ %s", currentN, depsN, p.GetPackage().HumanReadableString(), assertion.Package.HumanReadableString())
|
||||
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
|
||||
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.GetName())
|
||||
}
|
||||
Info(pkgTag, ":whale: Sourcing package from image", compileSpec.GetImage())
|
||||
artifact, err := cs.packageFromImage(compileSpec, currentPackageImageHash, keepPermissions, cs.KeepImg, concurrency)
|
||||
buildImageHash := cs.ImageRepository + ":" + assertion.Hash.BuildHash
|
||||
currentPackageImageHash := cs.ImageRepository + ":" + assertion.Hash.PackageHash
|
||||
Debug(pkgTag, " :arrow_right_hook: :whale: Builder image from", buildImageHash)
|
||||
Debug(pkgTag, " :arrow_right_hook: :whale: Package image name", currentPackageImageHash)
|
||||
|
||||
lastHash = currentPackageImageHash
|
||||
if compileSpec.GetImage() != "" {
|
||||
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 {
|
||||
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().GetName())
|
||||
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().HumanReadableString())
|
||||
}
|
||||
departifacts = append(departifacts, artifact)
|
||||
Info(pkgTag, ":white_check_mark: Done")
|
||||
continue
|
||||
}
|
||||
|
||||
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().GetFingerPrint()+" from image")
|
||||
artifact, err := cs.compileWithImage(compileSpec.GetImage(), buildImageHash, currentPackageImageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec)
|
||||
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().HumanReadableString()+" from tree")
|
||||
artifact, err := cs.compileWithImage(buildImageHash, "", currentPackageImageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec)
|
||||
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)
|
||||
Info(pkgTag, ":white_check_mark: Done")
|
||||
continue
|
||||
Info(pkgTag, ":collision: Done")
|
||||
}
|
||||
|
||||
Debug(pkgTag, " :wrench: Compiling "+compileSpec.GetPackage().GetFingerPrint()+" from tree")
|
||||
artifact, err := cs.compileWithImage(buildImageHash, "", currentPackageImageHash, concurrency, keepPermissions, cs.KeepImg, compileSpec)
|
||||
} else if len(dependencies) > 0 {
|
||||
lastHash = cs.ImageRepository + ":" + 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, "", targetPackageHash, concurrency, keepPermissions, cs.KeepImg, p)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed compiling "+compileSpec.GetPackage().GetName())
|
||||
// deperrs = append(deperrs, err)
|
||||
// break // stop at first error
|
||||
return artifact, err
|
||||
}
|
||||
departifacts = append(departifacts, artifact)
|
||||
Info(pkgTag, ":collision: Done")
|
||||
}
|
||||
artifact.SetDependencies(departifacts)
|
||||
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
|
||||
} 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) {
|
||||
|
@@ -49,7 +49,10 @@ type CompilerOptions struct {
|
||||
Concurrency int
|
||||
CompressionType CompressionImplementation
|
||||
Clean bool
|
||||
KeepImageExport bool
|
||||
|
||||
OnlyDeps bool
|
||||
NoDeps bool
|
||||
SolverOptions config.LuetSolverOptions
|
||||
}
|
||||
|
||||
@@ -62,6 +65,8 @@ func NewDefaultCompilerOptions() *CompilerOptions {
|
||||
KeepImg: true,
|
||||
Concurrency: runtime.NumCPU(),
|
||||
Clean: true,
|
||||
OnlyDeps: false,
|
||||
NoDeps: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
77
pkg/helpers/cli.go
Normal file
77
pkg/helpers/cli.go
Normal file
@@ -0,0 +1,77 @@
|
||||
// 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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
_gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
)
|
||||
|
||||
func CreateRegexArray(rgx []string) ([]*regexp.Regexp, error) {
|
||||
ans := make([]*regexp.Regexp, len(rgx))
|
||||
if len(rgx) > 0 {
|
||||
for idx, reg := range rgx {
|
||||
re := regexp.MustCompile(reg)
|
||||
if re == nil {
|
||||
return nil, errors.New("Invalid regex " + reg + "!")
|
||||
}
|
||||
ans[idx] = re
|
||||
}
|
||||
}
|
||||
|
||||
return ans, nil
|
||||
}
|
||||
|
||||
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
32
pkg/helpers/sys.go
Normal 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)
|
||||
}
|
@@ -21,6 +21,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
@@ -36,8 +37,12 @@ import (
|
||||
)
|
||||
|
||||
type LuetInstallerOptions struct {
|
||||
SolverOptions config.LuetSolverOptions
|
||||
Concurrency int
|
||||
SolverOptions config.LuetSolverOptions
|
||||
Concurrency int
|
||||
NoDeps bool
|
||||
OnlyDeps bool
|
||||
Force bool
|
||||
PreserveSystemEssentialData bool
|
||||
}
|
||||
|
||||
type LuetInstaller struct {
|
||||
@@ -103,23 +108,15 @@ func (l *LuetInstaller) Upgrade(s *System) error {
|
||||
return err
|
||||
}
|
||||
// First match packages against repositories by priority
|
||||
// matches := syncedRepos.PackageMatches(p)
|
||||
allRepos := pkg.NewInMemoryDatabase(false)
|
||||
syncedRepos.SyncDatabase(allRepos)
|
||||
// compute a "big" world
|
||||
solv := solver.NewResolver(s.Database, allRepos, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
|
||||
uninstall, solution, err := solv.Upgrade()
|
||||
uninstall, solution, err := solv.Upgrade(false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed solving solution for upgrade")
|
||||
}
|
||||
|
||||
for _, u := range uninstall {
|
||||
err := l.Uninstall(u, s)
|
||||
if err != nil {
|
||||
Warning("Failed uninstall for ", u.GetFingerPrint())
|
||||
}
|
||||
}
|
||||
|
||||
toInstall := []pkg.Package{}
|
||||
for _, assertion := range solution {
|
||||
if assertion.Value {
|
||||
@@ -127,7 +124,7 @@ func (l *LuetInstaller) Upgrade(s *System) error {
|
||||
}
|
||||
}
|
||||
|
||||
return l.Install(toInstall, s)
|
||||
return l.swap(syncedRepos, uninstall, toInstall, s)
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) SyncRepositories(inMemory bool) (Repositories, error) {
|
||||
@@ -152,7 +149,62 @@ func (l *LuetInstaller) SyncRepositories(inMemory bool) (Repositories, error) {
|
||||
return syncedRepos, nil
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) Install(cp []pkg.Package, s *System) error {
|
||||
func (l *LuetInstaller) Swap(toRemove []pkg.Package, toInstall []pkg.Package, s *System) error {
|
||||
syncedRepos, err := l.SyncRepositories(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return l.swap(syncedRepos, toRemove, toInstall, s)
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove []pkg.Package, toInstall []pkg.Package, s *System) error {
|
||||
|
||||
// First match packages against repositories by priority
|
||||
allRepos := pkg.NewInMemoryDatabase(false)
|
||||
syncedRepos.SyncDatabase(allRepos)
|
||||
toInstall = syncedRepos.ResolveSelectors(toInstall)
|
||||
|
||||
if err := l.install(syncedRepos, toInstall, s, true); err != nil {
|
||||
return errors.Wrap(err, "Pre-downloading packages")
|
||||
}
|
||||
|
||||
// We don't want any conflict with the installed to raise during the upgrade.
|
||||
// In this way we both force uninstalls and we avoid to check with conflicts
|
||||
// against the current system state which is pending to deletion
|
||||
// E.g. you can't check for conflicts for an upgrade of a new version of A
|
||||
// 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
|
||||
}
|
||||
l.Options.Force = true
|
||||
|
||||
for _, u := range toRemove {
|
||||
Info(":package: Marked for deletion", u.HumanReadableString())
|
||||
|
||||
err := l.Uninstall(u, s)
|
||||
if err != nil && !l.Options.Force {
|
||||
Error("Failed uninstall for ", u.HumanReadableString())
|
||||
return errors.Wrap(err, "uninstalling "+u.HumanReadableString())
|
||||
}
|
||||
|
||||
}
|
||||
l.Options.Force = forced
|
||||
|
||||
return l.install(syncedRepos, toInstall, s, false)
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) Install(cp []pkg.Package, s *System, downloadOnly bool) error {
|
||||
syncedRepos, err := l.SyncRepositories(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return l.install(syncedRepos, cp, s, downloadOnly)
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) install(syncedRepos Repositories, cp []pkg.Package, s *System, downloadOnly bool) error {
|
||||
var p []pkg.Package
|
||||
|
||||
// Check if the package is installed first
|
||||
@@ -161,7 +213,7 @@ func (l *LuetInstaller) Install(cp []pkg.Package, s *System) error {
|
||||
vers, _ := s.Database.FindPackageVersions(pi)
|
||||
|
||||
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
|
||||
//return errors.New("Package " + pi.GetFingerPrint() + " has other versions already installed. Uninstall one of them first: " + strings.Join(vers, " "))
|
||||
|
||||
@@ -175,10 +227,6 @@ func (l *LuetInstaller) Install(cp []pkg.Package, s *System) error {
|
||||
}
|
||||
// First get metas from all repos (and decodes trees)
|
||||
|
||||
syncedRepos, err := l.SyncRepositories(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// First match packages against repositories by priority
|
||||
// matches := syncedRepos.PackageMatches(p)
|
||||
|
||||
@@ -186,111 +234,181 @@ func (l *LuetInstaller) Install(cp []pkg.Package, s *System) error {
|
||||
allRepos := pkg.NewInMemoryDatabase(false)
|
||||
syncedRepos.SyncDatabase(allRepos)
|
||||
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{}
|
||||
for _, assertion := range solution {
|
||||
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 packagesToInstall []pkg.Package
|
||||
var err error
|
||||
var solution solver.PackagesAssertions
|
||||
|
||||
}
|
||||
if matches[0].Package.Matches(artefact.GetCompileSpec().GetPackage()) {
|
||||
// Filter out already installed
|
||||
if _, err := s.Database.FindPackage(assertion.Package); err != nil {
|
||||
toInstall[assertion.Package.GetFingerPrint()] = ArtifactMatch{Package: assertion.Package, Artifact: artefact, Repository: matches[0].Repo}
|
||||
}
|
||||
break A
|
||||
}
|
||||
if !l.Options.NoDeps {
|
||||
solv := solver.NewResolver(s.Database, allRepos, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
|
||||
solution, err = solv.Install(p)
|
||||
if err != nil && !l.Options.Force {
|
||||
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.
|
||||
all := make(chan ArtifactMatch)
|
||||
|
||||
var wg = new(sync.WaitGroup)
|
||||
for i := 0; i < l.Options.Concurrency; i++ {
|
||||
wg.Add(1)
|
||||
go l.installerWorker(i, wg, all, s)
|
||||
|
||||
if !downloadOnly {
|
||||
// Download first
|
||||
for i := 0; i < l.Options.Concurrency; i++ {
|
||||
wg.Add(1)
|
||||
go l.installerWorker(i, wg, all, s, true)
|
||||
}
|
||||
|
||||
for _, c := range toInstall {
|
||||
all <- c
|
||||
}
|
||||
close(all)
|
||||
wg.Wait()
|
||||
|
||||
all = make(chan ArtifactMatch)
|
||||
|
||||
wg = new(sync.WaitGroup)
|
||||
|
||||
// Do the real install
|
||||
for i := 0; i < l.Options.Concurrency; i++ {
|
||||
wg.Add(1)
|
||||
go l.installerWorker(i, wg, all, s, false)
|
||||
}
|
||||
|
||||
for _, c := range toInstall {
|
||||
all <- c
|
||||
}
|
||||
close(all)
|
||||
wg.Wait()
|
||||
} else {
|
||||
for i := 0; i < l.Options.Concurrency; i++ {
|
||||
wg.Add(1)
|
||||
go l.installerWorker(i, wg, all, s, downloadOnly)
|
||||
}
|
||||
|
||||
for _, c := range toInstall {
|
||||
all <- c
|
||||
}
|
||||
close(all)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
if downloadOnly {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, c := range toInstall {
|
||||
all <- c
|
||||
// Annotate to the system that the package was installed
|
||||
_, err := s.Database.CreatePackage(c.Package)
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Failed creating package")
|
||||
}
|
||||
}
|
||||
close(all)
|
||||
wg.Wait()
|
||||
|
||||
executedFinalizer := map[string]bool{}
|
||||
|
||||
// TODO: Lower those errors as warning
|
||||
for _, w := range p {
|
||||
// Finalizers needs to run in order and in sequence.
|
||||
ordered := solution.Order(allRepos, w.GetFingerPrint())
|
||||
for _, ass := range ordered {
|
||||
if ass.Value {
|
||||
// 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 {
|
||||
err := s.Database.UpdatePackage(ass.Package)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed updating package")
|
||||
}
|
||||
} else {
|
||||
_, err := s.Database.CreatePackage(ass.Package)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed creating package")
|
||||
}
|
||||
}
|
||||
installed, ok := toInstall[ass.Package.GetFingerPrint()]
|
||||
if !ok {
|
||||
return errors.New("Couldn't find ArtifactMatch for " + ass.Package.GetFingerPrint())
|
||||
}
|
||||
if !l.Options.NoDeps {
|
||||
// TODO: Lower those errors as warning
|
||||
for _, w := range p {
|
||||
// Finalizers needs to run in order and in sequence.
|
||||
ordered := solution.Order(allRepos, w.GetFingerPrint())
|
||||
ORDER:
|
||||
for _, ass := range ordered {
|
||||
if ass.Value {
|
||||
|
||||
treePackage, err := installed.Repository.GetTree().GetDatabase().FindPackage(ass.Package)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error getting package "+ass.Package.GetFingerPrint())
|
||||
}
|
||||
if helpers.Exists(treePackage.Rel(tree.FinalizerFile)) {
|
||||
Info("Executing finalizer for " + ass.Package.GetName())
|
||||
finalizerRaw, err := ioutil.ReadFile(treePackage.Rel(tree.FinalizerFile))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading file "+treePackage.Rel(tree.FinalizerFile))
|
||||
installed, ok := toInstall[ass.Package.GetFingerPrint()]
|
||||
if !ok {
|
||||
// It was a dep already installed in the system, so we can skip it safely
|
||||
continue ORDER
|
||||
}
|
||||
if _, exists := executedFinalizer[ass.Package.GetFingerPrint()]; !exists {
|
||||
finalizer, err := NewLuetFinalizerFromYaml(finalizerRaw)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading finalizer "+treePackage.Rel(tree.FinalizerFile))
|
||||
|
||||
treePackage, err := installed.Repository.GetTree().GetDatabase().FindPackage(ass.Package)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error getting package "+ass.Package.HumanReadableString())
|
||||
}
|
||||
if helpers.Exists(treePackage.Rel(tree.FinalizerFile)) {
|
||||
Info("Executing finalizer for " + ass.Package.HumanReadableString())
|
||||
finalizerRaw, err := ioutil.ReadFile(treePackage.Rel(tree.FinalizerFile))
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Error reading file "+treePackage.Rel(tree.FinalizerFile))
|
||||
}
|
||||
err = finalizer.RunInstall()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error executing install finalizer "+treePackage.Rel(tree.FinalizerFile))
|
||||
if _, exists := executedFinalizer[ass.Package.GetFingerPrint()]; !exists {
|
||||
finalizer, err := NewLuetFinalizerFromYaml(finalizerRaw)
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Error reading finalizer "+treePackage.Rel(tree.FinalizerFile))
|
||||
}
|
||||
err = finalizer.RunInstall()
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Error executing install finalizer "+treePackage.Rel(tree.FinalizerFile))
|
||||
}
|
||||
executedFinalizer[ass.Package.GetFingerPrint()] = true
|
||||
}
|
||||
executedFinalizer[ass.Package.GetFingerPrint()] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
for _, c := range toInstall {
|
||||
treePackage, err := c.Repository.GetTree().GetDatabase().FindPackage(c.Package)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error getting package "+c.Package.HumanReadableString())
|
||||
}
|
||||
if helpers.Exists(treePackage.Rel(tree.FinalizerFile)) {
|
||||
Info("Executing finalizer for " + c.Package.HumanReadableString())
|
||||
finalizerRaw, err := ioutil.ReadFile(treePackage.Rel(tree.FinalizerFile))
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Error reading file "+treePackage.Rel(tree.FinalizerFile))
|
||||
}
|
||||
if _, exists := executedFinalizer[c.Package.GetFingerPrint()]; !exists {
|
||||
finalizer, err := NewLuetFinalizerFromYaml(finalizerRaw)
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Error reading finalizer "+treePackage.Rel(tree.FinalizerFile))
|
||||
}
|
||||
err = finalizer.RunInstall()
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Error executing install finalizer "+treePackage.Rel(tree.FinalizerFile))
|
||||
}
|
||||
executedFinalizer[c.Package.GetFingerPrint()] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) installPackage(a ArtifactMatch, s *System) error {
|
||||
func (l *LuetInstaller) installPackage(a ArtifactMatch, s *System, downloadOnly bool) error {
|
||||
|
||||
artifact, err := a.Repository.Client().DownloadArtifact(a.Artifact)
|
||||
if err != nil {
|
||||
@@ -298,17 +416,20 @@ func (l *LuetInstaller) installPackage(a ArtifactMatch, s *System) error {
|
||||
}
|
||||
|
||||
err = artifact.Verify()
|
||||
if err != nil {
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Artifact integrity check failure")
|
||||
}
|
||||
if downloadOnly {
|
||||
return nil
|
||||
}
|
||||
|
||||
files, err := artifact.FileList()
|
||||
if err != nil {
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Could not open package archive")
|
||||
}
|
||||
|
||||
err = artifact.Unpack(s.Target, true)
|
||||
if err != nil {
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Error met while unpacking rootfs")
|
||||
}
|
||||
|
||||
@@ -317,17 +438,24 @@ func (l *LuetInstaller) installPackage(a ArtifactMatch, s *System) error {
|
||||
return s.Database.SetPackageFiles(&pkg.PackageFile{PackageFingerprint: a.Package.GetFingerPrint(), Files: files})
|
||||
}
|
||||
|
||||
func (l *LuetInstaller) installerWorker(i int, wg *sync.WaitGroup, c <-chan ArtifactMatch, s *System) error {
|
||||
func (l *LuetInstaller) installerWorker(i int, wg *sync.WaitGroup, c <-chan ArtifactMatch, s *System, downloadOnly bool) error {
|
||||
defer wg.Done()
|
||||
|
||||
for p := range c {
|
||||
// TODO: Keep trace of what was added from the tar, and save it into system
|
||||
err := l.installPackage(p, s)
|
||||
if err != nil {
|
||||
err := l.installPackage(p, s, downloadOnly)
|
||||
if err != nil && !l.Options.Force {
|
||||
//TODO: Uninstall, rollback.
|
||||
Fatal("Failed installing package "+p.Package.GetName(), err.Error())
|
||||
return errors.Wrap(err, "Failed installing package "+p.Package.GetName())
|
||||
}
|
||||
if err == nil && downloadOnly {
|
||||
Info(":package: ", p.Package.HumanReadableString(), "downloaded")
|
||||
} else 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
|
||||
@@ -342,7 +470,15 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error {
|
||||
// Remove from target
|
||||
for _, f := range files {
|
||||
target := filepath.Join(s.Target, f)
|
||||
Info("Removing", target)
|
||||
Debug("Removing", target)
|
||||
|
||||
if l.Options.PreserveSystemEssentialData &&
|
||||
strings.HasPrefix(f, config.LuetCfg.GetSystem().GetSystemPkgsCacheDirPath()) ||
|
||||
strings.HasPrefix(f, config.LuetCfg.GetSystem().GetSystemRepoDatabaseDirPath()) {
|
||||
Warning("Preserve ", f, " which is required by luet ( you have to delete it manually if you really need to)")
|
||||
continue
|
||||
}
|
||||
|
||||
err := os.Remove(target)
|
||||
if err != nil {
|
||||
Warning("Failed removing file (not present in the system target ?)", target)
|
||||
@@ -362,19 +498,34 @@ 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) TODO - mark the uninstallation in db
|
||||
// Get installed definition
|
||||
solv := solver.NewResolver(s.Database, s.Database, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
|
||||
solution, err := solv.Uninstall(p)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Uninstall failed")
|
||||
|
||||
checkConflicts := true
|
||||
if l.Options.Force == true {
|
||||
checkConflicts = false
|
||||
}
|
||||
for _, p := range solution {
|
||||
Info("Uninstalling", p.GetFingerPrint())
|
||||
|
||||
if !l.Options.NoDeps {
|
||||
solv := solver.NewResolver(s.Database, s.Database, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
|
||||
solution, err := solv.Uninstall(p, checkConflicts)
|
||||
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")
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
if err != nil && !l.Options.Force {
|
||||
return errors.Wrap(err, "Uninstall failed")
|
||||
}
|
||||
Info(":package: ", p.HumanReadableString(), "uninstalled")
|
||||
}
|
||||
return nil
|
||||
|
||||
|
@@ -113,7 +113,7 @@ urls:
|
||||
Expect(repo.GetType()).To(Equal("disk"))
|
||||
systemDB := pkg.NewInMemoryDatabase(false)
|
||||
system := &System{Database: systemDB, Target: fakeroot}
|
||||
err = inst.Install([]pkg.Package{&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}}, system)
|
||||
err = inst.Install([]pkg.Package{&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}}, system, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(helpers.Exists(filepath.Join(fakeroot, "test5"))).To(BeTrue())
|
||||
@@ -231,7 +231,7 @@ urls:
|
||||
|
||||
systemDB := pkg.NewBoltDatabase(filepath.Join(bolt, "db.db"))
|
||||
system := &System{Database: systemDB, Target: fakeroot}
|
||||
err = inst.Install([]pkg.Package{&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}}, system)
|
||||
err = inst.Install([]pkg.Package{&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}}, system, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(helpers.Exists(filepath.Join(fakeroot, "test5"))).To(BeTrue())
|
||||
@@ -339,7 +339,7 @@ urls:
|
||||
|
||||
systemDB := pkg.NewBoltDatabase(filepath.Join(bolt, "db.db"))
|
||||
system := &System{Database: systemDB, Target: fakeroot}
|
||||
err = inst.Install([]pkg.Package{&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}}, system)
|
||||
err = inst.Install([]pkg.Package{&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}}, system, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(helpers.Exists(filepath.Join(fakeroot, "test5"))).To(BeTrue())
|
||||
@@ -454,7 +454,7 @@ urls:
|
||||
|
||||
systemDB := pkg.NewBoltDatabase(filepath.Join(bolt, "db.db"))
|
||||
system := &System{Database: systemDB, Target: fakeroot}
|
||||
err = inst.Install([]pkg.Package{&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}}, system)
|
||||
err = inst.Install([]pkg.Package{&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}}, system, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(helpers.Exists(filepath.Join(fakeroot, "test5"))).To(BeTrue())
|
||||
|
@@ -23,11 +23,12 @@ import (
|
||||
)
|
||||
|
||||
type Installer interface {
|
||||
Install([]pkg.Package, *System) error
|
||||
Install([]pkg.Package, *System, bool) error
|
||||
Uninstall(pkg.Package, *System) error
|
||||
Upgrade(s *System) error
|
||||
Repositories([]Repository)
|
||||
SyncRepositories(bool) (Repositories, error)
|
||||
Swap([]pkg.Package, []pkg.Package, *System) error
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
|
@@ -21,7 +21,6 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -69,6 +68,19 @@ type LuetSystemRepositorySerialized struct {
|
||||
TreeChecksums compiler.Checksums `json:"treechecksums"`
|
||||
}
|
||||
|
||||
type LuetSearchModeType string
|
||||
|
||||
const (
|
||||
SLabel LuetSearchModeType = "label"
|
||||
SRegexPkg LuetSearchModeType = "regexPkg"
|
||||
SRegexLabel LuetSearchModeType = "regexLabel"
|
||||
)
|
||||
|
||||
type LuetSearchOpts struct {
|
||||
Pattern string
|
||||
Mode LuetSearchModeType
|
||||
}
|
||||
|
||||
func GenerateRepository(name, descr, t string, urls []string, priority int, src, treeDir string, db pkg.PackageDatabase) (Repository, error) {
|
||||
|
||||
art, err := buildPackageIndex(src)
|
||||
@@ -530,14 +542,21 @@ func (re Repositories) ResolveSelectors(p []pkg.Package) []pkg.Package {
|
||||
var matches []pkg.Package
|
||||
PACKAGE:
|
||||
for _, pack := range p {
|
||||
REPOSITORY:
|
||||
for _, r := range re {
|
||||
if pack.IsSelector() {
|
||||
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 {
|
||||
matches = append(matches, c)
|
||||
continue PACKAGE
|
||||
}
|
||||
} else {
|
||||
// If it's not a selector, just append it
|
||||
matches = append(matches, pack)
|
||||
}
|
||||
}
|
||||
@@ -547,14 +566,24 @@ PACKAGE:
|
||||
|
||||
}
|
||||
|
||||
func (re Repositories) Search(s string) []PackageMatch {
|
||||
func (re Repositories) SearchPackages(p string, o LuetSearchOpts) []PackageMatch {
|
||||
sort.Sort(re)
|
||||
var term = regexp.MustCompile(s)
|
||||
var matches []PackageMatch
|
||||
var err error
|
||||
|
||||
for _, r := range re {
|
||||
for _, pack := range r.GetTree().GetDatabase().World() {
|
||||
if term.MatchString(pack.GetName()) {
|
||||
var repoMatches []pkg.Package
|
||||
if o.Mode == SRegexPkg {
|
||||
repoMatches, err = r.GetTree().GetDatabase().FindPackageMatch(p)
|
||||
|
||||
} else if o.Mode == SLabel {
|
||||
repoMatches, err = r.GetTree().GetDatabase().FindPackageLabel(p)
|
||||
} else if o.Mode == SRegexLabel {
|
||||
repoMatches, err = r.GetTree().GetDatabase().FindPackageLabelMatch(p)
|
||||
}
|
||||
|
||||
if err == nil && len(repoMatches) > 0 {
|
||||
for _, pack := range repoMatches {
|
||||
matches = append(matches, PackageMatch{Package: pack, Repo: r})
|
||||
}
|
||||
}
|
||||
@@ -562,3 +591,15 @@ func (re Repositories) Search(s string) []PackageMatch {
|
||||
|
||||
return matches
|
||||
}
|
||||
|
||||
func (re Repositories) SearchLabelMatch(s string) []PackageMatch {
|
||||
return re.SearchPackages(s, LuetSearchOpts{Pattern: s, Mode: SRegexLabel})
|
||||
}
|
||||
|
||||
func (re Repositories) SearchLabel(s string) []PackageMatch {
|
||||
return re.SearchPackages(s, LuetSearchOpts{Pattern: s, Mode: SLabel})
|
||||
}
|
||||
|
||||
func (re Repositories) Search(s string) []PackageMatch {
|
||||
return re.SearchPackages(s, LuetSearchOpts{Pattern: s, Mode: SRegexPkg})
|
||||
}
|
||||
|
@@ -45,6 +45,9 @@ type PackageSet interface {
|
||||
World() []Package
|
||||
|
||||
FindPackageCandidate(p Package) (Package, error)
|
||||
FindPackageLabel(labelKey string) ([]Package, error)
|
||||
FindPackageLabelMatch(pattern string) ([]Package, error)
|
||||
FindPackageMatch(pattern string) ([]Package, error)
|
||||
}
|
||||
|
||||
type PackageFile struct {
|
||||
|
@@ -18,6 +18,7 @@ package pkg
|
||||
import (
|
||||
"encoding/base64"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -384,3 +385,61 @@ func (db *BoltDatabase) FindPackageVersions(p Package) ([]Package, error) {
|
||||
}
|
||||
return versionsInWorld, nil
|
||||
}
|
||||
|
||||
func (db *BoltDatabase) FindPackageLabel(labelKey string) ([]Package, error) {
|
||||
var ans []Package
|
||||
|
||||
for _, k := range db.GetPackages() {
|
||||
pack, err := db.GetPackage(k)
|
||||
if err != nil {
|
||||
return ans, err
|
||||
}
|
||||
if pack.HasLabel(labelKey) {
|
||||
ans = append(ans, pack)
|
||||
}
|
||||
}
|
||||
return ans, nil
|
||||
}
|
||||
|
||||
func (db *BoltDatabase) FindPackageLabelMatch(pattern string) ([]Package, error) {
|
||||
var ans []Package
|
||||
|
||||
re := regexp.MustCompile(pattern)
|
||||
if re == nil {
|
||||
return nil, errors.New("Invalid regex " + pattern + "!")
|
||||
}
|
||||
|
||||
for _, k := range db.GetPackages() {
|
||||
pack, err := db.GetPackage(k)
|
||||
if err != nil {
|
||||
return ans, err
|
||||
}
|
||||
if pack.MatchLabel(re) {
|
||||
ans = append(ans, pack)
|
||||
}
|
||||
}
|
||||
|
||||
return ans, nil
|
||||
}
|
||||
|
||||
func (db *BoltDatabase) FindPackageMatch(pattern string) ([]Package, error) {
|
||||
var ans []Package
|
||||
|
||||
re := regexp.MustCompile(pattern)
|
||||
if re == nil {
|
||||
return nil, errors.New("Invalid regex " + pattern + "!")
|
||||
}
|
||||
|
||||
for _, k := range db.GetPackages() {
|
||||
pack, err := db.GetPackage(k)
|
||||
if err != nil {
|
||||
return ans, err
|
||||
}
|
||||
|
||||
if re.MatchString(pack.GetCategory() + pack.GetName()) {
|
||||
ans = append(ans, pack)
|
||||
}
|
||||
}
|
||||
|
||||
return ans, nil
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ package pkg
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -358,3 +359,62 @@ func (db *InMemoryDatabase) FindPackageCandidate(p Package) (Package, error) {
|
||||
return required, err
|
||||
|
||||
}
|
||||
|
||||
func (db *InMemoryDatabase) FindPackageLabel(labelKey string) ([]Package, error) {
|
||||
var ans []Package
|
||||
|
||||
for _, k := range db.GetPackages() {
|
||||
pack, err := db.GetPackage(k)
|
||||
if err != nil {
|
||||
return ans, err
|
||||
}
|
||||
if pack.HasLabel(labelKey) {
|
||||
ans = append(ans, pack)
|
||||
}
|
||||
}
|
||||
|
||||
return ans, nil
|
||||
}
|
||||
|
||||
func (db *InMemoryDatabase) FindPackageLabelMatch(pattern string) ([]Package, error) {
|
||||
var ans []Package
|
||||
|
||||
re := regexp.MustCompile(pattern)
|
||||
if re == nil {
|
||||
return nil, errors.New("Invalid regex " + pattern + "!")
|
||||
}
|
||||
|
||||
for _, k := range db.GetPackages() {
|
||||
pack, err := db.GetPackage(k)
|
||||
if err != nil {
|
||||
return ans, err
|
||||
}
|
||||
if pack.MatchLabel(re) {
|
||||
ans = append(ans, pack)
|
||||
}
|
||||
}
|
||||
|
||||
return ans, nil
|
||||
}
|
||||
|
||||
func (db *InMemoryDatabase) FindPackageMatch(pattern string) ([]Package, error) {
|
||||
var ans []Package
|
||||
|
||||
re := regexp.MustCompile(pattern)
|
||||
if re == nil {
|
||||
return nil, errors.New("Invalid regex " + pattern + "!")
|
||||
}
|
||||
|
||||
for _, k := range db.GetPackages() {
|
||||
pack, err := db.GetPackage(k)
|
||||
if err != nil {
|
||||
return ans, err
|
||||
}
|
||||
|
||||
if re.MatchString(pack.GetCategory() + pack.GetName()) {
|
||||
ans = append(ans, pack)
|
||||
}
|
||||
}
|
||||
|
||||
return ans, nil
|
||||
}
|
||||
|
@@ -17,19 +17,22 @@ package pkg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
// . "github.com/mudler/luet/pkg/logger"
|
||||
|
||||
gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
|
||||
"github.com/crillab/gophersat/bf"
|
||||
"github.com/ghodss/yaml"
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/jinzhu/copier"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Package is a package interface (TBD)
|
||||
@@ -45,6 +48,7 @@ type Package interface {
|
||||
Requires([]*DefaultPackage) Package
|
||||
Conflicts([]*DefaultPackage) Package
|
||||
Revdeps(PackageDatabase) []Package
|
||||
LabelDeps(PackageDatabase, string) []Package
|
||||
|
||||
GetProvides() []*DefaultPackage
|
||||
SetProvides([]*DefaultPackage) Package
|
||||
@@ -60,7 +64,7 @@ type Package interface {
|
||||
GetVersion() string
|
||||
RequiresContains(PackageDatabase, Package) (bool, error)
|
||||
Matches(m Package) bool
|
||||
Bigger(m Package) bool
|
||||
BumpBuildVersion() error
|
||||
|
||||
AddUse(use string)
|
||||
RemoveUse(use string)
|
||||
@@ -82,11 +86,18 @@ type Package interface {
|
||||
SetLicense(string)
|
||||
GetLicense() string
|
||||
|
||||
AddLabel(string, string)
|
||||
GetLabels() map[string]string
|
||||
HasLabel(string) bool
|
||||
MatchLabel(*regexp.Regexp) bool
|
||||
|
||||
IsSelector() bool
|
||||
VersionMatchSelector(string) (bool, error)
|
||||
SelectorMatchVersion(string) (bool, error)
|
||||
|
||||
String() string
|
||||
HumanReadableString() string
|
||||
HashFingerprint() string
|
||||
}
|
||||
|
||||
type Tree interface {
|
||||
@@ -146,9 +157,11 @@ type DefaultPackage struct {
|
||||
// Path is set only internally when tree is loaded from disk
|
||||
Path string `json:"path,omitempty"`
|
||||
|
||||
Description string `json:"description"`
|
||||
Uri []string `json:"uri"`
|
||||
License string `json:"license"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Uri []string `json:"uri,omitempty"`
|
||||
License string `json:"license,omitempty"`
|
||||
|
||||
Labels map[string]string `json:labels,omitempty`
|
||||
}
|
||||
|
||||
// State represent the package state
|
||||
@@ -156,7 +169,13 @@ type State string
|
||||
|
||||
// NewPackage returns a new package
|
||||
func NewPackage(name, version string, requires []*DefaultPackage, conflicts []*DefaultPackage) *DefaultPackage {
|
||||
return &DefaultPackage{Name: name, Version: version, PackageRequires: requires, PackageConflicts: conflicts}
|
||||
return &DefaultPackage{
|
||||
Name: name,
|
||||
Version: version,
|
||||
PackageRequires: requires,
|
||||
PackageConflicts: conflicts,
|
||||
Labels: make(map[string]string, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) String() string {
|
||||
@@ -173,6 +192,16 @@ func (p *DefaultPackage) GetFingerPrint() string {
|
||||
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 {
|
||||
var unescaped DefaultPackage
|
||||
|
||||
@@ -204,6 +233,28 @@ func (p *DefaultPackage) IsSelector() bool {
|
||||
return strings.ContainsAny(p.GetVersion(), "<>=")
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) HasLabel(label string) bool {
|
||||
ans := false
|
||||
for k, _ := range p.Labels {
|
||||
if k == label {
|
||||
ans = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return ans
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) MatchLabel(r *regexp.Regexp) bool {
|
||||
ans := false
|
||||
for k, v := range p.Labels {
|
||||
if r.MatchString(k + "=" + v) {
|
||||
ans = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return ans
|
||||
}
|
||||
|
||||
// AddUse adds a use to a package
|
||||
func (p *DefaultPackage) AddUse(use string) {
|
||||
for _, v := range p.UseFlags {
|
||||
@@ -288,6 +339,12 @@ func (p *DefaultPackage) SetCategory(s string) {
|
||||
func (p *DefaultPackage) GetUses() []string {
|
||||
return p.UseFlags
|
||||
}
|
||||
func (p *DefaultPackage) AddLabel(k, v string) {
|
||||
p.Labels[k] = v
|
||||
}
|
||||
func (p *DefaultPackage) GetLabels() map[string]string {
|
||||
return p.Labels
|
||||
}
|
||||
func (p *DefaultPackage) GetProvides() []*DefaultPackage {
|
||||
return p.Provides
|
||||
}
|
||||
@@ -320,13 +377,6 @@ func (p *DefaultPackage) Matches(m Package) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (p *DefaultPackage) Bigger(m Package) bool {
|
||||
low := Lower([]Package{p, m})
|
||||
if low.Matches(m) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) Expand(definitiondb PackageDatabase) ([]Package, error) {
|
||||
var versionsInWorld []Package
|
||||
@@ -365,6 +415,19 @@ func (p *DefaultPackage) Revdeps(definitiondb PackageDatabase) []Package {
|
||||
return versionsInWorld
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) LabelDeps(definitiondb PackageDatabase, labelKey string) []Package {
|
||||
var pkgsWithLabelInWorld []Package
|
||||
// TODO: check if integrate some index to improve
|
||||
// research instead of iterate all list.
|
||||
for _, w := range definitiondb.World() {
|
||||
if w.HasLabel(labelKey) {
|
||||
pkgsWithLabelInWorld = append(pkgsWithLabelInWorld, w)
|
||||
}
|
||||
}
|
||||
|
||||
return pkgsWithLabelInWorld
|
||||
}
|
||||
|
||||
func DecodePackage(ID string, db PackageDatabase) (Package, error) {
|
||||
return db.GetPackage(ID)
|
||||
}
|
||||
@@ -394,29 +457,7 @@ func (pack *DefaultPackage) RequiresContains(definitiondb PackageDatabase, s Pac
|
||||
|
||||
return false, nil
|
||||
}
|
||||
func Lower(set []Package) Package {
|
||||
var versionsMap map[string]Package = make(map[string]Package)
|
||||
if len(set) == 0 {
|
||||
panic("Best needs a list with elements")
|
||||
}
|
||||
|
||||
versionsRaw := []string{}
|
||||
for _, p := range set {
|
||||
versionsRaw = append(versionsRaw, p.GetVersion())
|
||||
versionsMap[p.GetVersion()] = p
|
||||
}
|
||||
|
||||
versions := make([]*version.Version, len(versionsRaw))
|
||||
for i, raw := range versionsRaw {
|
||||
v, _ := version.NewVersion(raw)
|
||||
versions[i] = v
|
||||
}
|
||||
|
||||
// After this, the versions are properly sorted
|
||||
sort.Sort(version.Collection(versions))
|
||||
|
||||
return versionsMap[versions[0].Original()]
|
||||
}
|
||||
func Best(set []Package) Package {
|
||||
var versionsMap map[string]Package = make(map[string]Package)
|
||||
if len(set) == 0 {
|
||||
@@ -454,6 +495,22 @@ func (pack *DefaultPackage) BuildFormula(definitiondb PackageDatabase, db Packag
|
||||
A := bf.Var(encodedA)
|
||||
|
||||
var formulas []bf.Formula
|
||||
|
||||
// Do conflict with other packages versions (if A is selected, then conflict with other versions of A)
|
||||
packages, _ := definitiondb.FindPackageVersions(p)
|
||||
if len(packages) > 0 {
|
||||
for _, cp := range packages {
|
||||
encodedB, err := cp.Encode(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
B := bf.Var(encodedB)
|
||||
if !p.Matches(cp) {
|
||||
formulas = append(formulas, bf.Or(bf.Not(A), bf.Or(bf.Not(A), bf.Not(B))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, requiredDef := range p.GetRequires() {
|
||||
required, err := definitiondb.FindPackage(requiredDef)
|
||||
if err != nil || requiredDef.IsSelector() {
|
||||
@@ -465,62 +522,60 @@ func (pack *DefaultPackage) BuildFormula(definitiondb PackageDatabase, db Packag
|
||||
if err != nil || len(packages) == 0 {
|
||||
required = requiredDef
|
||||
} else {
|
||||
if len(packages) == 1 {
|
||||
required = packages[0]
|
||||
} else {
|
||||
var ALO, priorityConstraints, priorityALO []bf.Formula
|
||||
|
||||
// Try to prio best match
|
||||
// Force the solver to consider first our candidate (if does exists).
|
||||
// Then builds ALO and AMO for the requires.
|
||||
c, candidateErr := definitiondb.FindPackageCandidate(requiredDef)
|
||||
var C bf.Formula
|
||||
if candidateErr == nil {
|
||||
// We have a desired candidate, try to look a solution with that included first
|
||||
for _, o := range packages {
|
||||
encodedB, err := o.Encode(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
B := bf.Var(encodedB)
|
||||
if !o.Matches(c) {
|
||||
priorityConstraints = append(priorityConstraints, bf.Not(B))
|
||||
priorityALO = append(priorityALO, B)
|
||||
}
|
||||
}
|
||||
encodedC, err := c.Encode(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
C = bf.Var(encodedC)
|
||||
// Or the Candidate is true, or all the others might be not true
|
||||
// This forces the CDCL sat implementation to look first at a solution with C=true
|
||||
formulas = append(formulas, bf.Or(bf.Or(C, bf.Or(priorityConstraints...)), bf.Or(bf.Not(C), bf.Or(priorityALO...))))
|
||||
}
|
||||
var ALO, priorityConstraints, priorityALO []bf.Formula
|
||||
|
||||
// AMO - At most one
|
||||
// Try to prio best match
|
||||
// Force the solver to consider first our candidate (if does exists).
|
||||
// Then builds ALO and AMO for the requires.
|
||||
c, candidateErr := definitiondb.FindPackageCandidate(requiredDef)
|
||||
var C bf.Formula
|
||||
if candidateErr == nil {
|
||||
// We have a desired candidate, try to look a solution with that included first
|
||||
for _, o := range packages {
|
||||
encodedB, err := o.Encode(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
B := bf.Var(encodedB)
|
||||
ALO = append(ALO, B)
|
||||
for _, i := range packages {
|
||||
encodedI, err := i.Encode(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
I := bf.Var(encodedI)
|
||||
if !o.Matches(i) {
|
||||
formulas = append(formulas, bf.Or(bf.Not(I), bf.Not(B)))
|
||||
}
|
||||
if !o.Matches(c) {
|
||||
priorityConstraints = append(priorityConstraints, bf.Not(B))
|
||||
priorityALO = append(priorityALO, B)
|
||||
}
|
||||
}
|
||||
formulas = append(formulas, bf.Or(ALO...)) // ALO - At least one
|
||||
continue
|
||||
encodedC, err := c.Encode(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
C = bf.Var(encodedC)
|
||||
// Or the Candidate is true, or all the others might be not true
|
||||
// This forces the CDCL sat implementation to look first at a solution with C=true
|
||||
formulas = append(formulas, bf.Or(bf.Not(A), bf.Or(bf.Or(C, bf.Or(priorityConstraints...)), bf.Or(bf.Not(C), bf.Or(priorityALO...)))))
|
||||
}
|
||||
|
||||
// AMO - At most one
|
||||
for _, o := range packages {
|
||||
encodedB, err := o.Encode(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
B := bf.Var(encodedB)
|
||||
ALO = append(ALO, B)
|
||||
for _, i := range packages {
|
||||
encodedI, err := i.Encode(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
I := bf.Var(encodedI)
|
||||
if !o.Matches(i) {
|
||||
formulas = append(formulas, bf.Or(bf.Not(A), bf.Or(bf.Not(I), bf.Not(B))))
|
||||
}
|
||||
}
|
||||
}
|
||||
formulas = append(formulas, bf.Or(bf.Not(A), bf.Or(ALO...))) // ALO - At least one
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
encodedB, err := required.Encode(db)
|
||||
@@ -586,6 +641,7 @@ func (pack *DefaultPackage) BuildFormula(definitiondb PackageDatabase, db Packag
|
||||
formulas = append(formulas, f...)
|
||||
|
||||
}
|
||||
|
||||
return formulas, nil
|
||||
}
|
||||
|
||||
@@ -608,3 +664,89 @@ func (p *DefaultPackage) Explain() {
|
||||
fmt.Println("====================")
|
||||
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) BumpBuildVersion() error {
|
||||
cat := p.Category
|
||||
if cat == "" {
|
||||
// Use fake category for parse package
|
||||
cat = "app"
|
||||
}
|
||||
gp, err := gentoo.ParsePackageStr(
|
||||
fmt.Sprintf("%s/%s-%s", cat,
|
||||
p.Name, p.GetVersion()))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error on parser version")
|
||||
}
|
||||
|
||||
buildPrefix := ""
|
||||
buildId := 0
|
||||
|
||||
if gp.VersionBuild != "" {
|
||||
// Check if version build is a number
|
||||
buildId, err = strconv.Atoi(gp.VersionBuild)
|
||||
if err == nil {
|
||||
goto end
|
||||
}
|
||||
// POST: is not only a number
|
||||
|
||||
// TODO: check if there is a better way to handle all use cases.
|
||||
|
||||
r1 := regexp.MustCompile(`^r[0-9]*$`)
|
||||
if r1 == nil {
|
||||
return errors.New("Error on create regex for -r[0-9]")
|
||||
}
|
||||
if r1.MatchString(gp.VersionBuild) {
|
||||
buildId, err = strconv.Atoi(strings.ReplaceAll(gp.VersionBuild, "r", ""))
|
||||
if err == nil {
|
||||
buildPrefix = "r"
|
||||
goto end
|
||||
}
|
||||
}
|
||||
|
||||
p1 := regexp.MustCompile(`^p[0-9]*$`)
|
||||
if p1 == nil {
|
||||
return errors.New("Error on create regex for -p[0-9]")
|
||||
}
|
||||
if p1.MatchString(gp.VersionBuild) {
|
||||
buildId, err = strconv.Atoi(strings.ReplaceAll(gp.VersionBuild, "p", ""))
|
||||
if err == nil {
|
||||
buildPrefix = "p"
|
||||
goto end
|
||||
}
|
||||
}
|
||||
|
||||
rc1 := regexp.MustCompile(`^rc[0-9]*$`)
|
||||
if rc1 == nil {
|
||||
return errors.New("Error on create regex for -rc[0-9]")
|
||||
}
|
||||
if rc1.MatchString(gp.VersionBuild) {
|
||||
buildId, err = strconv.Atoi(strings.ReplaceAll(gp.VersionBuild, "rc", ""))
|
||||
if err == nil {
|
||||
buildPrefix = "rc"
|
||||
goto end
|
||||
}
|
||||
}
|
||||
|
||||
// Check if version build contains a dot
|
||||
dotIdx := strings.LastIndex(gp.VersionBuild, ".")
|
||||
if dotIdx > 0 {
|
||||
buildPrefix = gp.VersionBuild[0 : dotIdx+1]
|
||||
bVersion := gp.VersionBuild[dotIdx+1:]
|
||||
buildId, err = strconv.Atoi(bVersion)
|
||||
if err == nil {
|
||||
goto end
|
||||
}
|
||||
}
|
||||
|
||||
buildPrefix = gp.VersionBuild + "."
|
||||
buildId = 0
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
buildId++
|
||||
p.Version = fmt.Sprintf("%s%s+%s%d",
|
||||
gp.Version, gp.VersionSuffix, buildPrefix, buildId)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -16,6 +16,8 @@
|
||||
package pkg_test
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
. "github.com/mudler/luet/pkg/package"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -25,11 +27,18 @@ var _ = Describe("Package", func() {
|
||||
|
||||
Context("Encoding/Decoding", func() {
|
||||
a := &DefaultPackage{Name: "test", Version: "1", Category: "t"}
|
||||
a1 := NewPackage("A", "1.0", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
|
||||
It("Encodes and decodes correctly", func() {
|
||||
Expect(a.String()).ToNot(Equal(""))
|
||||
p := FromString(a.String())
|
||||
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() {
|
||||
@@ -54,6 +63,34 @@ var _ = Describe("Package", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Context("Find label on packages", func() {
|
||||
a := NewPackage("A", ">=1.0", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
a.AddLabel("project1", "test1")
|
||||
a.AddLabel("label2", "value1")
|
||||
b := NewPackage("B", "1.0", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
b.AddLabel("project2", "test2")
|
||||
b.AddLabel("label2", "value1")
|
||||
It("Expands correctly", func() {
|
||||
var err error
|
||||
definitions := NewInMemoryDatabase(false)
|
||||
for _, p := range []Package{a, b} {
|
||||
_, err = definitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
re := regexp.MustCompile("project[0-9][=].*")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(re).ToNot(BeNil())
|
||||
Expect(a.HasLabel("label2")).To(Equal(true))
|
||||
Expect(a.HasLabel("label3")).To(Equal(false))
|
||||
Expect(a.HasLabel("project1")).To(Equal(true))
|
||||
Expect(b.HasLabel("project2")).To(Equal(true))
|
||||
Expect(b.HasLabel("label2")).To(Equal(true))
|
||||
Expect(b.MatchLabel(re)).To(Equal(true))
|
||||
Expect(a.MatchLabel(re)).To(Equal(true))
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Context("Check description", func() {
|
||||
a := NewPackage("A", ">=1.0", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
a.SetDescription("Description A")
|
||||
@@ -204,7 +241,7 @@ var _ = Describe("Package", func() {
|
||||
|
||||
f, err := a1.BuildFormula(definitions, db)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(f)).To(Equal(2))
|
||||
Expect(len(f)).To(Equal(8))
|
||||
// Expect(f[0].String()).To(Equal("or(not(c31f5842), a4910f77)"))
|
||||
// Expect(f[1].String()).To(Equal("or(not(c31f5842), not(a97670be))"))
|
||||
})
|
||||
@@ -245,4 +282,69 @@ var _ = Describe("Package", func() {
|
||||
Expect(len(a1.GetUses())).To(Equal(0))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Check Bump build Version", func() {
|
||||
It("Bump without build version", func() {
|
||||
a1 := NewPackage("A", "1.0", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
err := a1.BumpBuildVersion()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(a1.GetVersion()).To(Equal("1.0+1"))
|
||||
})
|
||||
It("Bump 2", func() {
|
||||
p := NewPackage("A", "1.0+1", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
err := p.BumpBuildVersion()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.GetVersion()).To(Equal("1.0+2"))
|
||||
})
|
||||
|
||||
It("Bump 3", func() {
|
||||
p := NewPackage("A", "1.0+100", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
err := p.BumpBuildVersion()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.GetVersion()).To(Equal("1.0+101"))
|
||||
})
|
||||
|
||||
It("Bump 4", func() {
|
||||
p := NewPackage("A", "1.0+r1", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
err := p.BumpBuildVersion()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.GetVersion()).To(Equal("1.0+r2"))
|
||||
})
|
||||
|
||||
It("Bump 5", func() {
|
||||
p := NewPackage("A", "1.0+p1", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
err := p.BumpBuildVersion()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.GetVersion()).To(Equal("1.0+p2"))
|
||||
})
|
||||
|
||||
It("Bump 6", func() {
|
||||
p := NewPackage("A", "1.0+pre20200315", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
err := p.BumpBuildVersion()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.GetVersion()).To(Equal("1.0+pre20200315.1"))
|
||||
})
|
||||
|
||||
It("Bump 7", func() {
|
||||
p := NewPackage("A", "1.0+pre20200315.1", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
err := p.BumpBuildVersion()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.GetVersion()).To(Equal("1.0+pre20200315.2"))
|
||||
})
|
||||
|
||||
It("Bump 8", func() {
|
||||
p := NewPackage("A", "1.0+d-r1", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
err := p.BumpBuildVersion()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.GetVersion()).To(Equal("1.0+d-r1.1"))
|
||||
})
|
||||
|
||||
It("Bump 9", func() {
|
||||
p := NewPackage("A", "1.0+p20200315.1", []*DefaultPackage{}, []*DefaultPackage{})
|
||||
err := p.BumpBuildVersion()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p.GetVersion()).To(Equal("1.0+p20200315.2"))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
@@ -161,6 +161,35 @@ func ParseVersion(v string) (PkgVersionSelector, error) {
|
||||
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(
|
||||
fmt.Sprintf("(%s|%s|%s|%s|%s|%s)((%s|%s|%s|%s|%s|%s|%s)+)*$",
|
||||
// Version regex
|
||||
@@ -216,6 +245,8 @@ func ParseVersion(v string) (PkgVersionSelector, error) {
|
||||
ans.Condition = PkgCondEqual
|
||||
}
|
||||
|
||||
ans.Version += buildVersion
|
||||
|
||||
// NOTE: Now suffix complex like _alpha_rc1 are not supported.
|
||||
return ans, nil
|
||||
}
|
||||
@@ -225,15 +256,20 @@ func PackageAdmit(selector, i PkgVersionSelector) (bool, error) {
|
||||
var v2 *version.Version = nil
|
||||
var ans bool
|
||||
var err error
|
||||
var sanitizedSelectorVersion, sanitizedIVersion string
|
||||
|
||||
if selector.Version != "" {
|
||||
v1, err = version.NewVersion(selector.Version)
|
||||
// TODO: This is temporary!. I promise it.
|
||||
sanitizedSelectorVersion = strings.ReplaceAll(selector.Version, "_", "-")
|
||||
|
||||
v1, err = version.NewVersion(sanitizedSelectorVersion)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
if i.Version != "" {
|
||||
v2, err = version.NewVersion(i.Version)
|
||||
sanitizedIVersion = strings.ReplaceAll(i.Version, "_", "-")
|
||||
v2, err = version.NewVersion(sanitizedIVersion)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -259,7 +295,7 @@ func PackageAdmit(selector, i PkgVersionSelector) (bool, error) {
|
||||
// TODO: case of 7.3* where 7.30 is accepted.
|
||||
if v1 != nil && v2 != nil {
|
||||
segments := v1.Segments()
|
||||
n := strings.Count(selector.Version, ".")
|
||||
n := strings.Count(sanitizedIVersion, ".")
|
||||
switch n {
|
||||
case 0:
|
||||
segments[0]++
|
||||
@@ -272,7 +308,7 @@ func PackageAdmit(selector, i PkgVersionSelector) (bool, error) {
|
||||
}
|
||||
nextVersion := strings.Trim(strings.Replace(fmt.Sprint(segments), " ", ".", -1), "[]")
|
||||
constraints, err := version.NewConstraint(
|
||||
fmt.Sprintf(">= %s, < %s", selector.Version, nextVersion),
|
||||
fmt.Sprintf(">= %s, < %s", sanitizedSelectorVersion, nextVersion),
|
||||
)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
@@ -136,6 +136,72 @@ 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("Versions Parser16 - semver", func() {
|
||||
v, err := ParseVersion("<=1.0.29+pre2_p20191024")
|
||||
It("ParseVersion10", func() {
|
||||
var c PkgSelectorCondition = PkgCondLessEqual
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal("1.0.29+pre2_p20191024"))
|
||||
Expect(v.VersionSuffix).Should(Equal(""))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Selector1", func() {
|
||||
v1, err := ParseVersion(">=0.0.20190406.4.9.172-r1")
|
||||
v2, err2 := ParseVersion("1.0.111")
|
||||
@@ -184,6 +250,54 @@ 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("Selector8", func() {
|
||||
v1, err := ParseVersion(">=0")
|
||||
v2, err2 := ParseVersion("1.0.29+pre2_p20191024")
|
||||
match, err3 := PackageAdmit(v1, v2)
|
||||
It("Selector8", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(err2).Should(BeNil())
|
||||
Expect(err3).Should(BeNil())
|
||||
Expect(match).Should(Equal(true))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Condition Converter 1", func() {
|
||||
gp, err := gentoo.ParsePackageStr("=layer/build-1.0")
|
||||
var cond gentoo.PackageCond = gentoo.PkgCondEqual
|
||||
|
@@ -35,7 +35,7 @@ func LoadRepositories(c *LuetConfig) error {
|
||||
|
||||
files, err := ioutil.ReadDir(rdir)
|
||||
if err != nil {
|
||||
Warning("Skip dir", rdir, ":", err.Error())
|
||||
Debug("Skip dir", rdir, ":", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
|
@@ -28,11 +28,11 @@ import (
|
||||
type PackageSolver interface {
|
||||
SetDefinitionDatabase(pkg.PackageDatabase)
|
||||
Install(p []pkg.Package) (PackagesAssertions, error)
|
||||
Uninstall(candidate pkg.Package) ([]pkg.Package, error)
|
||||
Uninstall(candidate pkg.Package, checkconflicts bool) ([]pkg.Package, error)
|
||||
ConflictsWithInstalled(p pkg.Package) (bool, error)
|
||||
ConflictsWith(p pkg.Package, ls []pkg.Package) (bool, error)
|
||||
World() []pkg.Package
|
||||
Upgrade() ([]pkg.Package, PackagesAssertions, error)
|
||||
Upgrade(checkconflicts bool) ([]pkg.Package, PackagesAssertions, error)
|
||||
|
||||
SetResolver(PackageResolver)
|
||||
|
||||
@@ -210,7 +210,7 @@ func (s *Solver) ConflictsWithInstalled(p pkg.Package) (bool, error) {
|
||||
return s.ConflictsWith(p, s.Installed())
|
||||
}
|
||||
|
||||
func (s *Solver) Upgrade() ([]pkg.Package, PackagesAssertions, error) {
|
||||
func (s *Solver) Upgrade(checkconflicts bool) ([]pkg.Package, PackagesAssertions, error) {
|
||||
|
||||
// First get candidates that needs to be upgraded..
|
||||
|
||||
@@ -236,12 +236,11 @@ func (s *Solver) Upgrade() ([]pkg.Package, PackagesAssertions, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s2 := NewSolver(installedcopy, s.DefinitionDatabase, pkg.NewInMemoryDatabase(false))
|
||||
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)
|
||||
r, err := s.Uninstall(p, checkconflicts)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "Could not compute upgrade - couldn't uninstall selected candidate "+p.GetFingerPrint())
|
||||
}
|
||||
@@ -262,7 +261,7 @@ func (s *Solver) Upgrade() ([]pkg.Package, PackagesAssertions, error) {
|
||||
|
||||
// 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) ([]pkg.Package, error) {
|
||||
func (s *Solver) Uninstall(c pkg.Package, checkconflicts bool) ([]pkg.Package, error) {
|
||||
var res []pkg.Package
|
||||
candidate, err := s.InstalledDatabase.FindPackage(c)
|
||||
if err != nil {
|
||||
@@ -294,17 +293,19 @@ func (s *Solver) Uninstall(c pkg.Package) ([]pkg.Package, error) {
|
||||
}
|
||||
}
|
||||
|
||||
s2 := NewSolver(pkg.NewInMemoryDatabase(false), s.DefinitionDatabase, pkg.NewInMemoryDatabase(false))
|
||||
s2.SetResolver(s.Resolver)
|
||||
// Get the requirements to install the candidate
|
||||
saved := s.InstalledDatabase
|
||||
s.InstalledDatabase = pkg.NewInMemoryDatabase(false)
|
||||
asserts, err := s.Install([]pkg.Package{candidate})
|
||||
asserts, err := s2.Install([]pkg.Package{candidate})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.InstalledDatabase = saved
|
||||
|
||||
for _, a := range asserts {
|
||||
if a.Value {
|
||||
if !checkconflicts {
|
||||
res = append(res, a.Package.IsFlagged(false))
|
||||
continue
|
||||
}
|
||||
|
||||
c, err := s.ConflictsWithInstalled(a.Package)
|
||||
if err != nil {
|
||||
|
@@ -363,12 +363,19 @@ var _ = Describe("Solver", func() {
|
||||
It("Selects best version", func() {
|
||||
|
||||
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E.SetCategory("test")
|
||||
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
C.SetCategory("test")
|
||||
D2 := pkg.NewPackage("D", "1.9", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
D2.SetCategory("test")
|
||||
D := pkg.NewPackage("D", "1.8", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
D.SetCategory("test")
|
||||
D1 := pkg.NewPackage("D", "1.4", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
|
||||
D1.SetCategory("test")
|
||||
B := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0", Category: "test"}}, []*pkg.DefaultPackage{})
|
||||
B.SetCategory("test")
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0", Category: "test"}}, []*pkg.DefaultPackage{})
|
||||
A.SetCategory("test")
|
||||
|
||||
for _, p := range []pkg.Package{A, B, C, D, D1, D2, E} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
@@ -397,16 +404,23 @@ var _ = Describe("Solver", func() {
|
||||
It("Support provides", func() {
|
||||
|
||||
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
|
||||
E.SetCategory("test")
|
||||
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
C.SetCategory("test")
|
||||
D2 := pkg.NewPackage("D", "1.9", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
D2.SetCategory("test")
|
||||
D := pkg.NewPackage("D", "1.8", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
D.SetCategory("test")
|
||||
D1 := pkg.NewPackage("D", "1.4", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
|
||||
D1.SetCategory("test")
|
||||
B := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0", Category: "test"}}, []*pkg.DefaultPackage{})
|
||||
B.SetCategory("test")
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0", Category: "test"}}, []*pkg.DefaultPackage{})
|
||||
A.SetCategory("test")
|
||||
|
||||
D2.SetProvides([]*pkg.DefaultPackage{{Name: "E"}})
|
||||
A2 := pkg.NewPackage("A", "1.3", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "E", Version: ""}}, []*pkg.DefaultPackage{})
|
||||
D2.SetProvides([]*pkg.DefaultPackage{{Name: "E", Category: "test"}})
|
||||
A2 := pkg.NewPackage("A", "1.3", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "E", Version: "", Category: "test"}}, []*pkg.DefaultPackage{})
|
||||
A2.SetCategory("test")
|
||||
|
||||
for _, p := range []pkg.Package{A, B, C, D, D1, D2, A2, E} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
@@ -429,7 +443,7 @@ var _ = Describe("Solver", func() {
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D1, Value: false}))
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: E, Value: true}))
|
||||
|
||||
Expect(len(solution)).To(Equal(5))
|
||||
Expect(len(solution)).To(Equal(6))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
@@ -470,7 +484,7 @@ var _ = Describe("Solver", func() {
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D1, Value: false}))
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: E, Value: true}))
|
||||
|
||||
Expect(len(solution)).To(Equal(4))
|
||||
Expect(len(solution)).To(Equal(6))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
@@ -511,7 +525,7 @@ var _ = Describe("Solver", func() {
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D1, Value: false}))
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: E, Value: true}))
|
||||
|
||||
Expect(len(solution)).To(Equal(4))
|
||||
Expect(len(solution)).To(Equal(6))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
@@ -533,7 +547,7 @@ var _ = Describe("Solver", func() {
|
||||
}
|
||||
s = NewSolver(dbInstalled, dbDefinitions, db)
|
||||
|
||||
solution, err := s.Uninstall(A)
|
||||
solution, err := s.Uninstall(A, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).To(ContainElement(A.IsFlagged(false)))
|
||||
@@ -559,7 +573,7 @@ var _ = Describe("Solver", func() {
|
||||
}
|
||||
s = NewSolver(dbInstalled, dbDefinitions, db)
|
||||
|
||||
solution, err := s.Uninstall(&pkg.DefaultPackage{Name: "A", Version: ">1.0"})
|
||||
solution, err := s.Uninstall(&pkg.DefaultPackage{Name: "A", Version: ">1.0"}, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).To(ContainElement(A.IsFlagged(false)))
|
||||
@@ -674,7 +688,7 @@ var _ = Describe("Solver", func() {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
solution, err := s.Uninstall(A)
|
||||
solution, err := s.Uninstall(A, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).To(ContainElement(A.IsFlagged(false)))
|
||||
@@ -698,7 +712,7 @@ var _ = Describe("Solver", func() {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
solution, err := s.Uninstall(A)
|
||||
solution, err := s.Uninstall(A, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).To(ContainElement(A.IsFlagged(false)))
|
||||
@@ -721,7 +735,7 @@ var _ = Describe("Solver", func() {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
solution, err := s.Uninstall(A)
|
||||
solution, err := s.Uninstall(A, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).To(ContainElement(A.IsFlagged(false)))
|
||||
@@ -746,7 +760,7 @@ var _ = Describe("Solver", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Uninstall(A)
|
||||
solution, err := s.Uninstall(A, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).To(ContainElement(A.IsFlagged(false)))
|
||||
@@ -772,7 +786,7 @@ var _ = Describe("Solver", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Uninstall(A)
|
||||
solution, err := s.Uninstall(A, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).To(ContainElement(A.IsFlagged(false)))
|
||||
@@ -893,7 +907,7 @@ var _ = Describe("Solver", func() {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
uninstall, solution, err := s.Upgrade()
|
||||
uninstall, solution, err := s.Upgrade(true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(uninstall)).To(Equal(1))
|
||||
|
@@ -26,5 +26,5 @@ type Builder interface {
|
||||
GetDatabase() pkg.PackageDatabase
|
||||
WithDatabase(d pkg.PackageDatabase)
|
||||
|
||||
GetSourcePath() string
|
||||
GetSourcePath() []string
|
||||
}
|
||||
|
@@ -38,6 +38,20 @@ func NewCompilerRecipe(d pkg.PackageDatabase) Builder {
|
||||
return &CompilerRecipe{Recipe: Recipe{Database: d}}
|
||||
}
|
||||
|
||||
func ReadDefinitionFile(path string) (pkg.DefaultPackage, error) {
|
||||
empty := pkg.DefaultPackage{}
|
||||
dat, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return empty, errors.Wrap(err, "Error reading file "+path)
|
||||
}
|
||||
pack, err := pkg.DefaultPackageFromYaml(dat)
|
||||
if err != nil {
|
||||
return empty, errors.Wrap(err, "Error reading yaml "+path)
|
||||
}
|
||||
|
||||
return pack, nil
|
||||
}
|
||||
|
||||
// Recipe is the "general" reciper for Trees
|
||||
type CompilerRecipe struct {
|
||||
Recipe
|
||||
@@ -45,7 +59,7 @@ type CompilerRecipe struct {
|
||||
|
||||
func (r *CompilerRecipe) Load(path string) error {
|
||||
|
||||
r.SourcePath = path
|
||||
r.SourcePath = append(r.SourcePath, path)
|
||||
//tmpfile, err := ioutil.TempFile("", "luet")
|
||||
//if err != nil {
|
||||
// return err
|
||||
@@ -56,17 +70,17 @@ func (r *CompilerRecipe) Load(path string) error {
|
||||
// the function that handles each file or dir
|
||||
var ff = func(currentpath string, info os.FileInfo, err error) error {
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error on walk path "+currentpath)
|
||||
}
|
||||
|
||||
if info.Name() != DefinitionFile {
|
||||
return nil // Skip with no errors
|
||||
}
|
||||
|
||||
dat, err := ioutil.ReadFile(currentpath)
|
||||
pack, err := ReadDefinitionFile(currentpath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading file "+currentpath)
|
||||
}
|
||||
pack, err := pkg.DefaultPackageFromYaml(dat)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading yaml "+currentpath)
|
||||
return err
|
||||
}
|
||||
// Path is set only internally when tree is loaded from disk
|
||||
pack.SetPath(filepath.Dir(currentpath))
|
||||
@@ -74,13 +88,17 @@ func (r *CompilerRecipe) Load(path string) error {
|
||||
// Instead of rdeps, have a different tree for build deps.
|
||||
compileDefPath := pack.Rel(CompilerDefinitionFile)
|
||||
if helpers.Exists(compileDefPath) {
|
||||
dat, err = ioutil.ReadFile(compileDefPath)
|
||||
dat, err := ioutil.ReadFile(compileDefPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading file "+currentpath)
|
||||
return errors.Wrap(err,
|
||||
"Error reading file "+CompilerDefinitionFile+" from "+
|
||||
filepath.Dir(currentpath))
|
||||
}
|
||||
packbuild, err := pkg.DefaultPackageFromYaml(dat)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading yaml "+currentpath)
|
||||
return errors.Wrap(err,
|
||||
"Error reading yaml "+CompilerDefinitionFile+" from "+
|
||||
filepath.Dir(currentpath))
|
||||
}
|
||||
pack.Requires(packbuild.GetRequires())
|
||||
pack.Conflicts(packbuild.GetConflicts())
|
||||
@@ -103,4 +121,4 @@ func (r *CompilerRecipe) Load(path string) error {
|
||||
|
||||
func (r *CompilerRecipe) GetDatabase() pkg.PackageDatabase { return r.Database }
|
||||
func (r *CompilerRecipe) WithDatabase(d pkg.PackageDatabase) { r.Database = d }
|
||||
func (r *CompilerRecipe) GetSourcePath() string { return r.SourcePath }
|
||||
func (r *CompilerRecipe) GetSourcePath() []string { return r.SourcePath }
|
||||
|
@@ -40,7 +40,7 @@ func NewInstallerRecipe(db pkg.PackageDatabase) Builder {
|
||||
|
||||
// InstallerRecipe is the "general" reciper for Trees
|
||||
type InstallerRecipe struct {
|
||||
SourcePath string
|
||||
SourcePath []string
|
||||
Database pkg.PackageDatabase
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func (r *InstallerRecipe) Load(path string) error {
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
r.SourcePath = path
|
||||
r.SourcePath = append(r.SourcePath, path)
|
||||
|
||||
//r.Tree().SetPackageSet(pkg.NewBoltDatabase(tmpfile.Name()))
|
||||
// TODO: Handle cleaning after? Cleanup implemented in GetPackageSet().Clean()
|
||||
@@ -114,4 +114,4 @@ func (r *InstallerRecipe) Load(path string) error {
|
||||
|
||||
func (r *InstallerRecipe) GetDatabase() pkg.PackageDatabase { return r.Database }
|
||||
func (r *InstallerRecipe) WithDatabase(d pkg.PackageDatabase) { r.Database = d }
|
||||
func (r *InstallerRecipe) GetSourcePath() string { return r.SourcePath }
|
||||
func (r *InstallerRecipe) GetSourcePath() []string { return r.SourcePath }
|
||||
|
@@ -37,24 +37,32 @@ func NewGeneralRecipe(db pkg.PackageDatabase) Builder { return &Recipe{Database:
|
||||
|
||||
// Recipe is the "general" reciper for Trees
|
||||
type Recipe struct {
|
||||
SourcePath string
|
||||
SourcePath []string
|
||||
Database pkg.PackageDatabase
|
||||
}
|
||||
|
||||
func (r *Recipe) Save(path string) error {
|
||||
func WriteDefinitionFile(p pkg.Package, definitionFilePath string) error {
|
||||
data, err := p.Yaml()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(definitionFilePath, data, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Recipe) Save(path string) error {
|
||||
for _, p := range r.Database.World() {
|
||||
dir := filepath.Join(path, p.GetCategory(), p.GetName(), p.GetVersion())
|
||||
os.MkdirAll(dir, os.ModePerm)
|
||||
data, err := p.Yaml()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(dir, DefinitionFile), data, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := WriteDefinitionFile(p, filepath.Join(dir, DefinitionFile))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -65,7 +73,7 @@ func (r *Recipe) Load(path string) error {
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
r.SourcePath = path
|
||||
r.SourcePath = append(r.SourcePath, path)
|
||||
|
||||
if r.Database == nil {
|
||||
r.Database = pkg.NewInMemoryDatabase(false)
|
||||
@@ -109,4 +117,4 @@ func (r *Recipe) Load(path string) error {
|
||||
|
||||
func (r *Recipe) GetDatabase() pkg.PackageDatabase { return r.Database }
|
||||
func (r *Recipe) WithDatabase(d pkg.PackageDatabase) { r.Database = d }
|
||||
func (r *Recipe) GetSourcePath() string { return r.SourcePath }
|
||||
func (r *Recipe) GetSourcePath() []string { return r.SourcePath }
|
||||
|
@@ -96,4 +96,77 @@ var _ = Describe("Tree", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Context("Multiple trees", func() {
|
||||
It("Merges", func() {
|
||||
for index := 0; index < 300; index++ { // Just to make sure we don't have false positives
|
||||
db := pkg.NewInMemoryDatabase(false)
|
||||
generalRecipe := NewCompilerRecipe(db)
|
||||
tmpdir, err := ioutil.TempDir("", "package")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(tmpdir) // clean up
|
||||
|
||||
err = generalRecipe.Load("../../tests/fixtures/buildableseed")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(generalRecipe.GetDatabase().World())).To(Equal(4))
|
||||
|
||||
err = generalRecipe.Load("../../tests/fixtures/layers")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(generalRecipe.GetDatabase().World())).To(Equal(6))
|
||||
|
||||
extra, err := generalRecipe.GetDatabase().FindPackage(&pkg.DefaultPackage{Name: "extra", Category: "layer", Version: "1.0"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(extra).ToNot(BeNil())
|
||||
|
||||
D, err := generalRecipe.GetDatabase().FindPackage(&pkg.DefaultPackage{Name: "d", Category: "test", Version: "1.0"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(D.GetRequires()[0].GetName()).To(Equal("c"))
|
||||
CfromD, err := generalRecipe.GetDatabase().FindPackage(D.GetRequires()[0])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(CfromD.GetRequires()) != 0).To(BeTrue())
|
||||
Expect(CfromD.GetRequires()[0].GetName()).To(Equal("b"))
|
||||
|
||||
s := solver.NewSolver(pkg.NewInMemoryDatabase(false), generalRecipe.GetDatabase(), db)
|
||||
|
||||
Dd, err := generalRecipe.GetDatabase().FindPackage(&pkg.DefaultPackage{Name: "d", Category: "test", Version: "1.0"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
solution, err := s.Install([]pkg.Package{Dd})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
solution = solution.Order(generalRecipe.GetDatabase(), Dd.GetFingerPrint())
|
||||
pack, err := generalRecipe.GetDatabase().FindPackage(&pkg.DefaultPackage{Name: "a", Category: "test", Version: "1.0"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
base, err := generalRecipe.GetDatabase().FindPackage(&pkg.DefaultPackage{Name: "base", Category: "layer", Version: "0.2"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(solution).To(ContainElement(solver.PackageAssert{Package: pack.(*pkg.DefaultPackage), Value: false}))
|
||||
Expect(solution).To(ContainElement(solver.PackageAssert{Package: D.(*pkg.DefaultPackage), Value: true}))
|
||||
Expect(solution).To(ContainElement(solver.PackageAssert{Package: extra.(*pkg.DefaultPackage), Value: false}))
|
||||
Expect(solution).To(ContainElement(solver.PackageAssert{Package: base.(*pkg.DefaultPackage), Value: false}))
|
||||
Expect(len(solution)).To(Equal(6))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Context("Simple tree with labels", func() {
|
||||
It("Read tree with labels", func() {
|
||||
db := pkg.NewInMemoryDatabase(false)
|
||||
generalRecipe := NewCompilerRecipe(db)
|
||||
|
||||
err := generalRecipe.Load("../../tests/fixtures/labels")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(generalRecipe.GetDatabase().World())).To(Equal(1))
|
||||
pack, err := generalRecipe.GetDatabase().FindPackage(&pkg.DefaultPackage{Name: "pkgA", Category: "test", Version: "0.1"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(pack.HasLabel("label1")).To(Equal(true))
|
||||
Expect(pack.HasLabel("label3")).To(Equal(false))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
3
tests/fixtures/labels/pkgA/0.1/build.yaml
vendored
Normal file
3
tests/fixtures/labels/pkgA/0.1/build.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
image: "alpine"
|
||||
steps:
|
||||
- echo "test" > /file1
|
6
tests/fixtures/labels/pkgA/0.1/definition.yaml
vendored
Normal file
6
tests/fixtures/labels/pkgA/0.1/definition.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
category: "test"
|
||||
name: "pkgA"
|
||||
version: "0.1"
|
||||
labels:
|
||||
label1: "value1"
|
||||
label2: "value2"
|
2
tests/fixtures/layered/layer/base/build.yaml
vendored
2
tests/fixtures/layered/layer/base/build.yaml
vendored
@@ -1,2 +1,2 @@
|
||||
image: "golang:alpine"
|
||||
image: "golang"
|
||||
unpack: true
|
||||
|
@@ -3,8 +3,8 @@ requires:
|
||||
name: "base"
|
||||
version: "0.1"
|
||||
prelude:
|
||||
- apk update
|
||||
- apk add git
|
||||
- apt-get update
|
||||
- apt-get install git
|
||||
- rm -rf /go/pkg/mod
|
||||
steps:
|
||||
- echo test > /extra-layer
|
||||
|
@@ -3,7 +3,7 @@ requires:
|
||||
name: "extra"
|
||||
version: "0.1"
|
||||
prelude:
|
||||
- apk add git
|
||||
- apt-get install git
|
||||
- mkdir -p /go/src/github.com/Sabayon/
|
||||
- git clone https://github.com/Sabayon/pkgs-checker /go/src/github.com/Sabayon/pkgs-checker
|
||||
steps:
|
||||
|
10
tests/fixtures/upgrade_integration/c/build.yaml
vendored
Normal file
10
tests/fixtures/upgrade_integration/c/build.yaml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo c > /c
|
||||
- echo c > /cd
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "a"
|
||||
version: ">=1.0"
|
9
tests/fixtures/upgrade_integration/c/definition.yaml
vendored
Normal file
9
tests/fixtures/upgrade_integration/c/definition.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
category: "test"
|
||||
name: "c"
|
||||
version: "1.0"
|
||||
# Boom?
|
||||
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "a"
|
||||
version: ">=0.1"
|
11
tests/fixtures/upgrade_integration/cat/a/a/build.yaml
vendored
Normal file
11
tests/fixtures/upgrade_integration/cat/a/a/build.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
image: "alpine"
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact3 > /test3
|
||||
- echo artifact4 > /test4
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "b"
|
||||
version: "1.0"
|
8
tests/fixtures/upgrade_integration/cat/a/a/definition.yaml
vendored
Normal file
8
tests/fixtures/upgrade_integration/cat/a/a/definition.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
category: "test"
|
||||
name: "a"
|
||||
version: "1.1"
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "b"
|
||||
version: ">=0.1"
|
||||
|
11
tests/fixtures/upgrade_integration/cat/a/a1.0/build.yaml
vendored
Normal file
11
tests/fixtures/upgrade_integration/cat/a/a1.0/build.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
image: "alpine"
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact3 > /testaa
|
||||
- echo artifact4 > /testaa2
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "b"
|
||||
version: "1.0"
|
3
tests/fixtures/upgrade_integration/cat/a/a1.0/definition.yaml
vendored
Normal file
3
tests/fixtures/upgrade_integration/cat/a/a1.0/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "a"
|
||||
version: "1.0"
|
11
tests/fixtures/upgrade_integration/cat/a/alatest/build.yaml
vendored
Normal file
11
tests/fixtures/upgrade_integration/cat/a/alatest/build.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
image: "alpine"
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
steps:
|
||||
- echo artifact3 > /testlatest
|
||||
- echo artifact4 > /testlatest2
|
||||
requires:
|
||||
- category: "test"
|
||||
name: "b"
|
||||
version: "1.0"
|
3
tests/fixtures/upgrade_integration/cat/a/alatest/definition.yaml
vendored
Normal file
3
tests/fixtures/upgrade_integration/cat/a/alatest/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "a"
|
||||
version: "1.2"
|
9
tests/fixtures/upgrade_integration/cat/b-1.1/build.yaml
vendored
Normal file
9
tests/fixtures/upgrade_integration/cat/b-1.1/build.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
image: "alpine"
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
- chmod +x generate.sh
|
||||
steps:
|
||||
- echo artifact5 > /newc
|
||||
- echo artifact6 > /newnewc
|
||||
- ./generate.sh
|
3
tests/fixtures/upgrade_integration/cat/b-1.1/definition.yaml
vendored
Normal file
3
tests/fixtures/upgrade_integration/cat/b-1.1/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "b"
|
||||
version: "1.1"
|
1
tests/fixtures/upgrade_integration/cat/b-1.1/generate.sh
vendored
Normal file
1
tests/fixtures/upgrade_integration/cat/b-1.1/generate.sh
vendored
Normal file
@@ -0,0 +1 @@
|
||||
echo generated > /sonewc
|
9
tests/fixtures/upgrade_integration/cat/b/build.yaml
vendored
Normal file
9
tests/fixtures/upgrade_integration/cat/b/build.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
image: "alpine"
|
||||
prelude:
|
||||
- echo foo > /test
|
||||
- echo bar > /test2
|
||||
- chmod +x generate.sh
|
||||
steps:
|
||||
- echo artifact5 > /test5
|
||||
- echo artifact6 > /test6
|
||||
- ./generate.sh
|
3
tests/fixtures/upgrade_integration/cat/b/definition.yaml
vendored
Normal file
3
tests/fixtures/upgrade_integration/cat/b/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
category: "test"
|
||||
name: "b"
|
||||
version: "1.0"
|
1
tests/fixtures/upgrade_integration/cat/b/generate.sh
vendored
Normal file
1
tests/fixtures/upgrade_integration/cat/b/generate.sh
vendored
Normal file
@@ -0,0 +1 @@
|
||||
echo generated > /artifact42
|
@@ -12,7 +12,7 @@ oneTimeTearDown() {
|
||||
|
||||
testBuild() {
|
||||
mkdir $tmpdir/testbuild
|
||||
luet build --all --tree "$ROOT_DIR/tests/fixtures/qlearning" --destination $tmpdir/testbuild --compression gzip
|
||||
luet build --all --concurrency 1 --tree "$ROOT_DIR/tests/fixtures/qlearning" --destination $tmpdir/testbuild --compression gzip
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package dep B' "[ -e '$tmpdir/testbuild/b-test-1.0.package.tar.gz' ]"
|
||||
|
122
tests/integration/05_upgrade.sh
Executable file
122
tests/integration/05_upgrade.sh
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LUET_NOLOCK=true
|
||||
|
||||
oneTimeSetUp() {
|
||||
export tmpdir="$(mktemp -d)"
|
||||
}
|
||||
|
||||
oneTimeTearDown() {
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
|
||||
testBuild() {
|
||||
mkdir $tmpdir/testbuild
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/b-1.0
|
||||
buildst=$?
|
||||
assertTrue 'create package B 1.0' "[ -e '$tmpdir/testbuild/b-test-1.0.package.tar.gz' ]"
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/b-1.1
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package B 1.1' "[ -e '$tmpdir/testbuild/b-test-1.1.package.tar.gz' ]"
|
||||
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/a-1.0
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package A 1.0' "[ -e '$tmpdir/testbuild/a-test-1.0.package.tar.gz' ]"
|
||||
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/a-1.1
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
|
||||
assertTrue 'create package A 1.1' "[ -e '$tmpdir/testbuild/a-test-1.1.package.tar.gz' ]"
|
||||
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/a-1.2
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
|
||||
assertTrue 'create package A 1.2' "[ -e '$tmpdir/testbuild/a-test-1.2.package.tar.gz' ]"
|
||||
|
||||
|
||||
luet build --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" --destination $tmpdir/testbuild --compression gzip test/c-1.0
|
||||
buildst=$?
|
||||
assertEquals 'builds successfully' "$buildst" "0"
|
||||
assertTrue 'create package C 1.0' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.gz' ]"
|
||||
|
||||
}
|
||||
|
||||
testRepo() {
|
||||
assertTrue 'no repository' "[ ! -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||
luet create-repo --tree "$ROOT_DIR/tests/fixtures/upgrade_integration" \
|
||||
--output $tmpdir/testbuild \
|
||||
--packages $tmpdir/testbuild \
|
||||
--name "test" \
|
||||
--descr "Test Repo" \
|
||||
--urls $tmpdir/testrootfs \
|
||||
--type disk
|
||||
|
||||
createst=$?
|
||||
assertEquals 'create repo successfully' "$createst" "0"
|
||||
assertTrue 'create repository' "[ -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||
}
|
||||
|
||||
testConfig() {
|
||||
mkdir $tmpdir/testrootfs
|
||||
cat <<EOF > $tmpdir/luet.yaml
|
||||
general:
|
||||
debug: true
|
||||
system:
|
||||
rootfs: $tmpdir/testrootfs
|
||||
database_path: "/"
|
||||
database_engine: "boltdb"
|
||||
repositories:
|
||||
- name: "main"
|
||||
type: "disk"
|
||||
enable: true
|
||||
urls:
|
||||
- "$tmpdir/testbuild"
|
||||
EOF
|
||||
luet config --config $tmpdir/luet.yaml
|
||||
res=$?
|
||||
assertEquals 'config test successfully' "$res" "0"
|
||||
}
|
||||
|
||||
testInstall() {
|
||||
luet install --config $tmpdir/luet.yaml test/b-1.0
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed B' "[ -e '$tmpdir/testrootfs/test5' ]"
|
||||
|
||||
luet install --config $tmpdir/luet.yaml test/a-1.0
|
||||
assertTrue 'package installed A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
|
||||
luet install --config $tmpdir/luet.yaml test/a-1.1
|
||||
assertTrue 'package installed A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package keeps old A' "[ -e '$tmpdir/testrootfs/testaa' ]"
|
||||
assertTrue 'package new A was not installed' "[ ! -e '$tmpdir/testrootfs/testlatest' ]"
|
||||
|
||||
luet install --config $tmpdir/luet.yaml test/c-1.0
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package installed C' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||
}
|
||||
|
||||
testUpgrade() {
|
||||
luet --config $tmpdir/luet.yaml upgrade
|
||||
installst=$?
|
||||
assertEquals 'install test successfully' "$installst" "0"
|
||||
assertTrue 'package uninstalled B' "[ ! -e '$tmpdir/testrootfs/test5' ]"
|
||||
assertTrue 'package installed B' "[ -e '$tmpdir/testrootfs/newc' ]"
|
||||
assertTrue 'package uninstalled A' "[ ! -e '$tmpdir/testrootfs/testaa' ]"
|
||||
assertTrue 'package installed new A' "[ -e '$tmpdir/testrootfs/testlatest' ]"
|
||||
}
|
||||
|
||||
# Load shUnit2.
|
||||
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||
|
119
vendor/github.com/Sabayon/pkgs-checker/pkg/gentoo/pkg.go
generated
vendored
119
vendor/github.com/Sabayon/pkgs-checker/pkg/gentoo/pkg.go
generated
vendored
@@ -54,15 +54,22 @@ const (
|
||||
PkgCondMatchVersion = 8
|
||||
)
|
||||
|
||||
const (
|
||||
RegexCatString = `(^[a-z]+[0-9]*[a-z]*[-]*[a-z]+[0-9]*[a-z]*|^virtual)`
|
||||
RegexPkgNameString = `([a-zA-Z]*[0-9a-zA-Z\.\-_]*[a-zA-Z0-9]+|[a-zA-Z]+[+]+)`
|
||||
)
|
||||
|
||||
type GentooPackage struct {
|
||||
Name string `json:"name",omitempty"`
|
||||
Category string `json:"category",omitempty"`
|
||||
Version string `json:"version",omitempty"`
|
||||
VersionSuffix string `json:"version_suffix",omitempty"`
|
||||
VersionBuild string `json:"version_build",omitempty"`
|
||||
Slot string `json:"slot",omitempty"`
|
||||
Condition PackageCond
|
||||
Repository string `json:"repository",omitempty"`
|
||||
UseFlags []string `json:"use_flags",omitempty"`
|
||||
License string `json:"license",omitempty"`
|
||||
}
|
||||
|
||||
func (p *GentooPackage) String() string {
|
||||
@@ -191,14 +198,23 @@ func (p *GentooPackage) Admit(i *GentooPackage) (bool, error) {
|
||||
fmt.Sprintf("Wrong name for package %s", i.Name))
|
||||
}
|
||||
|
||||
if p.Version != "" {
|
||||
v1, err = version.NewVersion(p.Version)
|
||||
v1s := p.Version
|
||||
v2s := i.Version
|
||||
|
||||
if v1s != "" {
|
||||
if p.VersionBuild != "" {
|
||||
v1s = p.Version + "+" + p.VersionBuild
|
||||
}
|
||||
v1, err = version.NewVersion(v1s)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
if i.Version != "" {
|
||||
v2, err = version.NewVersion(i.Version)
|
||||
if v2s != "" {
|
||||
if i.VersionBuild != "" {
|
||||
v2s = i.Version + "+" + i.VersionBuild
|
||||
}
|
||||
v2, err = version.NewVersion(v2s)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -210,7 +226,8 @@ func (p *GentooPackage) Admit(i *GentooPackage) (bool, error) {
|
||||
} else {
|
||||
if p.Condition == PkgCondInvalid || p.Condition == PkgCondEqual {
|
||||
// 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
|
||||
}
|
||||
} else if p.Condition == PkgCondAnyRevision {
|
||||
@@ -270,8 +287,9 @@ func ParsePackageStr(pkg string) (*GentooPackage, error) {
|
||||
}
|
||||
|
||||
ans := GentooPackage{
|
||||
Slot: "0",
|
||||
Condition: PkgCondInvalid,
|
||||
Slot: "0",
|
||||
Condition: PkgCondInvalid,
|
||||
VersionBuild: "",
|
||||
}
|
||||
|
||||
// Check if pkg string contains inline use flags
|
||||
@@ -315,6 +333,67 @@ func ParsePackageStr(pkg string) (*GentooPackage, error) {
|
||||
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, "/")
|
||||
if len(words) != 2 {
|
||||
return nil, errors.New(fmt.Sprintf("Invalid package string %s", pkg))
|
||||
@@ -337,31 +416,9 @@ func ParsePackageStr(pkg string) (*GentooPackage, error) {
|
||||
}
|
||||
|
||||
regexPkg := regexp.MustCompile(
|
||||
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",
|
||||
),
|
||||
fmt.Sprintf("%s$", regexVerString),
|
||||
)
|
||||
|
||||
matches := regexPkg.FindAllString(pkgname, -1)
|
||||
|
||||
// NOTE: Now suffix comples like _alpha_rc1 are not supported.
|
||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -23,7 +23,7 @@ github.com/Microsoft/hcsshim/internal/longpath
|
||||
github.com/Microsoft/hcsshim/internal/safefile
|
||||
# github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5
|
||||
github.com/Nvveen/Gotty
|
||||
# github.com/Sabayon/pkgs-checker v0.4.2-0.20200101193228-1d500105afb7
|
||||
# github.com/Sabayon/pkgs-checker v0.6.2-0.20200315232328-b6efed54b4b1
|
||||
github.com/Sabayon/pkgs-checker/pkg/gentoo
|
||||
# github.com/apex/log v1.1.1
|
||||
github.com/apex/log
|
||||
|
Reference in New Issue
Block a user