diff --git a/cmd/build.go b/cmd/build.go index 3c931329..a08b6e87 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -31,7 +31,6 @@ import ( "github.com/mudler/luet/pkg/compiler/types/options" fileHelpers "github.com/mudler/luet/pkg/helpers/file" pkg "github.com/mudler/luet/pkg/package" - "github.com/mudler/luet/pkg/solver" tree "github.com/mudler/luet/pkg/tree" "github.com/spf13/cobra" @@ -39,6 +38,10 @@ import ( ) var buildCmd = &cobra.Command{ + // Skip processing output + Annotations: map[string]string{ + util.CommandProcessOutput: "", + }, Use: "build ...", Short: "build a package or a tree", Long: `Builds one or more packages from a tree (current directory is implied): @@ -83,8 +86,6 @@ Build packages specifying multiple definition trees: viper.BindPFlag("wait", cmd.Flags().Lookup("wait")) viper.BindPFlag("keep-images", cmd.Flags().Lookup("keep-images")) - util.BindSolverFlags(cmd) - viper.BindPFlag("general.show_build_output", cmd.Flags().Lookup("live-output")) viper.BindPFlag("backend-args", cmd.Flags().Lookup("backend-args")) @@ -93,7 +94,7 @@ Build packages specifying multiple definition trees: treePaths := viper.GetStringSlice("tree") dst := viper.GetString("destination") - concurrency := util.DefaultContext.Config.GetGeneral().Concurrency + concurrency := util.DefaultContext.Config.General.Concurrency backendType := viper.GetString("backend") privileged := viper.GetBool("privileged") revdeps := viper.GetBool("revdeps") @@ -116,11 +117,7 @@ Build packages specifying multiple definition trees: var results Results backendArgs := viper.GetStringSlice("backend-args") - out, _ := cmd.Flags().GetString("output") - if out != "terminal" { - util.DefaultContext.Config.GetLogging().SetLogLevel("error") - } pretend, _ := cmd.Flags().GetBool("pretend") fromRepo, _ := cmd.Flags().GetBool("from-repositories") @@ -153,15 +150,11 @@ Build packages specifying multiple definition trees: util.DefaultContext.Debug("Creating destination folder", dst) } - opts := util.SetSolverConfig(util.DefaultContext) + opts := util.DefaultContext.GetConfig().Solver pullRepo, _ := cmd.Flags().GetStringArray("pull-repository") - util.DefaultContext.Config.GetGeneral().ShowBuildOutput = viper.GetBool("general.show_build_output") - util.DefaultContext.Debug("Solver", opts.CompactString()) - opts.Options = solver.Options{Type: solver.SingleCoreSimple, Concurrency: concurrency} - compileropts := []options.Option{options.NoDeps(nodeps), options.WithBackendType(backendType), options.PushImages(push), @@ -170,7 +163,7 @@ Build packages specifying multiple definition trees: options.WithPushRepository(imageRepository), options.Rebuild(rebuild), options.WithTemplateFolder(util.TemplateFolders(util.DefaultContext, fromRepo, treePaths)), - options.WithSolverOptions(*opts), + options.WithSolverOptions(opts), options.Wait(wait), options.OnlyTarget(onlyTarget), options.PullFirst(pull), @@ -341,7 +334,7 @@ func init() { buildCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate") buildCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts") buildCmd.Flags().Bool("solver-concurrent", false, "Use concurrent solver (experimental)") - buildCmd.Flags().Bool("live-output", util.DefaultContext.Config.GetGeneral().ShowBuildOutput, "Enable live output of the build phase.") + buildCmd.Flags().Bool("live-output", true, "Enable live output of the build phase.") buildCmd.Flags().Bool("from-repositories", false, "Consume the user-defined repositories to pull specfiles from") buildCmd.Flags().Bool("rebuild", false, "To combine with --pull. Allows to rebuild the target package even if an image is available, against a local values file") buildCmd.Flags().Bool("pretend", false, "Just print what packages will be compiled") diff --git a/cmd/cleanup.go b/cmd/cleanup.go index cac50310..886b50f2 100644 --- a/cmd/cleanup.go +++ b/cmd/cleanup.go @@ -31,16 +31,13 @@ var cleanupCmd = &cobra.Command{ Use: "cleanup", Short: "Clean packages cache.", Long: `remove downloaded packages tarballs and clean cache directory`, - PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - }, + Run: func(cmd *cobra.Command, args []string) { var cleaned int = 0 - util.SetSystemConfig(util.DefaultContext) // Check if cache dir exists - if fileHelper.Exists(util.DefaultContext.Config.GetSystem().GetSystemPkgsCacheDirPath()) { + if fileHelper.Exists(util.DefaultContext.Config.System.PkgsCachePath) { - files, err := ioutil.ReadDir(util.DefaultContext.Config.GetSystem().GetSystemPkgsCacheDirPath()) + files, err := ioutil.ReadDir(util.DefaultContext.Config.System.PkgsCachePath) if err != nil { util.DefaultContext.Fatal("Error on read cachedir ", err.Error()) } @@ -50,7 +47,7 @@ var cleanupCmd = &cobra.Command{ util.DefaultContext.Debug("Removing ", file.Name()) err := os.RemoveAll( - filepath.Join(util.DefaultContext.Config.GetSystem().GetSystemPkgsCacheDirPath(), file.Name())) + filepath.Join(util.DefaultContext.Config.System.PkgsCachePath, file.Name())) if err != nil { util.DefaultContext.Fatal("Error on removing", file.Name()) } @@ -58,14 +55,11 @@ var cleanupCmd = &cobra.Command{ } } - util.DefaultContext.Info(fmt.Sprintf("Cleaned: %d files from %s", cleaned, util.DefaultContext.Config.GetSystem().GetSystemPkgsCacheDirPath())) + util.DefaultContext.Info(fmt.Sprintf("Cleaned: %d files from %s", cleaned, util.DefaultContext.Config.System.PkgsCachePath)) }, } func init() { - cleanupCmd.Flags().String("system-dbpath", "", "System db path") - cleanupCmd.Flags().String("system-target", "", "System rootpath") - cleanupCmd.Flags().String("system-engine", "", "System DB engine") RootCmd.AddCommand(cleanupCmd) } diff --git a/cmd/database/create.go b/cmd/database/create.go index 955e2e55..0fbe4914 100644 --- a/cmd/database/create.go +++ b/cmd/database/create.go @@ -27,7 +27,7 @@ import ( ) func NewDatabaseCreateCommand() *cobra.Command { - var ans = &cobra.Command{ + return &cobra.Command{ Use: "create ", Short: "Insert a package in the system DB", Long: `Inserts a package in the system database: @@ -42,12 +42,8 @@ The yaml must contain the package definition, and the file list at least. For reference, inspect a "metadata.yaml" file generated while running "luet build"`, Args: cobra.OnlyValidArgs, - PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - }, Run: func(cmd *cobra.Command, args []string) { - util.SetSystemConfig(util.DefaultContext) systemDB := util.DefaultContext.Config.GetSystemDB() for _, a := range args { @@ -81,9 +77,4 @@ For reference, inspect a "metadata.yaml" file generated while running "luet buil }, } - ans.Flags().String("system-dbpath", "", "System db path") - ans.Flags().String("system-target", "", "System rootpath") - ans.Flags().String("system-engine", "", "System DB engine") - - return ans } diff --git a/cmd/database/get.go b/cmd/database/get.go index 2043226a..011471cd 100644 --- a/cmd/database/get.go +++ b/cmd/database/get.go @@ -36,12 +36,9 @@ func NewDatabaseGetCommand() *cobra.Command { To return also files: $ luet database get --files system/foo`, Args: cobra.OnlyValidArgs, - PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - }, + Run: func(cmd *cobra.Command, args []string) { showFiles, _ := cmd.Flags().GetBool("files") - util.SetSystemConfig(util.DefaultContext) systemDB := util.DefaultContext.Config.GetSystemDB() @@ -77,9 +74,6 @@ To return also files: }, } c.Flags().Bool("files", false, "Show package files.") - c.Flags().String("system-dbpath", "", "System db path") - c.Flags().String("system-target", "", "System rootpath") - c.Flags().String("system-engine", "", "System DB engine") return c } diff --git a/cmd/database/remove.go b/cmd/database/remove.go index 1934064a..f71a87ae 100644 --- a/cmd/database/remove.go +++ b/cmd/database/remove.go @@ -23,7 +23,7 @@ import ( ) func NewDatabaseRemoveCommand() *cobra.Command { - var ans = &cobra.Command{ + return &cobra.Command{ Use: "remove [package1] [package2] ...", Short: "Remove a package from the system DB (forcefully - you normally don't want to do that)", Long: `Removes a package in the system database without actually uninstalling it: @@ -33,11 +33,8 @@ func NewDatabaseRemoveCommand() *cobra.Command { This commands takes multiple packages as arguments and prunes their entries from the system database. `, Args: cobra.OnlyValidArgs, - PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - }, + Run: func(cmd *cobra.Command, args []string) { - util.SetSystemConfig(util.DefaultContext) systemDB := util.DefaultContext.Config.GetSystemDB() @@ -58,9 +55,5 @@ This commands takes multiple packages as arguments and prunes their entries from }, } - ans.Flags().String("system-dbpath", "", "System db path") - ans.Flags().String("system-target", "", "System rootpath") - ans.Flags().String("system-engine", "", "System DB engine") - return ans } diff --git a/cmd/install.go b/cmd/install.go index 62381a77..5ee79641 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -15,9 +15,7 @@ package cmd import ( - "github.com/mudler/luet/pkg/api/core/types" installer "github.com/mudler/luet/pkg/installer" - "github.com/mudler/luet/pkg/solver" helpers "github.com/mudler/luet/cmd/helpers" "github.com/mudler/luet/cmd/util" @@ -48,8 +46,6 @@ To force install a package: `, Aliases: []string{"i"}, PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - util.BindSolverFlags(cmd) viper.BindPFlag("onlydeps", cmd.Flags().Lookup("onlydeps")) viper.BindPFlag("nodeps", cmd.Flags().Lookup("nodeps")) viper.BindPFlag("force", cmd.Flags().Lookup("force")) @@ -71,28 +67,13 @@ To force install a package: onlydeps := viper.GetBool("onlydeps") yes := viper.GetBool("yes") downloadOnly, _ := cmd.Flags().GetBool("download-only") - finalizerEnvs, _ := cmd.Flags().GetStringArray("finalizer-env") relax, _ := cmd.Flags().GetBool("relax") - util.SetSystemConfig(util.DefaultContext) - util.SetSolverConfig(util.DefaultContext) - - util.DefaultContext.Config.GetSolverOptions().Implementation = solver.SingleCoreSimple - - util.DefaultContext.Debug("Solver", util.DefaultContext.Config.GetSolverOptions().CompactString()) - - // Load config protect configs - util.DefaultContext.Config.LoadConfigProtect(util.DefaultContext) - - // Load finalizer runtime environments - err := util.SetCliFinalizerEnvs(util.DefaultContext, finalizerEnvs) - if err != nil { - util.DefaultContext.Fatal(err.Error()) - } + util.DefaultContext.Debug("Solver", util.DefaultContext.Config.Solver.CompactString()) inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{ - Concurrency: util.DefaultContext.Config.GetGeneral().Concurrency, - SolverOptions: *util.DefaultContext.Config.GetSolverOptions(), + Concurrency: util.DefaultContext.Config.General.Concurrency, + SolverOptions: util.DefaultContext.Config.Solver, NoDeps: nodeps, Force: force, OnlyDeps: onlydeps, @@ -104,8 +85,11 @@ To force install a package: Context: util.DefaultContext, }) - system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.GetSystem().Rootfs} - err = inst.Install(toInstall, system) + system := &installer.System{ + Database: util.DefaultContext.Config.GetSystemDB(), + Target: util.DefaultContext.Config.System.Rootfs, + } + err := inst.Install(toInstall, system) if err != nil { util.DefaultContext.Fatal("Error: " + err.Error()) } @@ -113,14 +97,7 @@ To force install a package: } func init() { - installCmd.Flags().String("system-dbpath", "", "System db path") - installCmd.Flags().String("system-target", "", "System rootpath") - installCmd.Flags().String("system-engine", "", "System DB engine") - installCmd.Flags().String("solver-type", "", "Solver strategy ( Defaults none, available: "+types.AvailableResolvers+" )") - 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("relax", false, "Relax installation constraints") diff --git a/cmd/oscheck.go b/cmd/oscheck.go index 56c9b080..3edbde6c 100644 --- a/cmd/oscheck.go +++ b/cmd/oscheck.go @@ -19,10 +19,8 @@ import ( "os" "strings" - "github.com/mudler/luet/pkg/api/core/types" installer "github.com/mudler/luet/pkg/installer" pkg "github.com/mudler/luet/pkg/package" - "github.com/mudler/luet/pkg/solver" "github.com/mudler/luet/cmd/util" @@ -43,8 +41,6 @@ To reinstall packages in the list: `, Aliases: []string{"i"}, PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - util.BindSolverFlags(cmd) viper.BindPFlag("onlydeps", cmd.Flags().Lookup("onlydeps")) viper.BindPFlag("nodeps", cmd.Flags().Lookup("nodeps")) viper.BindPFlag("force", cmd.Flags().Lookup("force")) @@ -57,9 +53,11 @@ To reinstall packages in the list: yes := viper.GetBool("yes") downloadOnly, _ := cmd.Flags().GetBool("download-only") - util.SetSystemConfig(util.DefaultContext) - system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.GetSystem().Rootfs} + system := &installer.System{ + Database: util.DefaultContext.Config.GetSystemDB(), + Target: util.DefaultContext.Config.System.Rootfs, + } packs := system.OSCheck() if !util.DefaultContext.Config.General.Quiet { if len(packs) == 0 { @@ -90,18 +88,11 @@ To reinstall packages in the list: toInstall = append(toInstall, new) } - util.SetSolverConfig(util.DefaultContext) - - util.DefaultContext.Config.GetSolverOptions().Implementation = solver.SingleCoreSimple - - util.DefaultContext.Debug("Solver", util.DefaultContext.Config.GetSolverOptions().CompactString()) - - // Load config protect configs - util.DefaultContext.Config.LoadConfigProtect(util.DefaultContext) + util.DefaultContext.Debug("Solver", util.DefaultContext.Config.Solver.CompactString()) inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{ - Concurrency: util.DefaultContext.Config.GetGeneral().Concurrency, - SolverOptions: *util.DefaultContext.Config.GetSolverOptions(), + Concurrency: util.DefaultContext.Config.General.Concurrency, + SolverOptions: util.DefaultContext.Config.Solver, NoDeps: true, Force: force, OnlyDeps: onlydeps, @@ -121,18 +112,11 @@ To reinstall packages in the list: } func init() { - osCheckCmd.Flags().String("system-dbpath", "", "System db path") - osCheckCmd.Flags().String("system-target", "", "System rootpath") - osCheckCmd.Flags().String("system-engine", "", "System DB engine") + osCheckCmd.Flags().Bool("reinstall", false, "reinstall") - osCheckCmd.Flags().String("solver-type", "", "Solver strategy ( Defaults none, available: "+types.AvailableResolvers+" )") - osCheckCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate") - osCheckCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate") - osCheckCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts") osCheckCmd.Flags().Bool("onlydeps", false, "Consider **only** package dependencies") osCheckCmd.Flags().Bool("force", false, "Skip errors and keep going (potentially harmful)") - osCheckCmd.Flags().Bool("solver-concurrent", false, "Use concurrent solver (experimental)") osCheckCmd.Flags().BoolP("yes", "y", false, "Don't ask questions") osCheckCmd.Flags().Bool("download-only", false, "Download only") diff --git a/cmd/pack.go b/cmd/pack.go index 8ef493e7..fa3e04ec 100644 --- a/cmd/pack.go +++ b/cmd/pack.go @@ -52,7 +52,7 @@ Afterwards, you can use the content generated and associate it with a tree and a dst := viper.GetString("destination") compressionType := viper.GetString("compression") - concurrency := util.DefaultContext.Config.GetGeneral().Concurrency + concurrency := util.DefaultContext.Config.General.Concurrency if len(args) != 1 { util.DefaultContext.Fatal("You must specify a package name") diff --git a/cmd/reclaim.go b/cmd/reclaim.go index f12377ad..ad1c0830 100644 --- a/cmd/reclaim.go +++ b/cmd/reclaim.go @@ -26,7 +26,6 @@ var reclaimCmd = &cobra.Command{ Use: "reclaim", Short: "Reclaim packages to Luet database from available repositories", PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) viper.BindPFlag("force", cmd.Flags().Lookup("force")) }, Long: `Reclaim tries to find association between packages in the online repositories and the system one. @@ -36,21 +35,23 @@ var reclaimCmd = &cobra.Command{ It scans the target file system, and if finds a match with a package available in the repositories, it marks as installed in the system database. `, Run: func(cmd *cobra.Command, args []string) { - util.SetSystemConfig(util.DefaultContext) force := viper.GetBool("force") - util.DefaultContext.Debug("Solver", util.DefaultContext.Config.GetSolverOptions().CompactString()) + util.DefaultContext.Debug("Solver", util.DefaultContext.Config.Solver.CompactString()) inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{ - Concurrency: util.DefaultContext.Config.GetGeneral().Concurrency, + Concurrency: util.DefaultContext.Config.General.Concurrency, Force: force, PreserveSystemEssentialData: true, PackageRepositories: util.DefaultContext.Config.SystemRepositories, Context: util.DefaultContext, }) - system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.GetSystem().Rootfs} + system := &installer.System{ + Database: util.DefaultContext.Config.GetSystemDB(), + Target: util.DefaultContext.Config.System.Rootfs, + } err := inst.Reclaim(system) if err != nil { util.DefaultContext.Fatal("Error: " + err.Error()) @@ -60,10 +61,6 @@ It scans the target file system, and if finds a match with a package available i func init() { - reclaimCmd.Flags().String("system-dbpath", "", "System db path") - reclaimCmd.Flags().String("system-target", "", "System rootpath") - reclaimCmd.Flags().String("system-engine", "", "System DB engine") - reclaimCmd.Flags().Bool("force", false, "Skip errors and keep going (potentially harmful)") RootCmd.AddCommand(reclaimCmd) diff --git a/cmd/reinstall.go b/cmd/reinstall.go index e0e17aae..c3a5443d 100644 --- a/cmd/reinstall.go +++ b/cmd/reinstall.go @@ -15,9 +15,7 @@ package cmd import ( - "github.com/mudler/luet/pkg/api/core/types" installer "github.com/mudler/luet/pkg/installer" - "github.com/mudler/luet/pkg/solver" helpers "github.com/mudler/luet/cmd/helpers" "github.com/mudler/luet/cmd/util" @@ -35,8 +33,6 @@ var reinstallCmd = &cobra.Command{ $ luet reinstall -y system/busybox shells/bash system/coreutils ... `, PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - util.BindSolverFlags(cmd) viper.BindPFlag("onlydeps", cmd.Flags().Lookup("onlydeps")) viper.BindPFlag("force", cmd.Flags().Lookup("force")) viper.BindPFlag("for", cmd.Flags().Lookup("for")) @@ -54,20 +50,11 @@ var reinstallCmd = &cobra.Command{ downloadOnly, _ := cmd.Flags().GetBool("download-only") installed, _ := cmd.Flags().GetBool("installed") - util.SetSystemConfig(util.DefaultContext) - - util.SetSolverConfig(util.DefaultContext) - - util.DefaultContext.Config.GetSolverOptions().Implementation = solver.SingleCoreSimple - - util.DefaultContext.Debug("Solver", util.DefaultContext.Config.GetSolverOptions().CompactString()) - - // Load config protect configs - util.DefaultContext.Config.LoadConfigProtect(util.DefaultContext) + util.DefaultContext.Debug("Solver", util.DefaultContext.Config.Solver.CompactString()) inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{ - Concurrency: util.DefaultContext.Config.GetGeneral().Concurrency, - SolverOptions: *util.DefaultContext.Config.GetSolverOptions(), + Concurrency: util.DefaultContext.Config.General.Concurrency, + SolverOptions: util.DefaultContext.Config.Solver, NoDeps: true, Force: force, OnlyDeps: onlydeps, @@ -78,7 +65,7 @@ var reinstallCmd = &cobra.Command{ PackageRepositories: util.DefaultContext.Config.SystemRepositories, }) - system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.GetSystem().Rootfs} + system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.System.Rootfs} if installed { for _, p := range system.Database.World() { @@ -106,18 +93,8 @@ var reinstallCmd = &cobra.Command{ } func init() { - - reinstallCmd.Flags().String("system-dbpath", "", "System db path") - reinstallCmd.Flags().String("system-target", "", "System rootpath") - reinstallCmd.Flags().String("system-engine", "", "System DB engine") - - reinstallCmd.Flags().String("solver-type", "", "Solver strategy ( Defaults none, available: "+types.AvailableResolvers+" )") - reinstallCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate") - reinstallCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate") - reinstallCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts") reinstallCmd.Flags().Bool("onlydeps", false, "Consider **only** package dependencies") reinstallCmd.Flags().Bool("force", false, "Skip errors and keep going (potentially harmful)") - reinstallCmd.Flags().Bool("solver-concurrent", false, "Use concurrent solver (experimental)") reinstallCmd.Flags().Bool("installed", false, "Reinstall installed packages") reinstallCmd.Flags().BoolP("yes", "y", false, "Don't ask questions") reinstallCmd.Flags().Bool("download-only", false, "Download only") diff --git a/cmd/replace.go b/cmd/replace.go index 641c097c..191c6e4e 100644 --- a/cmd/replace.go +++ b/cmd/replace.go @@ -15,7 +15,6 @@ package cmd import ( - "github.com/mudler/luet/pkg/api/core/types" installer "github.com/mudler/luet/pkg/installer" "github.com/mudler/luet/pkg/solver" @@ -37,8 +36,6 @@ var replaceCmd = &cobra.Command{ $ luet replace -y system/busybox ... --for shells/bash --for system/coreutils ... `, PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - util.BindSolverFlags(cmd) viper.BindPFlag("onlydeps", cmd.Flags().Lookup("onlydeps")) viper.BindPFlag("nodeps", cmd.Flags().Lookup("nodeps")) viper.BindPFlag("force", cmd.Flags().Lookup("force")) @@ -57,8 +54,6 @@ var replaceCmd = &cobra.Command{ yes := viper.GetBool("yes") downloadOnly, _ := cmd.Flags().GetBool("download-only") - util.SetSystemConfig(util.DefaultContext) - util.SetSolverConfig(util.DefaultContext) for _, a := range args { pack, err := helpers.ParsePackageStr(a) if err != nil { @@ -75,16 +70,13 @@ var replaceCmd = &cobra.Command{ toAdd = append(toAdd, pack) } - util.DefaultContext.Config.GetSolverOptions().Implementation = solver.SingleCoreSimple + util.DefaultContext.Config.Solver.Implementation = solver.SingleCoreSimple - util.DefaultContext.Debug("Solver", util.DefaultContext.Config.GetSolverOptions().CompactString()) - - // Load config protect configs - util.DefaultContext.Config.LoadConfigProtect(util.DefaultContext) + util.DefaultContext.Debug("Solver", util.DefaultContext.Config.Solver.CompactString()) inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{ - Concurrency: util.DefaultContext.Config.GetGeneral().Concurrency, - SolverOptions: *util.DefaultContext.Config.GetSolverOptions(), + Concurrency: util.DefaultContext.Config.General.Concurrency, + SolverOptions: util.DefaultContext.Config.Solver, NoDeps: nodeps, Force: force, OnlyDeps: onlydeps, @@ -95,7 +87,7 @@ var replaceCmd = &cobra.Command{ Context: util.DefaultContext, }) - system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.GetSystem().Rootfs} + system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.System.Rootfs} err := inst.Swap(toUninstall, toAdd, system) if err != nil { util.DefaultContext.Fatal("Error: " + err.Error()) @@ -105,18 +97,9 @@ var replaceCmd = &cobra.Command{ func init() { - replaceCmd.Flags().String("system-dbpath", "", "System db path") - replaceCmd.Flags().String("system-target", "", "System rootpath") - replaceCmd.Flags().String("system-engine", "", "System DB engine") - - replaceCmd.Flags().String("solver-type", "", "Solver strategy ( Defaults none, available: "+types.AvailableResolvers+" )") - replaceCmd.Flags().Float32("solver-rate", 0.7, "Solver learning rate") - replaceCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate") - replaceCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts") replaceCmd.Flags().Bool("nodeps", false, "Don't consider package dependencies (harmful!)") replaceCmd.Flags().Bool("onlydeps", false, "Consider **only** package dependencies") replaceCmd.Flags().Bool("force", false, "Skip errors and keep going (potentially harmful)") - replaceCmd.Flags().Bool("solver-concurrent", false, "Use concurrent solver (experimental)") replaceCmd.Flags().BoolP("yes", "y", false, "Don't ask questions") replaceCmd.Flags().StringSlice("for", []string{}, "Packages that has to be installed in place of others") replaceCmd.Flags().Bool("download-only", false, "Download only") diff --git a/cmd/repo/list.go b/cmd/repo/list.go index 909f965b..2f9cb4da 100644 --- a/cmd/repo/list.go +++ b/cmd/repo/list.go @@ -68,7 +68,7 @@ func NewRepoListCommand() *cobra.Command { repoText = pterm.LightYellow(repo.Urls[0]) } - repobasedir := util.DefaultContext.Config.GetSystem().GetRepoDatabaseDirPath(repo.Name) + repobasedir := util.DefaultContext.Config.System.GetRepoDatabaseDirPath(repo.Name) if repo.Cached { r := installer.NewSystemRepository(repo) diff --git a/cmd/root.go b/cmd/root.go index 37426ed2..c0972c57 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -81,19 +81,15 @@ To build a package, from a tree definition: `, Version: version(), PersistentPreRun: func(cmd *cobra.Command, args []string) { - err := util.InitContext(util.DefaultContext) + ctx, err := util.InitContext(cmd) if err != nil { - util.DefaultContext.Error("failed to load configuration:", err.Error()) + fmt.Println("failed to load configuration:", err.Error()) + os.Exit(1) } - util.DisplayVersionBanner(util.DefaultContext, util.IntroScreen, version, license) - // Initialize tmpdir prefix. TODO: Move this with LoadConfig - // directly on sub command to ensure the creation only when it's - // needed. - err = util.DefaultContext.Config.GetSystem().InitTmpDir() - if err != nil { - util.DefaultContext.Fatal("failed on init tmp basedir:", err.Error()) - } + util.DefaultContext = ctx + + util.DisplayVersionBanner(util.DefaultContext, util.IntroScreen, version, license) viper.BindPFlag("plugin", cmd.Flags().Lookup("plugin")) @@ -109,7 +105,7 @@ To build a package, from a tree definition: }, PersistentPostRun: func(cmd *cobra.Command, args []string) { // Cleanup all tmp directories used by luet - err := util.DefaultContext.Config.GetSystem().CleanupTmpDir() + err := util.DefaultContext.Clean() if err != nil { util.DefaultContext.Warning("failed on cleanup tmpdir:", err.Error()) } @@ -129,5 +125,5 @@ func Execute() { } func init() { - util.InitViper(util.DefaultContext, RootCmd) + util.InitViper(RootCmd) } diff --git a/cmd/search.go b/cmd/search.go index 50d4251d..f5c85a79 100644 --- a/cmd/search.go +++ b/cmd/search.go @@ -20,7 +20,6 @@ import ( "github.com/ghodss/yaml" "github.com/mudler/luet/cmd/util" - "github.com/mudler/luet/pkg/api/core/types" installer "github.com/mudler/luet/pkg/installer" pkg "github.com/mudler/luet/pkg/package" "github.com/pterm/pterm" @@ -86,7 +85,7 @@ func packageToList(l *util.ListWriter, repo string, p pkg.Package) { func searchLocally(term string, l *util.ListWriter, t *util.TableWriter, label, labelMatch, revdeps, hidden bool) Results { var results Results - system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.GetSystem().Rootfs} + system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.System.Rootfs} var err error iMatches := pkg.Packages{} @@ -148,8 +147,8 @@ func searchOnline(term string, l *util.ListWriter, t *util.TableWriter, label, l inst := installer.NewLuetInstaller( installer.LuetInstallerOptions{ - Concurrency: util.DefaultContext.Config.GetGeneral().Concurrency, - SolverOptions: *util.DefaultContext.Config.GetSolverOptions(), + Concurrency: util.DefaultContext.Config.General.Concurrency, + SolverOptions: util.DefaultContext.Config.Solver, PackageRepositories: util.DefaultContext.Config.SystemRepositories, Context: util.DefaultContext, }, @@ -238,8 +237,8 @@ func searchFiles(term string, l *util.ListWriter, t *util.TableWriter) Results { inst := installer.NewLuetInstaller( installer.LuetInstallerOptions{ - Concurrency: util.DefaultContext.Config.GetGeneral().Concurrency, - SolverOptions: *util.DefaultContext.Config.GetSolverOptions(), + Concurrency: util.DefaultContext.Config.General.Concurrency, + SolverOptions: util.DefaultContext.Config.Solver, PackageRepositories: util.DefaultContext.Config.SystemRepositories, Context: util.DefaultContext, }, @@ -272,7 +271,11 @@ func searchFiles(term string, l *util.ListWriter, t *util.TableWriter) Results { } var searchCmd = &cobra.Command{ - Use: "search ", + Use: "search ", + // Skip processing output + Annotations: map[string]string{ + util.CommandProcessOutput: "", + }, Short: "Search packages", Long: `Search for installed and available packages @@ -309,8 +312,7 @@ Search can also return results in the terminal in different ways: as terminal ou `, Aliases: []string{"s"}, PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - util.BindSolverFlags(cmd) + viper.BindPFlag("installed", cmd.Flags().Lookup("installed")) }, Run: func(cmd *cobra.Command, args []string) { @@ -329,18 +331,11 @@ Search can also return results in the terminal in different ways: as terminal ou tableMode, _ := cmd.Flags().GetBool("table") files, _ := cmd.Flags().GetBool("files") - util.SetSystemConfig(util.DefaultContext) - util.SetSolverConfig(util.DefaultContext) - out, _ := cmd.Flags().GetString("output") - if out != "terminal" { - util.DefaultContext.Config.GetLogging().SetLogLevel(types.FatalLevel) - } - l := &util.ListWriter{} t := &util.TableWriter{} t.AppendRow(rows) - util.DefaultContext.Debug("Solver", util.DefaultContext.Config.GetSolverOptions().CompactString()) + util.DefaultContext.Debug("Solver", util.DefaultContext.Config.Solver.CompactString()) switch { case files && installed: @@ -383,16 +378,9 @@ Search can also return results in the terminal in different ways: as terminal ou } func init() { - searchCmd.Flags().String("system-dbpath", "", "System db path") - searchCmd.Flags().String("system-target", "", "System rootpath") - searchCmd.Flags().String("system-engine", "", "System DB engine") searchCmd.Flags().Bool("installed", false, "Search between system packages") - searchCmd.Flags().String("solver-type", "", "Solver strategy ( Defaults none, available: "+types.AvailableResolvers+" )") searchCmd.Flags().StringP("output", "o", "terminal", "Output format ( Defaults: terminal, available: json,yaml )") - 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") searchCmd.Flags().Bool("revdeps", false, "Search package reverse dependencies") diff --git a/cmd/tree/images.go b/cmd/tree/images.go index ae76bdd4..001afd5e 100644 --- a/cmd/tree/images.go +++ b/cmd/tree/images.go @@ -38,7 +38,11 @@ import ( func NewTreeImageCommand() *cobra.Command { var ans = &cobra.Command{ - Use: "images [OPTIONS]", + Use: "images [OPTIONS]", + // Skip processing output + Annotations: map[string]string{ + util.CommandProcessOutput: "", + }, Short: "List of the images of a package", PreRun: func(cmd *cobra.Command, args []string) { t, _ := cmd.Flags().GetStringArray("tree") @@ -60,12 +64,7 @@ func NewTreeImageCommand() *cobra.Command { imageRepository := viper.GetString("image-repository") pullRepo, _ := cmd.Flags().GetStringArray("pull-repository") values := util.ValuesFlags() - out, _ := cmd.Flags().GetString("output") - if out != "terminal" { - util.DefaultContext.Config.GetLogging().SetLogLevel("error") - } - reciper := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false)) for _, t := range treePath { @@ -76,7 +75,7 @@ func NewTreeImageCommand() *cobra.Command { } compilerBackend := backend.NewSimpleDockerBackend(util.DefaultContext) - opts := *util.DefaultContext.Config.GetSolverOptions() + opts := util.DefaultContext.Config.Solver opts.Options = solver.Options{Type: solver.SingleCoreSimple, Concurrency: 1} luetCompiler := compiler.NewLuetCompiler( compilerBackend, diff --git a/cmd/tree/pkglist.go b/cmd/tree/pkglist.go index f27242a0..37d865a6 100644 --- a/cmd/tree/pkglist.go +++ b/cmd/tree/pkglist.go @@ -67,6 +67,10 @@ func NewTreePkglistCommand() *cobra.Command { var matches []string var ans = &cobra.Command{ + // Skip processing output + Annotations: map[string]string{ + util.CommandProcessOutput: "", + }, Use: "pkglist [OPTIONS]", Short: "List of the packages found in tree.", Args: cobra.NoArgs, @@ -95,9 +99,6 @@ func NewTreePkglistCommand() *cobra.Command { deps, _ := cmd.Flags().GetBool("deps") out, _ := cmd.Flags().GetString("output") - if out != "terminal" { - util.DefaultContext.Config.GetLogging().SetLogLevel("error") - } var reciper tree.Builder if buildtime { diff --git a/cmd/tree/validate.go b/cmd/tree/validate.go index 972e0dbd..1a71a461 100644 --- a/cmd/tree/validate.go +++ b/cmd/tree/validate.go @@ -255,7 +255,7 @@ func validatePackage(p pkg.Package, checkType string, opts *ValidateOpts, recipe r.GetCategory(), r.GetName(), r.GetVersion(), )) - if util.DefaultContext.Config.GetGeneral().Debug { + if util.DefaultContext.Config.General.Debug { for idx, pa := range solution { fmt.Println(fmt.Sprintf("[%9s] %s/%s-%s: solution %d: %s", checkType, @@ -426,7 +426,7 @@ func NewTreeValidateCommand() *cobra.Command { Run: func(cmd *cobra.Command, args []string) { var reciper tree.Builder - concurrency := util.DefaultContext.Config.GetGeneral().Concurrency + concurrency := util.DefaultContext.Config.General.Concurrency withSolver, _ := cmd.Flags().GetBool("with-solver") onlyRuntime, _ := cmd.Flags().GetBool("only-runtime") diff --git a/cmd/uninstall.go b/cmd/uninstall.go index 79c93bd6..c0247f18 100644 --- a/cmd/uninstall.go +++ b/cmd/uninstall.go @@ -17,7 +17,6 @@ package cmd import ( helpers "github.com/mudler/luet/cmd/helpers" "github.com/mudler/luet/cmd/util" - "github.com/mudler/luet/pkg/api/core/types" installer "github.com/mudler/luet/pkg/installer" pkg "github.com/mudler/luet/pkg/package" "github.com/mudler/luet/pkg/solver" @@ -32,8 +31,7 @@ var uninstallCmd = &cobra.Command{ Long: `Uninstall packages`, Aliases: []string{"rm", "un"}, PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - util.BindSolverFlags(cmd) + viper.BindPFlag("nodeps", cmd.Flags().Lookup("nodeps")) viper.BindPFlag("force", cmd.Flags().Lookup("force")) viper.BindPFlag("yes", cmd.Flags().Lookup("yes")) @@ -57,21 +55,15 @@ var uninstallCmd = &cobra.Command{ yes := viper.GetBool("yes") keepProtected, _ := cmd.Flags().GetBool("keep-protected-files") - util.SetSystemConfig(util.DefaultContext) - util.SetSolverConfig(util.DefaultContext) - util.DefaultContext.Config.ConfigProtectSkip = !keepProtected - util.DefaultContext.Config.GetSolverOptions().Implementation = solver.SingleCoreSimple + util.DefaultContext.Config.Solver.Implementation = solver.SingleCoreSimple - util.DefaultContext.Debug("Solver", util.DefaultContext.Config.GetSolverOptions().CompactString()) - - // Load config protect configs - util.DefaultContext.Config.LoadConfigProtect(util.DefaultContext) + util.DefaultContext.Debug("Solver", util.DefaultContext.Config.Solver.CompactString()) inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{ - Concurrency: util.DefaultContext.Config.GetGeneral().Concurrency, - SolverOptions: *util.DefaultContext.Config.GetSolverOptions(), + Concurrency: util.DefaultContext.Config.General.Concurrency, + SolverOptions: util.DefaultContext.Config.Solver, NoDeps: nodeps, Force: force, FullUninstall: full, @@ -82,7 +74,7 @@ var uninstallCmd = &cobra.Command{ Context: util.DefaultContext, }) - system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.GetSystem().Rootfs} + system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.System.Rootfs} if err := inst.Uninstall(system, toRemove...); err != nil { util.DefaultContext.Fatal("Error: " + err.Error()) @@ -92,14 +84,6 @@ var uninstallCmd = &cobra.Command{ func init() { - uninstallCmd.Flags().String("system-dbpath", "", "System db path") - uninstallCmd.Flags().String("system-target", "", "System rootpath") - uninstallCmd.Flags().String("system-engine", "", "System DB engine") - - uninstallCmd.Flags().String("solver-type", "", "Solver strategy ( Defaults none, available: "+types.AvailableResolvers+" )") - 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! overrides checkconflicts and full!)") uninstallCmd.Flags().Bool("force", false, "Force uninstall") uninstallCmd.Flags().Bool("full", false, "Attempts to remove as much packages as possible which aren't required (slow)") diff --git a/cmd/upgrade.go b/cmd/upgrade.go index fd139f27..971eaa84 100644 --- a/cmd/upgrade.go +++ b/cmd/upgrade.go @@ -16,7 +16,6 @@ package cmd import ( "github.com/mudler/luet/cmd/util" - "github.com/mudler/luet/pkg/api/core/types" installer "github.com/mudler/luet/pkg/installer" "github.com/mudler/luet/pkg/solver" @@ -29,8 +28,7 @@ var upgradeCmd = &cobra.Command{ Short: "Upgrades the system", Aliases: []string{"u"}, PreRun: func(cmd *cobra.Command, args []string) { - util.BindSystemFlags(cmd) - util.BindSolverFlags(cmd) + viper.BindPFlag("force", cmd.Flags().Lookup("force")) viper.BindPFlag("yes", cmd.Flags().Lookup("yes")) }, @@ -48,19 +46,13 @@ var upgradeCmd = &cobra.Command{ yes := viper.GetBool("yes") downloadOnly, _ := cmd.Flags().GetBool("download-only") - util.SetSystemConfig(util.DefaultContext) - opts := util.SetSolverConfig(util.DefaultContext) + util.DefaultContext.Config.Solver.Implementation = solver.SingleCoreSimple - util.DefaultContext.Config.GetSolverOptions().Implementation = solver.SingleCoreSimple - - util.DefaultContext.Debug("Solver", opts.CompactString()) - - // Load config protect configs - util.DefaultContext.Config.LoadConfigProtect(util.DefaultContext) + util.DefaultContext.Debug("Solver", util.DefaultContext.GetConfig().Solver) inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{ - Concurrency: util.DefaultContext.Config.GetGeneral().Concurrency, - SolverOptions: *util.DefaultContext.Config.GetSolverOptions(), + Concurrency: util.DefaultContext.Config.General.Concurrency, + SolverOptions: util.DefaultContext.Config.Solver, Force: force, FullUninstall: full, NoDeps: nodeps, @@ -75,7 +67,7 @@ var upgradeCmd = &cobra.Command{ Context: util.DefaultContext, }) - system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.GetSystem().Rootfs} + system := &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.System.Rootfs} if err := inst.Upgrade(system); err != nil { util.DefaultContext.Fatal("Error: " + err.Error()) } @@ -83,14 +75,6 @@ var upgradeCmd = &cobra.Command{ } func init() { - upgradeCmd.Flags().String("system-dbpath", "", "System db path") - upgradeCmd.Flags().String("system-target", "", "System rootpath") - upgradeCmd.Flags().String("system-engine", "", "System DB engine") - - upgradeCmd.Flags().String("solver-type", "", "Solver strategy ( Defaults none, available: "+types.AvailableResolvers+" )") - 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") upgradeCmd.Flags().Bool("nodeps", false, "Don't consider package dependencies (harmful! overrides checkconflicts and full!)") upgradeCmd.Flags().Bool("full", false, "Attempts to remove as much packages as possible which aren't required (slow)") diff --git a/cmd/util.go b/cmd/util.go index ac766d16..5356a651 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -24,19 +24,19 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/go-units" "github.com/mudler/luet/pkg/api/core/image" - luettypes "github.com/mudler/luet/pkg/api/core/types" fileHelper "github.com/mudler/luet/pkg/helpers/file" "github.com/pkg/errors" "github.com/mudler/luet/cmd/util" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/helpers/docker" "github.com/spf13/cobra" ) -func pack(ctx *luettypes.Context, p, dst, imageName, arch, OS string) error { +func pack(ctx *context.Context, p, dst, imageName, arch, OS string) error { - tempimage, err := ctx.Config.GetSystem().TempFile("tempimage") + tempimage, err := ctx.TempFile("tempimage") if err != nil { return errors.Wrap(err, "error met while creating tempdir for "+p) } diff --git a/cmd/util/cli.go b/cmd/util/cli.go index 75cebc83..d81e210d 100644 --- a/cmd/util/cli.go +++ b/cmd/util/cli.go @@ -16,7 +16,6 @@ package util import ( - "errors" "os" "path/filepath" "strings" @@ -26,28 +25,14 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/api/core/types" "github.com/mudler/luet/pkg/installer" ) -var DefaultContext = types.NewContext() - var lockedCommands = []string{"install", "uninstall", "upgrade"} var bannerCommands = []string{"install", "build", "uninstall", "upgrade"} -func BindSystemFlags(cmd *cobra.Command) { - viper.BindPFlag("system.database_path", cmd.Flags().Lookup("system-dbpath")) - viper.BindPFlag("system.rootfs", cmd.Flags().Lookup("system-target")) - viper.BindPFlag("system.database_engine", cmd.Flags().Lookup("system-engine")) -} - -func BindSolverFlags(cmd *cobra.Command) { - viper.BindPFlag("solver.type", cmd.Flags().Lookup("solver-type")) - viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount")) - viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate")) - viper.BindPFlag("solver.max_attempts", cmd.Flags().Lookup("solver-attempts")) -} - func BindValuesFlags(cmd *cobra.Command) { viper.BindPFlag("values", cmd.Flags().Lookup("values")) } @@ -56,59 +41,14 @@ func ValuesFlags() []string { return viper.GetStringSlice("values") } -func SetSystemConfig(ctx *types.Context) { - dbpath := viper.GetString("system.database_path") - rootfs := viper.GetString("system.rootfs") - engine := viper.GetString("system.database_engine") - - ctx.Config.System.DatabaseEngine = engine - ctx.Config.System.DatabasePath = dbpath - ctx.Config.System.SetRootFS(rootfs) -} - -func SetSolverConfig(ctx *types.Context) (c *types.LuetSolverOptions) { - stype := viper.GetString("solver.type") - discount := viper.GetFloat64("solver.discount") - rate := viper.GetFloat64("solver.rate") - attempts := viper.GetInt("solver.max_attempts") - - ctx.Config.GetSolverOptions().Type = stype - ctx.Config.GetSolverOptions().LearnRate = float32(rate) - ctx.Config.GetSolverOptions().Discount = float32(discount) - ctx.Config.GetSolverOptions().MaxAttempts = attempts - - return &types.LuetSolverOptions{ - Type: stype, - LearnRate: float32(rate), - Discount: float32(discount), - MaxAttempts: attempts, - } -} - -func SetCliFinalizerEnvs(ctx *types.Context, finalizerEnvs []string) error { - if len(finalizerEnvs) > 0 { - for _, v := range finalizerEnvs { - idx := strings.Index(v, "=") - if idx < 0 { - return errors.New("Found invalid runtime finalizer environment: " + v) - } - - ctx.Config.SetFinalizerEnv(v[0:idx], v[idx+1:]) - } - - } - - return nil -} - // TemplateFolders returns the default folders which holds shared template between packages in a given tree path -func TemplateFolders(ctx *types.Context, fromRepo bool, treePaths []string) []string { +func TemplateFolders(ctx *context.Context, fromRepo bool, treePaths []string) []string { templateFolders := []string{} for _, t := range treePaths { templateFolders = append(templateFolders, filepath.Join(t, "templates")) } if fromRepo { - for _, s := range installer.SystemRepositories(ctx.Config.SystemRepositories) { + for _, s := range installer.SystemRepositories(ctx.GetConfig().SystemRepositories) { templateFolders = append(templateFolders, filepath.Join(s.TreePath, "templates")) } } @@ -126,7 +66,7 @@ func IntroScreen() { pterm.DefaultCenter.Print(pterm.DefaultHeader.WithFullWidth().WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Sprint("Luet - 0-deps container-based package manager")) } -func HandleLock(c *types.Context) { +func HandleLock(c types.Context) { if os.Getenv("LUET_NOLOCK") != "true" { if len(os.Args) > 1 { for _, lockedCmd := range lockedCommands { @@ -146,7 +86,7 @@ func HandleLock(c *types.Context) { } } -func DisplayVersionBanner(c *types.Context, banner func(), version func() string, license []string) { +func DisplayVersionBanner(c *context.Context, banner func(), version func() string, license []string) { display := false if len(os.Args) > 1 { for _, c := range bannerCommands { diff --git a/cmd/util/config.go b/cmd/util/config.go index fcd5d07c..8fab8d3f 100644 --- a/cmd/util/config.go +++ b/cmd/util/config.go @@ -16,6 +16,7 @@ package util import ( + "errors" "fmt" "os" "os/user" @@ -23,8 +24,15 @@ import ( "runtime" "strings" + "github.com/ipfs/go-log/v2" extensions "github.com/mudler/cobra-extensions" + "github.com/mudler/luet/pkg/api/core/context" + gc "github.com/mudler/luet/pkg/api/core/garbagecollector" + "github.com/mudler/luet/pkg/api/core/logger" "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/solver" + "github.com/pterm/pterm" + "go.uber.org/zap/zapcore" helpers "github.com/mudler/luet/pkg/helpers" fileHelper "github.com/mudler/luet/pkg/helpers/file" @@ -87,26 +95,117 @@ func initConfig() { } +var DefaultContext *context.Context + // InitContext inits the context by parsing the configurations from viper // this is meant to be run before each command to be able to parse any override from // the CLI/ENV -func InitContext(ctx *types.Context) (err error) { +func InitContext(cmd *cobra.Command) (ctx *context.Context, err error) { - err = viper.Unmarshal(&ctx.Config) + c := &types.LuetConfig{} + err = viper.Unmarshal(c) if err != nil { return } + // Converts user-defined config into paths + // and creates the required directory on the system if necessary + c.Init() + + finalizerEnvs, _ := cmd.Flags().GetStringArray("finalizer-env") + setCliFinalizerEnvs(c, finalizerEnvs) + + c.Solver.Options = solver.Options{Type: solver.SingleCoreSimple, Concurrency: c.General.Concurrency} + + ctx = context.NewContext( + context.WithConfig(c), + context.WithGarbageCollector(gc.GarbageCollector(c.System.TmpDirBase)), + ) + // Inits the context with the configurations loaded // It reads system repositories, sets logging, and all the // context which is required to perform luet actions - err = ctx.Init() - if err != nil { - return + return ctx, initContext(cmd, ctx) +} + +func setCliFinalizerEnvs(c *types.LuetConfig, finalizerEnvs []string) error { + if len(finalizerEnvs) > 0 { + for _, v := range finalizerEnvs { + idx := strings.Index(v, "=") + if idx < 0 { + return errors.New("Found invalid runtime finalizer environment: " + v) + } + + c.SetFinalizerEnv(v[0:idx], v[idx+1:]) + } } - // no_spinner is not mapped in our configs - ctx.NoSpinner = viper.GetBool("no_spinner") + return nil +} + +const ( + CommandProcessOutput = "command.process.output" +) + +func initContext(cmd *cobra.Command, c *context.Context) (err error) { + if logger.IsTerminal() { + if !c.Config.Logging.Color { + pterm.DisableColor() + } + } else { + pterm.DisableColor() + c.Debug("Not a terminal, colors disabled") + } + + if c.Config.General.Quiet { + pterm.DisableColor() + pterm.DisableStyling() + } + + level := c.Config.Logging.Level + if c.Config.General.Debug { + level = "debug" + } + + if _, ok := cmd.Annotations[CommandProcessOutput]; ok { + // Note: create-repo output is different, so we annotate in the cmd of create-repo CommandNoProcess + // to avoid + out, _ := cmd.Flags().GetString("output") + if out != "terminal" { + level = zapcore.Level(log.LevelFatal).String() + } + } + + // Init logging + opts := []logger.LoggerOptions{ + logger.WithLevel(level), + } + + if c.Config.Logging.NoSpinner { + opts = append(opts, logger.NoSpinner) + } + + if c.Config.Logging.EnableLogFile && c.Config.Logging.Path != "" { + f := "console" + if c.Config.Logging.JsonFormat { + f = "json" + } + opts = append(opts, logger.WithFileLogging(c.Config.Logging.Path, f)) + } + + if c.Config.Logging.EnableEmoji { + opts = append(opts, logger.EnableEmoji()) + } + + l, err := logger.New(opts...) + + c.Logger = l + + c.Debug("System rootfs:", c.Config.System.Rootfs) + c.Debug("Colors", c.Config.Logging.Color) + c.Debug("Logging level", c.Config.Logging.Level) + c.Debug("Debug mode", c.Config.General.Debug) + return } @@ -156,7 +255,7 @@ func setDefaults(viper *viper.Viper) { // InitViper inits a new viper // this is meant to be run just once at beginning to setup the root command -func InitViper(ctx *types.Context, RootCmd *cobra.Command) { +func InitViper(RootCmd *cobra.Command) { cobra.OnInitialize(initConfig) pflags := RootCmd.PersistentFlags() pflags.StringVar(&cfgFile, "config", "", "config file (default is $HOME/.luet.yaml)") @@ -165,29 +264,38 @@ func InitViper(ctx *types.Context, RootCmd *cobra.Command) { pflags.Bool("fatal", false, "Enables Warnings to exit") pflags.Bool("enable-logfile", false, "Enable log to file") pflags.Bool("no-spinner", false, "Disable spinner.") - pflags.Bool("color", ctx.Config.GetLogging().Color, "Enable/Disable color.") - pflags.Bool("emoji", ctx.Config.GetLogging().EnableEmoji, "Enable/Disable emoji.") - pflags.Bool("skip-config-protect", ctx.Config.ConfigProtectSkip, - "Disable config protect analysis.") - pflags.StringP("logfile", "l", ctx.Config.GetLogging().Path, - "Logfile path. Empty value disable log to file.") + pflags.Bool("color", true, "Enable/Disable color.") + pflags.Bool("emoji", true, "Enable/Disable emoji.") + pflags.Bool("skip-config-protect", true, "Disable config protect analysis.") + pflags.StringP("logfile", "l", "", "Logfile path. Empty value disable log to file.") pflags.StringSlice("plugin", []string{}, "A list of runtime plugins to load") - // os/user doesn't work in from scratch environments. - // Check if i can retrieve user informations. - _, err := user.Current() - if err != nil { - ctx.Warning("failed to retrieve user identity:", err.Error()) - } - pflags.Bool("same-owner", ctx.Config.GetGeneral().SameOwner, "Maintain same owner on uncompress.") + pflags.String("system-dbpath", "", "System db path") + pflags.String("system-target", "", "System rootpath") + pflags.String("system-engine", "", "System DB engine") + + pflags.String("solver-type", "", "Solver strategy ( Defaults none, available: "+types.AvailableResolvers+" )") + pflags.Float32("solver-rate", 0.7, "Solver learning rate") + pflags.Float32("solver-discount", 1.0, "Solver discount rate") + pflags.Int("solver-attempts", 9000, "Solver maximum attempts") + + pflags.Bool("same-owner", true, "Maintain same owner on uncompress.") pflags.Int("concurrency", runtime.NumCPU(), "Concurrency") - pflags.Int("http-timeout", ctx.Config.General.HTTPTimeout, "Default timeout for http(s) requests") + pflags.Int("http-timeout", 360, "Default timeout for http(s) requests") + + viper.BindPFlag("system.database_path", pflags.Lookup("system-dbpath")) + viper.BindPFlag("system.rootfs", pflags.Lookup("system-target")) + viper.BindPFlag("system.database_engine", pflags.Lookup("system-engine")) + viper.BindPFlag("solver.type", pflags.Lookup("solver-type")) + viper.BindPFlag("solver.discount", pflags.Lookup("solver-discount")) + viper.BindPFlag("solver.rate", pflags.Lookup("solver-rate")) + viper.BindPFlag("solver.max_attempts", pflags.Lookup("solver-attempts")) viper.BindPFlag("logging.color", pflags.Lookup("color")) viper.BindPFlag("logging.enable_emoji", pflags.Lookup("emoji")) viper.BindPFlag("logging.enable_logfile", pflags.Lookup("enable-logfile")) viper.BindPFlag("logging.path", pflags.Lookup("logfile")) - + viper.BindPFlag("logging.no_spinner", pflags.Lookup("no-spinner")) viper.BindPFlag("general.concurrency", pflags.Lookup("concurrency")) viper.BindPFlag("general.debug", pflags.Lookup("debug")) viper.BindPFlag("general.quiet", pflags.Lookup("quiet")) diff --git a/go.mod b/go.mod index d7ac5bdc..f1bed53d 100644 --- a/go.mod +++ b/go.mod @@ -30,12 +30,14 @@ require ( github.com/hashicorp/go-version v1.3.0 github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.12 + github.com/ipfs/go-log/v2 v2.4.0 github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 github.com/klauspost/compress v1.13.0 github.com/klauspost/pgzip v1.2.5 github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d github.com/kyokomi/emoji v2.1.0+incompatible github.com/marcsauter/single v0.0.0-20181104081128-f8bf46f26ec0 + github.com/mattn/go-isatty v0.0.14 github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/hashstructure/v2 v2.0.1 github.com/mitchellh/mapstructure v1.4.2 // indirect @@ -65,7 +67,7 @@ require ( golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect golang.org/x/mod v0.4.2 golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5 // indirect - golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 + golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect google.golang.org/genproto v0.0.0-20210811021853-ddbe55d93216 // indirect diff --git a/go.sum b/go.sum index 7e0521a7..8d44f4ef 100644 --- a/go.sum +++ b/go.sum @@ -663,6 +663,8 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/ipfs/go-log/v2 v2.4.0 h1:iR/2o9PGWanVJrBgIH5Ff8mPGOwpqLaPIAFqSnsdlzk= +github.com/ipfs/go-log/v2 v2.4.0/go.mod h1:nPZnh7Cj7lwS3LpRU5Mwr2ol1c2gXIEXuF6aywqrtmo= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 h1:sHsPfNMAG70QAvKbddQ0uScZCHQoZsT5NykGRCeeeIs= @@ -747,6 +749,8 @@ github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHef github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -1139,15 +1143,18 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= diff --git a/pkg/api/core/bus/events.go b/pkg/api/core/bus/events.go index cee2eb50..52ea2dcd 100644 --- a/pkg/api/core/bus/events.go +++ b/pkg/api/core/bus/events.go @@ -90,7 +90,7 @@ type Bus struct { *pluggable.Manager } -func (b *Bus) Initialize(ctx *types.Context, plugin ...string) { +func (b *Bus) Initialize(ctx types.Context, plugin ...string) { b.Manager.Load(plugin...).Register() for _, e := range b.Manager.Events { diff --git a/pkg/api/core/config/config_protect_test.go b/pkg/api/core/config/config_protect_test.go index 43183c8d..bdd6f813 100644 --- a/pkg/api/core/config/config_protect_test.go +++ b/pkg/api/core/config/config_protect_test.go @@ -18,7 +18,7 @@ package config_test import ( config "github.com/mudler/luet/pkg/api/core/config" - "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/context" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -29,7 +29,7 @@ var _ = Describe("Config", func() { Context("Test config protect", func() { It("Protect1", func() { - ctx := types.NewContext() + ctx := context.NewContext() files := []string{ "etc/foo/my.conf", "usr/bin/foo", @@ -59,7 +59,7 @@ var _ = Describe("Config", func() { }) It("Protect2", func() { - ctx := types.NewContext() + ctx := context.NewContext() files := []string{ "etc/foo/my.conf", @@ -86,7 +86,7 @@ var _ = Describe("Config", func() { }) It("Protect3: Annotation dir without initial slash", func() { - ctx := types.NewContext() + ctx := context.NewContext() files := []string{ "etc/foo/my.conf", diff --git a/pkg/api/core/context/contest_suite_test.go b/pkg/api/core/context/contest_suite_test.go new file mode 100644 index 00000000..ea4423ec --- /dev/null +++ b/pkg/api/core/context/contest_suite_test.go @@ -0,0 +1,28 @@ +// Copyright © 2021 Ettore Di Giacinto +// +// 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 . + +package context_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestContext(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Context Suite") +} diff --git a/pkg/api/core/context/context.go b/pkg/api/core/context/context.go new file mode 100644 index 00000000..14b2db37 --- /dev/null +++ b/pkg/api/core/context/context.go @@ -0,0 +1,159 @@ +// Copyright © 2021 Ettore Di Giacinto +// +// 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 . + +package context + +import ( + "context" + "os" + "path/filepath" + + fileHelper "github.com/mudler/luet/pkg/helpers/file" + + gc "github.com/mudler/luet/pkg/api/core/garbagecollector" + "github.com/mudler/luet/pkg/api/core/logger" + "github.com/mudler/luet/pkg/api/core/types" + + "github.com/pkg/errors" +) + +type Context struct { + *logger.Logger + context.Context + types.GarbageCollector + Config *types.LuetConfig + NoSpinner bool + annotations map[string]interface{} +} + +// SetAnnotation sets generic annotations to hold in a context +func (c *Context) SetAnnotation(s string, i interface{}) { + c.annotations[s] = i +} + +// GetAnnotation gets generic annotations to hold in a context +func (c *Context) GetAnnotation(s string) interface{} { + return c.annotations[s] +} + +type ContextOption func(c *Context) error + +// WithLogger sets the logger +func WithLogger(l *logger.Logger) ContextOption { + return func(c *Context) error { + c.Logger = l + return nil + } +} + +// WithConfig sets the luet config +func WithConfig(cc *types.LuetConfig) ContextOption { + return func(c *Context) error { + c.Config = cc + return nil + } +} + +// NOTE: GC needs to be instantiated when a new context is created from system TmpDirBase + +// WithGarbageCollector sets the Garbage collector for the given context +func WithGarbageCollector(l types.GarbageCollector) ContextOption { + return func(c *Context) error { + if !filepath.IsAbs(l.String()) { + abs, err := fileHelper.Rel2Abs(l.String()) + if err != nil { + return errors.Wrap(err, "while converting relative path to absolute path") + } + l = gc.GarbageCollector(abs) + } + + c.GarbageCollector = l + return nil + } +} + +// NewContext returns a new context. +// It accepts a Garbage collector, a config and a logger as an option +func NewContext(opts ...ContextOption) *Context { + l, _ := logger.New() + d := &Context{ + annotations: make(map[string]interface{}), + Logger: l, + GarbageCollector: gc.GarbageCollector(filepath.Join(os.TempDir(), "tmpluet")), + Config: &types.LuetConfig{ + ConfigFromHost: true, + Logging: types.LuetLoggingConfig{}, + General: types.LuetGeneralConfig{}, + System: types.LuetSystemConfig{ + DatabasePath: filepath.Join("var", "db"), + PkgsCachePath: filepath.Join("var", "db", "packages"), + }, + Solver: types.LuetSolverOptions{}, + }, + } + + for _, o := range opts { + o(d) + } + return d +} + +// WithLoggingContext returns a copy of the context with a contextualized logger +func (c *Context) WithLoggingContext(name string) types.Context { + configCopy := *c.Config + configCopy.System = c.Config.System + configCopy.General = c.Config.General + configCopy.Logging = c.Config.Logging + + ctx := *c + ctxCopy := &ctx + ctxCopy.Config = &configCopy + ctxCopy.annotations = ctx.annotations + + ctxCopy.Logger, _ = c.Logger.Copy(logger.WithContext(name)) + + return ctxCopy +} + +// Copy returns a context copy with a reset logging context +func (c *Context) Copy() types.Context { + return c.WithLoggingContext("") +} + +func (c *Context) Warning(mess ...interface{}) { + c.Logger.Warn(mess...) + if c.Config.General.FatalWarns { + os.Exit(2) + } +} + +func (c *Context) Warn(mess ...interface{}) { + c.Warning(mess...) +} + +func (c *Context) Warnf(t string, mess ...interface{}) { + c.Logger.Warnf(t, mess...) + if c.Config.General.FatalWarns { + os.Exit(2) + } +} + +func (c *Context) Warningf(t string, mess ...interface{}) { + c.Warnf(t, mess...) +} + +func (c *Context) GetConfig() types.LuetConfig { + return *c.Config +} diff --git a/pkg/api/core/garbagecollector/garbagecollector.go b/pkg/api/core/garbagecollector/garbagecollector.go new file mode 100644 index 00000000..197b82d6 --- /dev/null +++ b/pkg/api/core/garbagecollector/garbagecollector.go @@ -0,0 +1,59 @@ +// Copyright © 2021 Ettore Di Giacinto +// +// 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 . + +package gc + +import ( + "io/ioutil" + "os" +) + +type GarbageCollector string + +func (c GarbageCollector) String() string { + return string(c) +} + +func (c GarbageCollector) init() error { + if _, err := os.Stat(string(c)); err != nil { + if os.IsNotExist(err) { + err = os.MkdirAll(string(c), os.ModePerm) + if err != nil { + return err + } + } + } + return nil +} + +func (c GarbageCollector) Clean() error { + return os.RemoveAll(string(c)) +} + +func (c GarbageCollector) TempDir(pattern string) (string, error) { + err := c.init() + if err != nil { + return "", err + } + return ioutil.TempDir(string(c), pattern) +} + +func (c GarbageCollector) TempFile(s string) (*os.File, error) { + err := c.init() + if err != nil { + return nil, err + } + return ioutil.TempFile(string(c), s) +} diff --git a/pkg/api/core/image/cache_test.go b/pkg/api/core/image/cache_test.go index 4616f30a..d18bc483 100644 --- a/pkg/api/core/image/cache_test.go +++ b/pkg/api/core/image/cache_test.go @@ -18,8 +18,8 @@ package image_test import ( "path/filepath" + "github.com/mudler/luet/pkg/api/core/context" . "github.com/mudler/luet/pkg/api/core/image" - "github.com/mudler/luet/pkg/api/core/types" "github.com/mudler/luet/pkg/helpers/file" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -27,16 +27,16 @@ import ( var _ = Describe("Cache", func() { - ctx := types.NewContext() + ctx := context.NewContext() Context("used as k/v store", func() { cache := &Cache{} var dir string BeforeEach(func() { - ctx = types.NewContext() + ctx = context.NewContext() var err error - dir, err = ctx.Config.System.TempDir("foo") + dir, err = ctx.TempDir("foo") Expect(err).ToNot(HaveOccurred()) cache = NewCache(dir, 10*1024*1024, 1) // 10MB Cache when upgrading to files. Max volatile memory of 1 row. }) diff --git a/pkg/api/core/image/create_test.go b/pkg/api/core/image/create_test.go index eb1ac999..a5cfe4c2 100644 --- a/pkg/api/core/image/create_test.go +++ b/pkg/api/core/image/create_test.go @@ -20,8 +20,8 @@ import ( "path/filepath" "runtime" + "github.com/mudler/luet/pkg/api/core/context" . "github.com/mudler/luet/pkg/api/core/image" - "github.com/mudler/luet/pkg/api/core/types" "github.com/mudler/luet/pkg/api/core/types/artifact" "github.com/mudler/luet/pkg/compiler/backend" "github.com/mudler/luet/pkg/helpers/file" @@ -32,12 +32,12 @@ import ( var _ = Describe("Create", func() { Context("Creates an OCI image from a standard tar", func() { It("creates an image which is loadable", func() { - ctx := types.NewContext() + ctx := context.NewContext() - dst, err := ctx.Config.System.TempFile("dst") + dst, err := ctx.TempFile("dst") Expect(err).ToNot(HaveOccurred()) defer os.RemoveAll(dst.Name()) - srcTar, err := ctx.Config.System.TempFile("srcTar") + srcTar, err := ctx.TempFile("srcTar") Expect(err).ToNot(HaveOccurred()) defer os.RemoveAll(srcTar.Name()) diff --git a/pkg/api/core/image/delta_test.go b/pkg/api/core/image/delta_test.go index 922eea42..2fcc21ae 100644 --- a/pkg/api/core/image/delta_test.go +++ b/pkg/api/core/image/delta_test.go @@ -23,8 +23,8 @@ import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" daemon "github.com/google/go-containerregistry/pkg/v1/daemon" + "github.com/mudler/luet/pkg/api/core/context" . "github.com/mudler/luet/pkg/api/core/image" - "github.com/mudler/luet/pkg/api/core/types" "github.com/mudler/luet/pkg/helpers/file" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -47,7 +47,7 @@ var _ = Describe("Delta", func() { }) Context("ExtractDeltaFiles", func() { - ctx := types.NewContext() + ctx := context.NewContext() var tmpfile *os.File var ref, ref2 name.Reference var img, img2 v1.Image @@ -59,7 +59,7 @@ var _ = Describe("Delta", func() { img2, _ = daemon.Image(ref2) BeforeEach(func() { - ctx = types.NewContext() + ctx = context.NewContext() tmpfile, err = ioutil.TempFile("", "delta") Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/api/core/image/extract.go b/pkg/api/core/image/extract.go index 4c5f9478..cbfc7425 100644 --- a/pkg/api/core/image/extract.go +++ b/pkg/api/core/image/extract.go @@ -35,7 +35,7 @@ import ( // considering the added files only, and applies a filter on them based on the regexes // in the lists. func ExtractDeltaAdditionsFiles( - ctx *types.Context, + ctx types.Context, srcimg v1.Image, includes []string, excludes []string, ) (func(h *tar.Header) (bool, error), error) { @@ -43,7 +43,7 @@ func ExtractDeltaAdditionsFiles( includeRegexp := compileRegexes(includes) excludeRegexp := compileRegexes(excludes) - srcfilesd, err := ctx.Config.System.TempDir("srcfiles") + srcfilesd, err := ctx.TempDir("srcfiles") if err != nil { return nil, err } @@ -128,7 +128,7 @@ func ExtractDeltaAdditionsFiles( // It then filters files by an include and exclude list. // The list can be regexes func ExtractFiles( - ctx *types.Context, + ctx types.Context, prefixPath string, includes []string, excludes []string, ) func(h *tar.Header) (bool, error) { @@ -193,7 +193,7 @@ func ExtractFiles( // ExtractReader perform the extracting action over the io.ReadCloser // it extracts the files over output. Accepts a filter as an option // and additional containerd Options -func ExtractReader(ctx *types.Context, reader io.ReadCloser, output string, filter func(h *tar.Header) (bool, error), opts ...containerdarchive.ApplyOpt) (int64, string, error) { +func ExtractReader(ctx types.Context, reader io.ReadCloser, output string, filter func(h *tar.Header) (bool, error), opts ...containerdarchive.ApplyOpt) (int64, string, error) { defer reader.Close() // If no filter is specified, grab all. @@ -213,8 +213,8 @@ func ExtractReader(ctx *types.Context, reader io.ReadCloser, output string, filt } // Extract is just syntax sugar around ExtractReader. It extracts an image into a dir -func Extract(ctx *types.Context, img v1.Image, filter func(h *tar.Header) (bool, error), opts ...containerdarchive.ApplyOpt) (int64, string, error) { - tmpdiffs, err := ctx.Config.GetSystem().TempDir("extraction") +func Extract(ctx types.Context, img v1.Image, filter func(h *tar.Header) (bool, error), opts ...containerdarchive.ApplyOpt) (int64, string, error) { + tmpdiffs, err := ctx.TempDir("extraction") if err != nil { return 0, "", errors.Wrap(err, "Error met while creating tempdir for rootfs") } @@ -222,6 +222,6 @@ func Extract(ctx *types.Context, img v1.Image, filter func(h *tar.Header) (bool, } // ExtractTo is just syntax sugar around ExtractReader -func ExtractTo(ctx *types.Context, img v1.Image, output string, filter func(h *tar.Header) (bool, error), opts ...containerdarchive.ApplyOpt) (int64, string, error) { +func ExtractTo(ctx types.Context, img v1.Image, output string, filter func(h *tar.Header) (bool, error), opts ...containerdarchive.ApplyOpt) (int64, string, error) { return ExtractReader(ctx, mutate.Extract(img), output, filter, opts...) } diff --git a/pkg/api/core/image/extract_test.go b/pkg/api/core/image/extract_test.go index 4a4ebaec..4dbda826 100644 --- a/pkg/api/core/image/extract_test.go +++ b/pkg/api/core/image/extract_test.go @@ -23,8 +23,8 @@ import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" daemon "github.com/google/go-containerregistry/pkg/v1/daemon" + "github.com/mudler/luet/pkg/api/core/context" . "github.com/mudler/luet/pkg/api/core/image" - "github.com/mudler/luet/pkg/api/core/types" "github.com/mudler/luet/pkg/helpers/file" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -34,14 +34,14 @@ var _ = Describe("Extract", func() { Context("extract files from images", func() { Context("ExtractFiles", func() { - ctx := types.NewContext() + ctx := context.NewContext() var tmpfile *os.File var ref name.Reference var img v1.Image var err error BeforeEach(func() { - ctx = types.NewContext() + ctx = context.NewContext() tmpfile, err = ioutil.TempFile("", "extract") Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/api/core/image/mutator_suite_test.go b/pkg/api/core/image/mutator_suite_test.go index 70a6fa52..1e96c3b1 100644 --- a/pkg/api/core/image/mutator_suite_test.go +++ b/pkg/api/core/image/mutator_suite_test.go @@ -18,7 +18,7 @@ package image_test import ( "testing" - "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/compiler/backend" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -26,7 +26,7 @@ import ( func TestMutator(t *testing.T) { RegisterFailHandler(Fail) - b := backend.NewSimpleDockerBackend(types.NewContext()) + b := backend.NewSimpleDockerBackend(context.NewContext()) b.DownloadImage(backend.Options{ImageName: "alpine"}) b.DownloadImage(backend.Options{ImageName: "golang:alpine"}) diff --git a/pkg/api/core/logger/config_suite_test.go b/pkg/api/core/logger/config_suite_test.go new file mode 100644 index 00000000..3e2cebe3 --- /dev/null +++ b/pkg/api/core/logger/config_suite_test.go @@ -0,0 +1,28 @@ +// Copyright © 2021 Ettore Di Giacinto +// +// 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 . + +package logger_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestAPITypes(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Types Suite") +} diff --git a/pkg/api/core/logger/logger.go b/pkg/api/core/logger/logger.go new file mode 100644 index 00000000..f18a10ec --- /dev/null +++ b/pkg/api/core/logger/logger.go @@ -0,0 +1,367 @@ +// Copyright © 2021 Ettore Di Giacinto +// +// 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 . + +package logger + +import ( + "fmt" + "os" + "path" + "regexp" + "runtime" + "strings" + "sync" + + log "github.com/ipfs/go-log/v2" + "github.com/kyokomi/emoji" + "github.com/pterm/pterm" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// Logger is the default logger +type Logger struct { + level log.LogLevel + emoji bool + logToFile bool + noSpinner bool + fileLogger *zap.Logger + context string + spinnerLock sync.Mutex + s *pterm.SpinnerPrinter +} + +// LogLevel represents a log severity level. Use the package variables as an +// enum. +type LogLevel zapcore.Level + +type LoggerOptions func(*Logger) error + +var NoSpinner LoggerOptions = func(l *Logger) error { + l.noSpinner = true + return nil +} + +func WithLevel(level string) LoggerOptions { + return func(l *Logger) error { + lvl, _ := log.LevelFromString(level) // Defaults to Info + l.level = lvl + if l.level == log.LevelDebug { + pterm.EnableDebugMessages() + } + return nil + } +} + +func WithContext(c string) LoggerOptions { + return func(l *Logger) error { + l.context = c + return nil + } +} + +func WithFileLogging(p, encoding string) LoggerOptions { + return func(l *Logger) error { + if encoding == "" { + encoding = "console" + } + l.logToFile = true + var err error + cfg := zap.NewProductionConfig() + cfg.OutputPaths = []string{p} + cfg.Level = zap.NewAtomicLevelAt(zapcore.Level(l.level)) + cfg.ErrorOutputPaths = []string{} + cfg.Encoding = encoding + cfg.DisableCaller = true + cfg.DisableStacktrace = true + cfg.EncoderConfig.TimeKey = "time" + cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + + l.fileLogger, err = cfg.Build() + return err + } +} + +var EnableEmoji = func() LoggerOptions { + return func(l *Logger) error { + l.emoji = true + return nil + } +} + +func New(opts ...LoggerOptions) (*Logger, error) { + l := &Logger{ + level: log.LevelDebug, + s: pterm.DefaultSpinner.WithShowTimer(false).WithRemoveWhenDone(true), + } + for _, o := range opts { + if err := o(l); err != nil { + return nil, err + } + } + + return l, nil +} + +func (l *Logger) Copy(opts ...LoggerOptions) (*Logger, error) { + c := *l + copy := &c + for _, o := range opts { + if err := o(copy); err != nil { + return nil, err + } + } + + return copy, nil +} + +func joinMsg(args ...interface{}) (message string) { + for _, m := range args { + message += " " + fmt.Sprintf("%v", m) + } + return +} + +func (l *Logger) enabled(lvl log.LogLevel) bool { + return lvl >= l.level +} + +var emojiStrip = regexp.MustCompile(`[:][\w]+[:]`) + +func (l *Logger) transform(args ...interface{}) (sanitized []interface{}) { + for _, a := range args { + var aString string + + // Strip emoji if needed + if l.emoji { + aString = emoji.Sprint(a) + } else { + aString = emojiStrip.ReplaceAllString(joinMsg(a), "") + } + + sanitized = append(sanitized, aString) + } + + if l.context != "" { + sanitized = append([]interface{}{fmt.Sprintf("(%s)", l.context)}, sanitized...) + } + return +} + +func prefixCodeLine(args ...interface{}) []interface{} { + pc, file, line, ok := runtime.Caller(3) + if ok { + args = append([]interface{}{fmt.Sprintf("(%s:#%d:%v)", + path.Base(file), line, runtime.FuncForPC(pc).Name())}, args...) + } + return args +} + +func (l *Logger) send(ll log.LogLevel, f string, args ...interface{}) { + if !l.enabled(ll) { + return + } + + sanitizedArgs := joinMsg(l.transform(args...)...) + sanitizedF := joinMsg(l.transform(f)...) + formatDefined := f != "" + + switch { + case log.LevelDebug == ll && !formatDefined: + pterm.Debug.Println(prefixCodeLine(sanitizedArgs)...) + if l.logToFile { + l.fileLogger.Debug(joinMsg(prefixCodeLine(sanitizedArgs)...)) + } + case log.LevelDebug == ll && formatDefined: + pterm.Debug.Printfln(sanitizedF, prefixCodeLine(args...)...) + if l.logToFile { + l.fileLogger.Sugar().Debugf(sanitizedF, prefixCodeLine(args...)...) + } + case log.LevelError == ll && !formatDefined: + pterm.Error.Println(pterm.LightRed(sanitizedArgs)) + if l.logToFile { + l.fileLogger.Error(sanitizedArgs) + } + case log.LevelError == ll && formatDefined: + pterm.Error.Printfln(pterm.LightRed(sanitizedF), args...) + if l.logToFile { + l.fileLogger.Sugar().Errorf(sanitizedF, args...) + } + + case log.LevelFatal == ll && !formatDefined: + pterm.Error.Println(sanitizedArgs) + if l.logToFile { + l.fileLogger.Error(sanitizedArgs) + } + case log.LevelFatal == ll && formatDefined: + pterm.Error.Printfln(sanitizedF, args...) + if l.logToFile { + l.fileLogger.Sugar().Errorf(sanitizedF, args...) + } + //INFO + case log.LevelInfo == ll && !formatDefined: + pterm.Info.Println(sanitizedArgs) + if l.logToFile { + l.fileLogger.Info(sanitizedArgs) + } + case log.LevelInfo == ll && formatDefined: + pterm.Info.Printfln(sanitizedF, args...) + if l.logToFile { + l.fileLogger.Sugar().Infof(sanitizedF, args...) + } + //WARN + case log.LevelWarn == ll && !formatDefined: + pterm.Warning.Println(sanitizedArgs) + if l.logToFile { + l.fileLogger.Warn(sanitizedArgs) + } + case log.LevelWarn == ll && formatDefined: + pterm.Warning.Printfln(sanitizedF, args...) + if l.logToFile { + l.fileLogger.Sugar().Warnf(sanitizedF, args...) + } + } +} + +func (l *Logger) Debug(args ...interface{}) { + l.send(log.LevelDebug, "", args...) +} + +func (l *Logger) Error(args ...interface{}) { + l.send(log.LevelError, "", args...) +} + +func (l *Logger) Trace(args ...interface{}) { + l.send(log.LevelDebug, "", args...) +} + +func (l *Logger) Tracef(t string, args ...interface{}) { + l.send(log.LevelDebug, t, args...) +} + +func (l *Logger) Fatal(args ...interface{}) { + l.send(log.LevelFatal, "", args...) + os.Exit(1) +} + +func (l *Logger) Info(args ...interface{}) { + l.send(log.LevelInfo, "", args...) +} + +func (l *Logger) Success(args ...interface{}) { + l.Info(append([]interface{}{"SUCCESS"}, args...)...) +} + +func (l *Logger) Panic(args ...interface{}) { + l.Fatal(args...) +} + +func (l *Logger) Warn(args ...interface{}) { + l.send(log.LevelWarn, "", args...) +} + +func (l *Logger) Warning(args ...interface{}) { + l.Warn(args...) +} + +func (l *Logger) Debugf(f string, args ...interface{}) { + l.send(log.LevelDebug, f, args...) +} + +func (l *Logger) Errorf(f string, args ...interface{}) { + l.send(log.LevelError, f, args...) +} + +func (l *Logger) Fatalf(f string, args ...interface{}) { + l.send(log.LevelFatal, f, args...) +} + +func (l *Logger) Infof(f string, args ...interface{}) { + l.send(log.LevelInfo, f, args...) +} + +func (l *Logger) Panicf(f string, args ...interface{}) { + l.Fatalf(joinMsg(f), args...) +} + +func (l *Logger) Warnf(f string, args ...interface{}) { + l.send(log.LevelWarn, f, args...) +} + +func (l *Logger) Warningf(f string, args ...interface{}) { + l.Warnf(f, args...) +} + +func (l *Logger) Ask() bool { + var input string + + l.Info("Do you want to continue with this operation? [y/N]: ") + _, err := fmt.Scanln(&input) + if err != nil { + return false + } + input = strings.ToLower(input) + + if input == "y" || input == "yes" { + return true + } + return false +} + +// Spinner starts the spinner +func (l *Logger) Spinner() { + if !IsTerminal() || l.noSpinner { + return + } + + l.spinnerLock.Lock() + defer l.spinnerLock.Unlock() + + if l.s != nil && !l.s.IsActive { + l.s, _ = l.s.Start() + } +} + +func (l *Logger) Screen(text string) { + pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(2).Println(text) +} + +func (l *Logger) SpinnerText(suffix, prefix string) { + if !IsTerminal() || l.noSpinner { + return + } + l.spinnerLock.Lock() + defer l.spinnerLock.Unlock() + + if l.level == log.LevelDebug { + fmt.Printf("%s %s\n", + suffix, prefix, + ) + } else { + l.s.UpdateText(suffix + prefix) + } +} + +func (l *Logger) SpinnerStop() { + if !IsTerminal() || l.noSpinner { + return + } + l.spinnerLock.Lock() + defer l.spinnerLock.Unlock() + + if l.s != nil { + l.s.Success() + } +} diff --git a/pkg/api/core/types/context_test.go b/pkg/api/core/logger/logger_test.go similarity index 67% rename from pkg/api/core/types/context_test.go rename to pkg/api/core/logger/logger_test.go index f9edfe1a..b39605cd 100644 --- a/pkg/api/core/types/context_test.go +++ b/pkg/api/core/logger/logger_test.go @@ -13,7 +13,7 @@ // You should have received a copy of the GNU General Public License along // with this program; if not, see . -package types_test +package logger_test import ( "io" @@ -21,7 +21,8 @@ import ( "os" "github.com/gookit/color" - types "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/logger" + . "github.com/mudler/luet/pkg/api/core/logger" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -44,30 +45,11 @@ func captureStdout(f func(w io.Writer)) string { } var _ = Describe("Context and logging", func() { - ctx := types.NewContext() - - BeforeEach(func() { - ctx = types.NewContext() - }) - - Context("LogLevel", func() { - It("converts it correctly to number and zaplog", func() { - Expect(types.ErrorLevel.ToNumber()).To(Equal(0)) - Expect(types.InfoLevel.ToNumber()).To(Equal(2)) - Expect(types.WarningLevel.ToNumber()).To(Equal(1)) - Expect(types.LogLevel("foo").ToNumber()).To(Equal(3)) - Expect(types.WarningLevel.ZapLevel().String()).To(Equal("warn")) - Expect(types.InfoLevel.ZapLevel().String()).To(Equal("info")) - Expect(types.ErrorLevel.ZapLevel().String()).To(Equal("error")) - Expect(types.FatalLevel.ZapLevel().String()).To(Equal("fatal")) - Expect(types.LogLevel("foo").ZapLevel().String()).To(Equal("debug")) - }) - }) Context("Context", func() { It("detect if is a terminal", func() { Expect(captureStdout(func(w io.Writer) { - _, _, err := ctx.GetTerminalSize() + _, _, err := GetTerminalSize() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(Equal("size not detectable")) os.Stdout.Write([]byte(err.Error())) @@ -75,47 +57,71 @@ var _ = Describe("Context and logging", func() { }) It("respects loglevel", func() { - ctx.Config.GetGeneral().Debug = false + + l, err := New(WithLevel("info")) + Expect(err).ToNot(HaveOccurred()) + Expect(captureStdout(func(w io.Writer) { - ctx.Debug("") + l.Debug("") })).To(Equal("")) - ctx.Config.GetGeneral().Debug = true + l, err = New(WithLevel("debug")) + Expect(err).ToNot(HaveOccurred()) + Expect(captureStdout(func(w io.Writer) { - ctx.Debug("foo") + l.Debug("foo") })).To(ContainSubstring("foo")) }) + It("logs with context", func() { + l, err := New(WithLevel("debug"), WithContext("foo")) + Expect(err).ToNot(HaveOccurred()) + + Expect(captureStdout(func(w io.Writer) { + l.Debug("bar") + })).To(ContainSubstring("(foo) bar")) + }) + + It("returns copies with logged context", func() { + l, err := New(WithLevel("debug")) + l, _ = l.Copy(logger.WithContext("bazzz")) + Expect(err).ToNot(HaveOccurred()) + + Expect(captureStdout(func(w io.Writer) { + l.Debug("bar") + })).To(ContainSubstring("(bazzz) bar")) + }) + It("logs to file", func() { - ctx.NoColor() t, err := ioutil.TempFile("", "tree") Expect(err).ToNot(HaveOccurred()) defer os.RemoveAll(t.Name()) // clean up - ctx.Config.GetLogging().EnableLogFile = true - ctx.Config.GetLogging().Path = t.Name() - ctx.Init() + l, err := New(WithLevel("debug"), WithFileLogging(t.Name(), "")) + Expect(err).ToNot(HaveOccurred()) + + // ctx.Init() Expect(captureStdout(func(w io.Writer) { - ctx.Info("foot") + l.Info("foot") })).To(And(ContainSubstring("INFO"), ContainSubstring("foot"))) Expect(captureStdout(func(w io.Writer) { - ctx.Success("test") + l.Success("test") })).To(And(ContainSubstring("SUCCESS"), ContainSubstring("test"))) Expect(captureStdout(func(w io.Writer) { - ctx.Error("foobar") + l.Error("foobar") })).To(And(ContainSubstring("ERROR"), ContainSubstring("foobar"))) Expect(captureStdout(func(w io.Writer) { - ctx.Warning("foowarn") + l.Warning("foowarn") })).To(And(ContainSubstring("WARNING"), ContainSubstring("foowarn"))) - l, err := ioutil.ReadFile(t.Name()) + ll, err := ioutil.ReadFile(t.Name()) Expect(err).ToNot(HaveOccurred()) - logs := string(l) + logs := string(ll) Expect(logs).To(ContainSubstring("foot")) Expect(logs).To(ContainSubstring("test")) Expect(logs).To(ContainSubstring("foowarn")) diff --git a/pkg/api/core/logger/terminal.go b/pkg/api/core/logger/terminal.go new file mode 100644 index 00000000..8c729237 --- /dev/null +++ b/pkg/api/core/logger/terminal.go @@ -0,0 +1,43 @@ +// Copyright © 2021 Ettore Di Giacinto +// +// 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 . + +package logger + +import ( + "errors" + "os" + + "github.com/mattn/go-isatty" + "golang.org/x/term" +) + +func IsTerminal() bool { + return isatty.IsTerminal(os.Stdout.Fd()) +} + +// GetTerminalSize returns the width and the height of the active terminal. +func GetTerminalSize() (width, height int, err error) { + w, h, err := term.GetSize(int(os.Stdout.Fd())) + if w <= 0 { + w = 0 + } + if h <= 0 { + h = 0 + } + if err != nil { + err = errors.New("size not detectable") + } + return w, h, err +} diff --git a/pkg/api/core/types/artifact/artifact.go b/pkg/api/core/types/artifact/artifact.go index 1bd13ce3..6d532a47 100644 --- a/pkg/api/core/types/artifact/artifact.go +++ b/pkg/api/core/types/artifact/artifact.go @@ -41,7 +41,7 @@ import ( bus "github.com/mudler/luet/pkg/api/core/bus" config "github.com/mudler/luet/pkg/api/core/config" "github.com/mudler/luet/pkg/api/core/image" - types "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/types" backend "github.com/mudler/luet/pkg/compiler/backend" compression "github.com/mudler/luet/pkg/compiler/types/compression" compilerspec "github.com/mudler/luet/pkg/compiler/types/spec" @@ -70,7 +70,7 @@ type PackageArtifact struct { Runtime *pkg.DefaultPackage `json:"runtime,omitempty"` } -func ImageToArtifact(ctx *types.Context, img v1.Image, t compression.Implementation, output string, filter func(h *tar.Header) (bool, error)) (*PackageArtifact, error) { +func ImageToArtifact(ctx types.Context, img v1.Image, t compression.Implementation, output string, filter func(h *tar.Header) (bool, error)) (*PackageArtifact, error) { _, tmpdiffs, err := image.Extract(ctx, img, filter) if err != nil { return nil, errors.Wrap(err, "Error met while creating tempdir for rootfs") @@ -176,12 +176,12 @@ func (a *PackageArtifact) GetFileName() string { } // CreateArtifactForFile creates a new artifact from the given file -func CreateArtifactForFile(ctx *types.Context, s string, opts ...func(*PackageArtifact)) (*PackageArtifact, error) { +func CreateArtifactForFile(ctx types.Context, s string, opts ...func(*PackageArtifact)) (*PackageArtifact, error) { if _, err := os.Stat(s); os.IsNotExist(err) { return nil, errors.Wrap(err, "artifact path doesn't exist") } fileName := path.Base(s) - archive, err := ctx.Config.GetSystem().TempDir("archive") + archive, err := ctx.TempDir("archive") if err != nil { return nil, errors.Wrap(err, "error met while creating tempdir for "+s) } @@ -191,7 +191,7 @@ func CreateArtifactForFile(ctx *types.Context, s string, opts ...func(*PackageAr return nil, errors.Wrapf(err, "error while copying %s to %s", s, dst) } - artifact, err := ctx.Config.GetSystem().TempDir("artifact") + artifact, err := ctx.TempDir("artifact") if err != nil { return nil, errors.Wrap(err, "error met while creating tempdir for "+s) } @@ -210,9 +210,9 @@ type ImageBuilder interface { } // GenerateFinalImage takes an artifact and builds a Docker image with its content -func (a *PackageArtifact) GenerateFinalImage(ctx *types.Context, imageName string, b ImageBuilder, keepPerms bool) error { +func (a *PackageArtifact) GenerateFinalImage(ctx types.Context, imageName string, b ImageBuilder, keepPerms bool) error { - tempimage, err := ctx.Config.GetSystem().TempFile("tempimage") + tempimage, err := ctx.TempFile("tempimage") if err != nil { return errors.Wrap(err, "error met while creating tempdir for "+a.Path) } @@ -428,7 +428,7 @@ func replaceFileTarWrapper(dst string, inputTarStream io.ReadCloser, mods []stri return pipeReader } -func tarModifierWrapperFunc(ctx *types.Context) func(dst, path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) { +func tarModifierWrapperFunc(ctx types.Context) func(dst, path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) { return func(dst, path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) { // If the destination path already exists I rename target file name with postfix. var destPath string @@ -495,10 +495,10 @@ func tarModifierWrapperFunc(ctx *types.Context) func(dst, path string, header *t } } -func (a *PackageArtifact) GetProtectFiles(ctx *types.Context) (res []string) { +func (a *PackageArtifact) GetProtectFiles(ctx types.Context) (res []string) { annotationDir := "" - if !ctx.Config.ConfigProtectSkip { + if !ctx.GetConfig().ConfigProtectSkip { // a.CompileSpec could be nil when artifact.Unpack is used for tree tarball if a.CompileSpec != nil && @@ -511,7 +511,7 @@ func (a *PackageArtifact) GetProtectFiles(ctx *types.Context) (res []string) { // TODO: check if skip this if we have a.CompileSpec nil cp := config.NewConfigProtect(annotationDir) - cp.Map(a.Files, ctx.Config.GetConfigProtectConfFiles()) + cp.Map(a.Files, ctx.GetConfig().ConfigProtectConfFiles) // NOTE: for unpack we need files path without initial / res = cp.GetProtectFiles(false) @@ -521,7 +521,7 @@ func (a *PackageArtifact) GetProtectFiles(ctx *types.Context) (res []string) { } // Unpack Untar and decompress (TODO) to the given path -func (a *PackageArtifact) Unpack(ctx *types.Context, dst string, keepPerms bool) error { +func (a *PackageArtifact) Unpack(ctx types.Context, dst string, keepPerms bool) error { if !strings.HasPrefix(dst, string(os.PathSeparator)) { return errors.New("destination must be an absolute path") diff --git a/pkg/api/core/types/artifact/artifact_test.go b/pkg/api/core/types/artifact/artifact_test.go index 2aa0e87f..6a193511 100644 --- a/pkg/api/core/types/artifact/artifact_test.go +++ b/pkg/api/core/types/artifact/artifact_test.go @@ -20,10 +20,9 @@ import ( "os" "path/filepath" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/api/core/image" - "github.com/mudler/luet/pkg/api/core/types" . "github.com/mudler/luet/pkg/api/core/types/artifact" - . "github.com/mudler/luet/pkg/compiler/backend" backend "github.com/mudler/luet/pkg/compiler/backend" compression "github.com/mudler/luet/pkg/compiler/types/compression" "github.com/mudler/luet/pkg/compiler/types/options" @@ -39,7 +38,7 @@ import ( var _ = Describe("Artifact", func() { Context("Simple package build definition", func() { - ctx := types.NewContext() + ctx := context.NewContext() It("Generates a verified delta", func() { generalRecipe := tree.NewGeneralRecipe(pkg.NewInMemoryDatabase(false)) @@ -49,7 +48,7 @@ var _ = Describe("Artifact", func() { Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(1)) - cc := NewLuetCompiler(nil, generalRecipe.GetDatabase(), options.WithContext(types.NewContext())) + cc := NewLuetCompiler(nil, generalRecipe.GetDatabase(), options.WithContext(context.NewContext())) lspec, err := cc.FromPackage(&pkg.DefaultPackage{Name: "enman", Category: "app-admin", Version: "1.4.0"}) Expect(err).ToNot(HaveOccurred()) @@ -83,7 +82,7 @@ WORKDIR /luetbuild ENV PACKAGE_NAME=enman ENV PACKAGE_VERSION=1.4.0 ENV PACKAGE_CATEGORY=app-admin`)) - b := NewSimpleDockerBackend(ctx) + b := backend.NewSimpleDockerBackend(ctx) opts := backend.Options{ ImageName: "luet/base", SourcePath: tmpdir, @@ -120,7 +119,7 @@ RUN echo bar > /test2`)) }) It("Generates packages images", func() { - b := NewSimpleDockerBackend(ctx) + b := backend.NewSimpleDockerBackend(ctx) imageprefix := "foo/" testString := []byte(`funky test data`) @@ -177,7 +176,7 @@ RUN echo bar > /test2`)) }) It("Generates empty packages images", func() { - b := NewSimpleDockerBackend(ctx) + b := backend.NewSimpleDockerBackend(ctx) imageprefix := "foo/" tmpdir, err := ioutil.TempDir(os.TempDir(), "artifact") diff --git a/pkg/api/core/types/artifact/cache_test.go b/pkg/api/core/types/artifact/cache_test.go index 4452a167..2e5dbe1d 100644 --- a/pkg/api/core/types/artifact/cache_test.go +++ b/pkg/api/core/types/artifact/cache_test.go @@ -20,7 +20,7 @@ import ( "os" "path/filepath" - types "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/context" . "github.com/mudler/luet/pkg/api/core/types/artifact" compilerspec "github.com/mudler/luet/pkg/compiler/types/spec" fileHelper "github.com/mudler/luet/pkg/helpers/file" @@ -59,7 +59,7 @@ var _ = Describe("Cache", func() { Expect(err).ToNot(HaveOccurred()) b := NewPackageArtifact(path) - ctx := types.NewContext() + ctx := context.NewContext() err = b.Unpack(ctx, tmpdir, false) Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/api/core/types/artifact/checksum.go b/pkg/api/core/types/artifact/checksum.go index 5db70e2a..36785b78 100644 --- a/pkg/api/core/types/artifact/checksum.go +++ b/pkg/api/core/types/artifact/checksum.go @@ -45,7 +45,7 @@ type HashOptions struct { func (c Checksums) List() (res [][]string) { keys := make([]string, 0) - for k, _ := range c { + for k := range c { keys = append(keys, k) } sort.Strings(keys) diff --git a/pkg/api/core/types/config.go b/pkg/api/core/types/config.go index b3336c5b..4db7169a 100644 --- a/pkg/api/core/types/config.go +++ b/pkg/api/core/types/config.go @@ -1,6 +1,4 @@ -// Copyright © 2019 Ettore Di Giacinto -// Daniele Rondina -// 2021 Ettore Di Giacinto +// Copyright © 2019-2021 Ettore Di Giacinto // // 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 @@ -39,19 +37,22 @@ var AvailableResolvers = strings.Join([]string{solver.QLearningResolverType}, " type LuetLoggingConfig struct { // Path of the logfile - Path string `mapstructure:"path"` + Path string `yaml:"path" mapstructure:"path"` // Enable/Disable logging to file - EnableLogFile bool `mapstructure:"enable_logfile"` + EnableLogFile bool `yaml:"enable_logfile" mapstructure:"enable_logfile"` // Enable JSON format logging in file - JsonFormat bool `mapstructure:"json_format"` + JsonFormat bool `yaml:"json_format" mapstructure:"json_format"` // Log level - Level LogLevel `mapstructure:"level"` + Level string `yaml:"level" mapstructure:"level"` // Enable emoji - EnableEmoji bool `mapstructure:"enable_emoji"` + EnableEmoji bool `yaml:"enable_emoji" mapstructure:"enable_emoji"` // Enable/Disable color in logging - Color bool `mapstructure:"color"` + Color bool `yaml:"color" mapstructure:"color"` + + // NoSpinner disable spinner + NoSpinner bool `yaml:"no_spinner" mapstructure:"no_spinner"` } type LuetGeneralConfig struct { @@ -108,8 +109,42 @@ type LuetSystemConfig struct { TmpDirBase string `yaml:"tmpdir_base" mapstructure:"tmpdir_base"` } -func (s *LuetSystemConfig) SetRootFS(path string) error { - p, err := fileHelper.Rel2Abs(path) +// Init reads the config and replace user-defined paths with +// absolute paths where necessary, and construct the paths for the cache +// and database on the real system +func (c *LuetConfig) Init() error { + if err := c.System.init(); err != nil { + return err + } + + if err := c.loadConfigProtect(); err != nil { + return err + } + + // Load repositories + if err := c.loadRepositories(); err != nil { + return err + } + + return nil +} + +func (s *LuetSystemConfig) init() error { + if err := s.setRootfs(); err != nil { + return err + } + + if err := s.setDBPath(); err != nil { + return err + } + + s.setCachePath() + + return nil +} + +func (s *LuetSystemConfig) setRootfs() error { + p, err := fileHelper.Rel2Abs(s.Rootfs) if err != nil { return err } @@ -118,9 +153,8 @@ func (s *LuetSystemConfig) SetRootFS(path string) error { return nil } -func (sc *LuetSystemConfig) GetRepoDatabaseDirPath(name string) string { - dbpath := filepath.Join(sc.Rootfs, sc.DatabasePath) - dbpath = filepath.Join(dbpath, "repos/"+name) +func (sc LuetSystemConfig) GetRepoDatabaseDirPath(name string) string { + dbpath := filepath.Join(sc.DatabasePath, "repos/"+name) err := os.MkdirAll(dbpath, os.ModePerm) if err != nil { panic(err) @@ -128,45 +162,48 @@ func (sc *LuetSystemConfig) GetRepoDatabaseDirPath(name string) string { return dbpath } -func (sc *LuetSystemConfig) GetSystemRepoDatabaseDirPath() string { +func (sc *LuetSystemConfig) setDBPath() error { dbpath := filepath.Join(sc.Rootfs, sc.DatabasePath) err := os.MkdirAll(dbpath, os.ModePerm) if err != nil { - panic(err) + return err } - return dbpath + sc.DatabasePath = dbpath + return nil } -func (sc *LuetSystemConfig) GetSystemPkgsCacheDirPath() (p string) { +func (sc *LuetSystemConfig) setCachePath() { var cachepath string if sc.PkgsCachePath != "" { - cachepath = sc.PkgsCachePath + if !filepath.IsAbs(cachepath) { + cachepath = filepath.Join(sc.DatabasePath, sc.PkgsCachePath) + os.MkdirAll(cachepath, os.ModePerm) + } else { + cachepath = sc.PkgsCachePath + } } else { // Create dynamic cache for test suites cachepath, _ = ioutil.TempDir(os.TempDir(), "cachepkgs") } - if filepath.IsAbs(cachepath) { - p = cachepath - } else { - p = filepath.Join(sc.GetSystemRepoDatabaseDirPath(), cachepath) - } - sc.PkgsCachePath = cachepath // Be consistent with the path we set - - return } -func (sc *LuetSystemConfig) GetRootFsAbs() (string, error) { - return filepath.Abs(sc.Rootfs) -} - -type LuetKV struct { +type FinalizerEnv struct { Key string `json:"key" yaml:"key" mapstructure:"key"` Value string `json:"value" yaml:"value" mapstructure:"value"` } +type Finalizers []FinalizerEnv + +func (f Finalizers) Slice() (sl []string) { + for _, kv := range f { + sl = append(sl, fmt.Sprintf("%s=%s", kv.Key, kv.Value)) + } + return +} + type LuetConfig struct { Logging LuetLoggingConfig `yaml:"logging,omitempty" mapstructure:"logging"` General LuetGeneralConfig `yaml:"general,omitempty" mapstructure:"general"` @@ -179,16 +216,16 @@ type LuetConfig struct { ConfigFromHost bool `yaml:"config_from_host,omitempty" mapstructure:"config_from_host"` SystemRepositories LuetRepositories `yaml:"repositories,omitempty" mapstructure:"repositories"` - FinalizerEnvs []LuetKV `json:"finalizer_envs,omitempty" yaml:"finalizer_envs,omitempty" mapstructure:"finalizer_envs,omitempty"` + FinalizerEnvs Finalizers `json:"finalizer_envs,omitempty" yaml:"finalizer_envs,omitempty" mapstructure:"finalizer_envs,omitempty"` ConfigProtectConfFiles []config.ConfigProtectConfFile `yaml:"-" mapstructure:"-"` } func (c *LuetConfig) GetSystemDB() pkg.PackageDatabase { - switch c.GetSystem().DatabaseEngine { + switch c.System.DatabaseEngine { case "boltdb": return pkg.NewBoltDatabase( - filepath.Join(c.GetSystem().GetSystemRepoDatabaseDirPath(), "luet.db")) + filepath.Join(c.System.DatabasePath, "luet.db")) default: return pkg.NewInMemoryDatabase(true) } @@ -198,83 +235,30 @@ func (c *LuetConfig) AddSystemRepository(r LuetRepository) { c.SystemRepositories = append(c.SystemRepositories, r) } -func (c *LuetConfig) GetFinalizerEnvsMap() map[string]string { - ans := make(map[string]string) - - for _, kv := range c.FinalizerEnvs { - ans[kv.Key] = kv.Value - } - return ans -} - func (c *LuetConfig) SetFinalizerEnv(k, v string) { keyPresent := false - envs := []LuetKV{} + envs := []FinalizerEnv{} for _, kv := range c.FinalizerEnvs { if kv.Key == k { keyPresent = true - envs = append(envs, LuetKV{Key: kv.Key, Value: v}) + envs = append(envs, FinalizerEnv{Key: kv.Key, Value: v}) } else { envs = append(envs, kv) } } if !keyPresent { - envs = append(envs, LuetKV{Key: k, Value: v}) + envs = append(envs, FinalizerEnv{Key: k, Value: v}) } c.FinalizerEnvs = envs } -func (c *LuetConfig) GetFinalizerEnvs() []string { - ans := []string{} - for _, kv := range c.FinalizerEnvs { - ans = append(ans, fmt.Sprintf("%s=%s", kv.Key, kv.Value)) - } - return ans -} - -func (c *LuetConfig) GetFinalizerEnv(k string) (string, error) { - keyNotPresent := true - ans := "" - for _, kv := range c.FinalizerEnvs { - if kv.Key == k { - keyNotPresent = false - ans = kv.Value - } - } - - if keyNotPresent { - return "", errors.New("Finalizer key " + k + " not found") - } - return ans, nil -} - -func (c *LuetConfig) GetLogging() *LuetLoggingConfig { - return &c.Logging -} - -func (c *LuetConfig) GetGeneral() *LuetGeneralConfig { - return &c.General -} - -func (c *LuetConfig) GetSystem() *LuetSystemConfig { - return &c.System -} - -func (c *LuetConfig) GetSolverOptions() *LuetSolverOptions { - return &c.Solver -} - func (c *LuetConfig) YAML() ([]byte, error) { return yaml.Marshal(c) } -func (c *LuetConfig) GetConfigProtectConfFiles() []config.ConfigProtectConfFile { - return c.ConfigProtectConfFiles -} - -func (c *LuetConfig) AddConfigProtectConfFile(file *config.ConfigProtectConfFile) { +func (c *LuetConfig) addProtectFile(file *config.ConfigProtectConfFile) { if c.ConfigProtectConfFiles == nil { c.ConfigProtectConfFiles = []config.ConfigProtectConfFile{*file} } else { @@ -282,28 +266,21 @@ func (c *LuetConfig) AddConfigProtectConfFile(file *config.ConfigProtectConfFile } } -func (c *LuetConfig) LoadRepositories(ctx *Context) error { +func (c *LuetConfig) loadRepositories() error { var regexRepo = regexp.MustCompile(`.yml$|.yaml$`) - var err error rootfs := "" // Respect the rootfs param on read repositories if !c.ConfigFromHost { - rootfs, err = c.GetSystem().GetRootFsAbs() - if err != nil { - return err - } + rootfs = c.System.Rootfs } for _, rdir := range c.RepositoriesConfDir { rdir = filepath.Join(rootfs, rdir) - ctx.Debug("Parsing Repository Directory", rdir, "...") - files, err := ioutil.ReadDir(rdir) if err != nil { - ctx.Debug("Skip dir", rdir, ":", err.Error()) continue } @@ -313,27 +290,20 @@ func (c *LuetConfig) LoadRepositories(ctx *Context) error { } if !regexRepo.MatchString(file.Name()) { - ctx.Debug("File", file.Name(), "skipped.") continue } content, err := ioutil.ReadFile(path.Join(rdir, file.Name())) if err != nil { - ctx.Warning("On read file", file.Name(), ":", err.Error()) - ctx.Warning("File", file.Name(), "skipped.") continue } r, err := LoadRepository(content) if err != nil { - ctx.Warning("On parse file", file.Name(), ":", err.Error()) - ctx.Warning("File", file.Name(), "skipped.") continue } if r.Name == "" || len(r.Urls) == 0 || r.Type == "" { - ctx.Warning("Invalid repository ", file.Name()) - ctx.Warning("File", file.Name(), "skipped.") continue } @@ -359,28 +329,20 @@ func (c *LuetConfig) GetSystemRepository(name string) (*LuetRepository, error) { return ans, nil } -func (c *LuetConfig) LoadConfigProtect(ctx *Context) error { +func (c *LuetConfig) loadConfigProtect() error { var regexConfs = regexp.MustCompile(`.yml$`) - var err error - rootfs := "" // Respect the rootfs param on read repositories if !c.ConfigFromHost { - rootfs, err = c.GetSystem().GetRootFsAbs() - if err != nil { - return err - } + rootfs = c.System.Rootfs } for _, cdir := range c.ConfigProtectConfDir { cdir = filepath.Join(rootfs, cdir) - ctx.Debug("Parsing Config Protect Directory", cdir, "...") - files, err := ioutil.ReadDir(cdir) if err != nil { - ctx.Debug("Skip dir", cdir, ":", err.Error()) continue } @@ -390,38 +352,31 @@ func (c *LuetConfig) LoadConfigProtect(ctx *Context) error { } if !regexConfs.MatchString(file.Name()) { - ctx.Debug("File", file.Name(), "skipped.") continue } content, err := ioutil.ReadFile(path.Join(cdir, file.Name())) if err != nil { - ctx.Warning("On read file", file.Name(), ":", err.Error()) - ctx.Warning("File", file.Name(), "skipped.") continue } - r, err := loadConfigProtectConFile(file.Name(), content) + r, err := loadConfigProtectConfFile(file.Name(), content) if err != nil { - ctx.Warning("On parse file", file.Name(), ":", err.Error()) - ctx.Warning("File", file.Name(), "skipped.") continue } if r.Name == "" || len(r.Directories) == 0 { - ctx.Warning("Invalid config protect file", file.Name()) - ctx.Warning("File", file.Name(), "skipped.") continue } - c.AddConfigProtectConfFile(r) + c.addProtectFile(r) } } return nil } -func loadConfigProtectConFile(filename string, data []byte) (*config.ConfigProtectConfFile, error) { +func loadConfigProtectConfFile(filename string, data []byte) (*config.ConfigProtectConfFile, error) { ans := config.NewConfigProtectConfFile(filename) err := yaml.Unmarshal(data, &ans) if err != nil { @@ -429,47 +384,3 @@ func loadConfigProtectConFile(filename string, data []byte) (*config.ConfigProte } return ans, nil } - -func (c *LuetLoggingConfig) SetLogLevel(s LogLevel) { - c.Level = s -} - -func (c *LuetSystemConfig) InitTmpDir() error { - if !filepath.IsAbs(c.TmpDirBase) { - abs, err := fileHelper.Rel2Abs(c.TmpDirBase) - if err != nil { - return errors.Wrap(err, "while converting relative path to absolute path") - } - c.TmpDirBase = abs - } - - if _, err := os.Stat(c.TmpDirBase); err != nil { - if os.IsNotExist(err) { - err = os.MkdirAll(c.TmpDirBase, os.ModePerm) - if err != nil { - return err - } - } - } - return nil -} - -func (c *LuetSystemConfig) CleanupTmpDir() error { - return os.RemoveAll(c.TmpDirBase) -} - -func (c *LuetSystemConfig) TempDir(pattern string) (string, error) { - err := c.InitTmpDir() - if err != nil { - return "", err - } - return ioutil.TempDir(c.TmpDirBase, pattern) -} - -func (c *LuetSystemConfig) TempFile(pattern string) (*os.File, error) { - err := c.InitTmpDir() - if err != nil { - return nil, err - } - return ioutil.TempFile(c.TmpDirBase, pattern) -} diff --git a/pkg/api/core/types/config_test.go b/pkg/api/core/types/config_test.go index 484c9f5b..5fcd0f62 100644 --- a/pkg/api/core/types/config_test.go +++ b/pkg/api/core/types/config_test.go @@ -17,53 +17,86 @@ package types_test import ( + "io/ioutil" "os" "path/filepath" "strings" - types "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/context" + "github.com/mudler/luet/pkg/api/core/types" fileHelper "github.com/mudler/luet/pkg/helpers/file" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Config", func() { - Context("Load Repository1", func() { - ctx := types.NewContext() - ctx.Config.RepositoriesConfDir = []string{ - "../../../../tests/fixtures/repos.conf.d", - } - err := ctx.Config.LoadRepositories(ctx) + Context("Inits paths", func() { + t, _ := ioutil.TempDir("", "tests") + defer os.RemoveAll(t) + c := &types.LuetConfig{ + System: types.LuetSystemConfig{ + Rootfs: t, + PkgsCachePath: "foo", + DatabasePath: "baz", + }} + It("sets default", func() { + err := c.Init() + Expect(err).ToNot(HaveOccurred()) + Expect(c.System.Rootfs).To(Equal(t)) + Expect(c.System.PkgsCachePath).To(Equal(filepath.Join(t, "baz", "foo"))) + Expect(c.System.DatabasePath).To(Equal(filepath.Join(t, "baz"))) + }) + }) + + Context("Load Repository1", func() { + var ctx *context.Context + BeforeEach(func() { + ctx = context.NewContext(context.WithConfig(&types.LuetConfig{ + RepositoriesConfDir: []string{ + "../../../../tests/fixtures/repos.conf.d", + }, + })) + ctx.Config.Init() + }) It("Check Load Repository 1", func() { - Expect(err).Should(BeNil()) - Expect(len(ctx.Config.SystemRepositories)).Should(Equal(2)) - Expect(ctx.Config.SystemRepositories[0].Name).Should(Equal("test1")) - Expect(ctx.Config.SystemRepositories[0].Priority).Should(Equal(999)) - Expect(ctx.Config.SystemRepositories[0].Type).Should(Equal("disk")) - Expect(len(ctx.Config.SystemRepositories[0].Urls)).Should(Equal(1)) - Expect(ctx.Config.SystemRepositories[0].Urls[0]).Should(Equal("tests/repos/test1")) + Expect(len(ctx.GetConfig().SystemRepositories)).Should(Equal(2)) + Expect(ctx.GetConfig().SystemRepositories[0].Name).Should(Equal("test1")) + Expect(ctx.GetConfig().SystemRepositories[0].Priority).Should(Equal(999)) + Expect(ctx.GetConfig().SystemRepositories[0].Type).Should(Equal("disk")) + Expect(len(ctx.GetConfig().SystemRepositories[0].Urls)).Should(Equal(1)) + Expect(ctx.GetConfig().SystemRepositories[0].Urls[0]).Should(Equal("tests/repos/test1")) }) It("Chec Load Repository 2", func() { - Expect(err).Should(BeNil()) - Expect(len(ctx.Config.SystemRepositories)).Should(Equal(2)) - Expect(ctx.Config.SystemRepositories[1].Name).Should(Equal("test2")) - Expect(ctx.Config.SystemRepositories[1].Priority).Should(Equal(1000)) - Expect(ctx.Config.SystemRepositories[1].Type).Should(Equal("disk")) - Expect(len(ctx.Config.SystemRepositories[1].Urls)).Should(Equal(1)) - Expect(ctx.Config.SystemRepositories[1].Urls[0]).Should(Equal("tests/repos/test2")) + Expect(len(ctx.GetConfig().SystemRepositories)).Should(Equal(2)) + Expect(ctx.GetConfig().SystemRepositories[1].Name).Should(Equal("test2")) + Expect(ctx.GetConfig().SystemRepositories[1].Priority).Should(Equal(1000)) + Expect(ctx.GetConfig().SystemRepositories[1].Type).Should(Equal("disk")) + Expect(len(ctx.GetConfig().SystemRepositories[1].Urls)).Should(Equal(1)) + Expect(ctx.GetConfig().SystemRepositories[1].Urls[0]).Should(Equal("tests/repos/test2")) }) }) + Context("Simple temporary directory creation", func() { + ctx := context.NewContext(context.WithConfig(&types.LuetConfig{ + System: types.LuetSystemConfig{ + TmpDirBase: os.TempDir() + "/tmpluet", + }, + })) + + BeforeEach(func() { + ctx = context.NewContext(context.WithConfig(&types.LuetConfig{ + System: types.LuetSystemConfig{ + TmpDirBase: os.TempDir() + "/tmpluet", + }, + })) + + }) It("Create Temporary directory", func() { - ctx := types.NewContext() - - ctx.Config.GetSystem().TmpDirBase = os.TempDir() + "/tmpluet" - - tmpDir, err := ctx.Config.GetSystem().TempDir("test1") + tmpDir, err := ctx.TempDir("test1") Expect(err).ToNot(HaveOccurred()) Expect(strings.HasPrefix(tmpDir, filepath.Join(os.TempDir(), "tmpluet"))).To(BeTrue()) Expect(fileHelper.Exists(tmpDir)).To(BeTrue()) @@ -72,11 +105,7 @@ var _ = Describe("Config", func() { }) It("Create Temporary file", func() { - ctx := types.NewContext() - - ctx.Config.GetSystem().TmpDirBase = os.TempDir() + "/tmpluet" - - tmpFile, err := ctx.Config.GetSystem().TempFile("testfile1") + tmpFile, err := ctx.TempFile("testfile1") Expect(err).ToNot(HaveOccurred()) Expect(strings.HasPrefix(tmpFile.Name(), filepath.Join(os.TempDir(), "tmpluet"))).To(BeTrue()) Expect(fileHelper.Exists(tmpFile.Name())).To(BeTrue()) diff --git a/pkg/api/core/types/context.go b/pkg/api/core/types/context.go index 0ab99f5a..266ce530 100644 --- a/pkg/api/core/types/context.go +++ b/pkg/api/core/types/context.go @@ -15,417 +15,16 @@ package types -import ( - "context" - "fmt" - "os" - "path" - "path/filepath" - "regexp" - "runtime" - "strings" - "sync" +type Context interface { + Logger + GarbageCollector + GetConfig() LuetConfig + Copy() Context + // SetAnnotation sets generic annotations to hold in a context + SetAnnotation(s string, i interface{}) - "github.com/kyokomi/emoji" - "github.com/mudler/luet/pkg/helpers/terminal" - "github.com/pkg/errors" - "github.com/pterm/pterm" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - "golang.org/x/term" -) + // GetAnnotation gets generic annotations to hold in a context + GetAnnotation(s string) interface{} -const ( - ErrorLevel LogLevel = "error" - WarningLevel LogLevel = "warning" - InfoLevel LogLevel = "info" - SuccessLevel LogLevel = "success" - FatalLevel LogLevel = "fatal" -) - -type Context struct { - context.Context - Config *LuetConfig - IsTerminal bool - NoSpinner bool - name string - - s *pterm.SpinnerPrinter - spinnerLock *sync.Mutex - z *zap.Logger - ProgressBar *pterm.ProgressbarPrinter -} - -func NewContext() *Context { - return &Context{ - spinnerLock: &sync.Mutex{}, - IsTerminal: terminal.IsTerminal(os.Stdout), - Config: &LuetConfig{ - ConfigFromHost: true, - Logging: LuetLoggingConfig{}, - General: LuetGeneralConfig{}, - System: LuetSystemConfig{ - DatabasePath: filepath.Join("var", "db", "packages"), - TmpDirBase: filepath.Join(os.TempDir(), "tmpluet")}, - Solver: LuetSolverOptions{}, - }, - s: pterm.DefaultSpinner.WithShowTimer(false).WithRemoveWhenDone(true), - } -} - -func (c *Context) WithName(name string) *Context { - newc := c.Copy() - newc.name = name - return newc -} - -func (c *Context) Copy() *Context { - - configCopy := *c.Config - configCopy.System = *c.Config.GetSystem() - configCopy.General = *c.Config.GetGeneral() - configCopy.Logging = *c.Config.GetLogging() - - ctx := *c - ctxCopy := &ctx - ctxCopy.Config = &configCopy - - return ctxCopy -} - -// GetTerminalSize returns the width and the height of the active terminal. -func (c *Context) GetTerminalSize() (width, height int, err error) { - w, h, err := term.GetSize(int(os.Stdout.Fd())) - if w <= 0 { - w = 0 - } - if h <= 0 { - h = 0 - } - if err != nil { - err = errors.New("size not detectable") - } - return w, h, err -} - -func (c *Context) Init() (err error) { - if c.IsTerminal { - if !c.Config.Logging.Color { - c.Debug("Disabling colors") - c.NoColor() - } - } else { - c.Debug("Not a terminal, disabling colors") - c.NoColor() - } - - if c.Config.General.Quiet { - c.NoColor() - pterm.DisableStyling() - } - - c.Debug("Colors", c.Config.GetLogging().Color) - c.Debug("Logging level", c.Config.GetLogging().Level) - c.Debug("Debug mode", c.Config.GetGeneral().Debug) - - if c.Config.GetLogging().EnableLogFile && c.Config.GetLogging().Path != "" { - // Init zap logger - err = c.InitZap() - if err != nil { - return - } - } - - // Load repositories - err = c.Config.LoadRepositories(c) - if err != nil { - return - } - return -} - -func (c *Context) NoColor() { - pterm.DisableColor() -} - -func (c *Context) Ask() bool { - var input string - - c.Info("Do you want to continue with this operation? [y/N]: ") - _, err := fmt.Scanln(&input) - if err != nil { - return false - } - input = strings.ToLower(input) - - if input == "y" || input == "yes" { - return true - } - return false -} - -func (c *Context) InitZap() error { - var err error - if c.z == nil { - // TODO: test permission for open logfile. - cfg := zap.NewProductionConfig() - cfg.OutputPaths = []string{c.Config.GetLogging().Path} - cfg.Level = c.Config.GetLogging().Level.ZapLevel() - cfg.ErrorOutputPaths = []string{} - if c.Config.GetLogging().JsonFormat { - cfg.Encoding = "json" - } else { - cfg.Encoding = "console" - } - cfg.DisableCaller = true - cfg.DisableStacktrace = true - cfg.EncoderConfig.TimeKey = "time" - cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder - - c.z, err = cfg.Build() - if err != nil { - fmt.Fprint(os.Stderr, "Error on initialize file logger: "+err.Error()+"\n") - return err - } - } - - return nil -} - -// Spinner starts the spinner -func (c *Context) Spinner() { - if !c.IsTerminal || c.NoSpinner { - return - } - - c.spinnerLock.Lock() - defer c.spinnerLock.Unlock() - var confLevel int - if c.Config.GetGeneral().Debug { - confLevel = 3 - } else { - confLevel = c.Config.GetLogging().Level.ToNumber() - } - if 2 > confLevel { - return - } - - if !c.s.IsActive { - c.s, _ = c.s.Start() - } -} - -func (c *Context) Screen(text string) { - pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(2).Println(text) - //pterm.DefaultCenter.Print(pterm.DefaultHeader.WithFullWidth().WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Sprint(text)) -} - -func (c *Context) SpinnerText(suffix, prefix string) { - if !c.IsTerminal || c.NoSpinner { - return - } - - c.spinnerLock.Lock() - defer c.spinnerLock.Unlock() - if c.Config.GetGeneral().Debug { - fmt.Printf("%s %s\n", - suffix, prefix, - ) - } else { - c.s.UpdateText(suffix + prefix) - } -} - -func (c *Context) SpinnerStop() { - if !c.IsTerminal { - return - } - - c.spinnerLock.Lock() - defer c.spinnerLock.Unlock() - var confLevel int - if c.Config.GetGeneral().Debug { - confLevel = 3 - } else { - confLevel = c.Config.GetLogging().Level.ToNumber() - } - if 2 > confLevel { - return - } - if c.s != nil { - c.s.Success() - } -} - -func (c *Context) log2File(level LogLevel, msg string) { - switch level { - case FatalLevel: - c.z.Fatal(msg) - case ErrorLevel: - c.z.Error(msg) - case WarningLevel: - c.z.Warn(msg) - case InfoLevel, SuccessLevel: - c.z.Info(msg) - default: - c.z.Debug(msg) - } -} - -func (c *Context) Msg(level LogLevel, ln bool, msg ...interface{}) { - var message string - var confLevel, msgLevel int - - if c.Config.GetGeneral().Debug { - confLevel = 3 - pterm.EnableDebugMessages() - } else { - confLevel = c.Config.GetLogging().Level.ToNumber() - } - msgLevel = level.ToNumber() - - if msgLevel > confLevel { - return - } - - for _, m := range msg { - message += " " + fmt.Sprintf("%v", m) - } - - // Color message - levelMsg := message - - if c.Config.GetLogging().Color { - switch level { - case WarningLevel: - levelMsg = pterm.LightYellow(":construction: warning" + message) - case InfoLevel: - levelMsg = message - case SuccessLevel: - levelMsg = pterm.LightGreen(message) - case ErrorLevel: - levelMsg = pterm.Red(message) - default: - levelMsg = pterm.Blue(message) - } - } - - // Strip emoji if needed - if c.Config.GetLogging().EnableEmoji && c.IsTerminal { - levelMsg = emoji.Sprint(levelMsg) - } else { - re := regexp.MustCompile(`[:][\w]+[:]`) - levelMsg = re.ReplaceAllString(levelMsg, "") - } - - if c.name != "" { - levelMsg = fmt.Sprintf("[%s] %s", c.name, levelMsg) - } - - if c.z != nil { - c.log2File(level, message) - } - - // Print the message based on the level - switch level { - case SuccessLevel: - if ln { - pterm.Success.Println(levelMsg) - } else { - pterm.Success.Print(levelMsg) - } - case InfoLevel: - if ln { - pterm.Info.Println(levelMsg) - } else { - pterm.Info.Print(levelMsg) - } - case WarningLevel: - if ln { - pterm.Warning.Println(levelMsg) - } else { - pterm.Warning.Print(levelMsg) - } - case ErrorLevel: - if ln { - pterm.Error.Println(levelMsg) - } else { - pterm.Error.Print(levelMsg) - } - case FatalLevel: - if ln { - pterm.Fatal.Println(levelMsg) - } else { - pterm.Fatal.Print(levelMsg) - } - default: - if ln { - pterm.Debug.Println(levelMsg) - } else { - pterm.Debug.Print(levelMsg) - } - } -} - -func (c *Context) Warning(mess ...interface{}) { - c.Msg("warning", true, mess...) - if c.Config.GetGeneral().FatalWarns { - os.Exit(2) - } -} - -func (c *Context) Debug(mess ...interface{}) { - pc, file, line, ok := runtime.Caller(1) - if ok { - mess = append([]interface{}{fmt.Sprintf("(%s:#%d:%v)", - path.Base(file), line, runtime.FuncForPC(pc).Name())}, mess...) - } - c.Msg("debug", true, mess...) -} - -func (c *Context) Info(mess ...interface{}) { - c.Msg("info", true, mess...) -} - -func (c *Context) Success(mess ...interface{}) { - c.Msg("success", true, mess...) -} - -func (c *Context) Error(mess ...interface{}) { - c.Msg("error", true, mess...) -} - -func (c *Context) Fatal(mess ...interface{}) { - c.Error(mess...) - os.Exit(1) -} - -type LogLevel string - -func (level LogLevel) ToNumber() int { - switch level { - case ErrorLevel, FatalLevel: - return 0 - case WarningLevel: - return 1 - case InfoLevel, SuccessLevel: - return 2 - default: // debug - return 3 - } -} - -func (level LogLevel) ZapLevel() zap.AtomicLevel { - switch level { - case FatalLevel: - return zap.NewAtomicLevelAt(zap.FatalLevel) - case ErrorLevel: - return zap.NewAtomicLevelAt(zap.ErrorLevel) - case WarningLevel: - return zap.NewAtomicLevelAt(zap.WarnLevel) - case InfoLevel, SuccessLevel: - return zap.NewAtomicLevelAt(zap.InfoLevel) - default: - return zap.NewAtomicLevelAt(zap.DebugLevel) - } + WithLoggingContext(s string) Context } diff --git a/pkg/api/core/types/garbagecollector.go b/pkg/api/core/types/garbagecollector.go new file mode 100644 index 00000000..7ce49b12 --- /dev/null +++ b/pkg/api/core/types/garbagecollector.go @@ -0,0 +1,25 @@ +// Copyright © 2021 Ettore Di Giacinto +// +// 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 . + +package types + +import "os" + +type GarbageCollector interface { + Clean() error + TempDir(pattern string) (string, error) + TempFile(s string) (*os.File, error) + String() string +} diff --git a/pkg/api/core/types/logger.go b/pkg/api/core/types/logger.go new file mode 100644 index 00000000..0998ef1f --- /dev/null +++ b/pkg/api/core/types/logger.go @@ -0,0 +1,41 @@ +// Copyright © 2021 Ettore Di Giacinto +// +// 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 . + +package types + +// Logger is a standard logging interface +type Logger interface { + Info(...interface{}) + Success(...interface{}) + Warning(...interface{}) + Warn(...interface{}) + Debug(...interface{}) + Error(...interface{}) + Fatal(...interface{}) + Panic(...interface{}) + Trace(...interface{}) + Infof(string, ...interface{}) + Warnf(string, ...interface{}) + Debugf(string, ...interface{}) + Errorf(string, ...interface{}) + Fatalf(string, ...interface{}) + Panicf(string, ...interface{}) + Tracef(string, ...interface{}) + + SpinnerStop() + Spinner() + Ask() bool + Screen(string) +} diff --git a/pkg/compiler/backend.go b/pkg/compiler/backend.go index b76f8e3f..3aad10e7 100644 --- a/pkg/compiler/backend.go +++ b/pkg/compiler/backend.go @@ -2,13 +2,13 @@ package compiler import ( v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/types" "github.com/mudler/luet/pkg/compiler/backend" "github.com/pkg/errors" ) -func NewBackend(ctx *types.Context, s string) (CompilerBackend, error) { +func NewBackend(ctx types.Context, s string) (CompilerBackend, error) { var compilerBackend CompilerBackend switch s { diff --git a/pkg/compiler/backend/common.go b/pkg/compiler/backend/common.go index 033d15e5..33d41f1d 100644 --- a/pkg/compiler/backend/common.go +++ b/pkg/compiler/backend/common.go @@ -18,9 +18,8 @@ package backend import ( "os/exec" - "github.com/mudler/luet/pkg/api/core/types" - "github.com/google/go-containerregistry/pkg/crane" + "github.com/mudler/luet/pkg/api/core/types" "github.com/pkg/errors" ) @@ -43,9 +42,9 @@ type Options struct { BackendArgs []string } -func runCommand(ctx *types.Context, cmd *exec.Cmd) error { +func runCommand(ctx types.Context, cmd *exec.Cmd) error { output := "" - buffered := !ctx.Config.GetGeneral().ShowBuildOutput + buffered := !ctx.GetConfig().General.ShowBuildOutput writer := NewBackendWriter(buffered, ctx) cmd.Stdout = writer diff --git a/pkg/compiler/backend/simpledocker.go b/pkg/compiler/backend/simpledocker.go index 4e7fbd87..b9718b77 100644 --- a/pkg/compiler/backend/simpledocker.go +++ b/pkg/compiler/backend/simpledocker.go @@ -32,10 +32,10 @@ import ( ) type SimpleDocker struct { - ctx *types.Context + ctx types.Context } -func NewSimpleDockerBackend(ctx *types.Context) *SimpleDocker { +func NewSimpleDockerBackend(ctx types.Context) *SimpleDocker { return &SimpleDocker{ctx: ctx} } @@ -190,7 +190,7 @@ func (s *SimpleDocker) imageFromCLIPipe(a string) (v1.Image, error) { } func (s *SimpleDocker) imageFromDisk(a string) (v1.Image, error) { - f, err := s.ctx.Config.GetSystem().TempFile("snapshot") + f, err := s.ctx.TempFile("snapshot") if err != nil { return nil, err } diff --git a/pkg/compiler/backend/simpledocker_test.go b/pkg/compiler/backend/simpledocker_test.go index 61b36325..9ff6e4af 100644 --- a/pkg/compiler/backend/simpledocker_test.go +++ b/pkg/compiler/backend/simpledocker_test.go @@ -16,7 +16,7 @@ package backend_test import ( - "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/context" . "github.com/mudler/luet/pkg/compiler" "github.com/mudler/luet/pkg/compiler/backend" . "github.com/mudler/luet/pkg/compiler/backend" @@ -34,7 +34,7 @@ import ( var _ = Describe("Docker backend", func() { Context("Simple Docker backend satisfies main interface functionalities", func() { - ctx := types.NewContext() + ctx := context.NewContext() It("Builds and generate tars", func() { generalRecipe := tree.NewGeneralRecipe(pkg.NewInMemoryDatabase(false)) diff --git a/pkg/compiler/backend/simpleimg.go b/pkg/compiler/backend/simpleimg.go index 3dadb7c4..0efccc8d 100644 --- a/pkg/compiler/backend/simpleimg.go +++ b/pkg/compiler/backend/simpleimg.go @@ -28,10 +28,10 @@ import ( ) type SimpleImg struct { - ctx *types.Context + ctx types.Context } -func NewSimpleImgBackend(ctx *types.Context) *SimpleImg { +func NewSimpleImgBackend(ctx types.Context) *SimpleImg { return &SimpleImg{ctx: ctx} } @@ -77,7 +77,7 @@ func (s *SimpleImg) RemoveImage(opts Options) error { func (s *SimpleImg) ImageReference(a string, ondisk bool) (v1.Image, error) { - f, err := s.ctx.Config.GetSystem().TempFile("snapshot") + f, err := s.ctx.TempFile("snapshot") if err != nil { return nil, err } diff --git a/pkg/compiler/backend/writer.go b/pkg/compiler/backend/writer.go index 65196193..c78ceddd 100644 --- a/pkg/compiler/backend/writer.go +++ b/pkg/compiler/backend/writer.go @@ -25,10 +25,10 @@ import ( type BackendWriter struct { BufferedOutput bool Buffer *bytes.Buffer - ctx *types.Context + ctx types.Context } -func NewBackendWriter(buffered bool, ctx *types.Context) *BackendWriter { +func NewBackendWriter(buffered bool, ctx types.Context) *BackendWriter { return &BackendWriter{ BufferedOutput: buffered, Buffer: &bytes.Buffer{}, @@ -41,7 +41,7 @@ func (b *BackendWriter) Write(p []byte) (int, error) { return b.Buffer.Write(p) } - b.ctx.Msg("info", false, (string(p))) + b.ctx.Info((string(p))) return len(p), nil } diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index b90ad069..f902f8a0 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -30,8 +30,8 @@ import ( "time" bus "github.com/mudler/luet/pkg/api/core/bus" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/api/core/image" - "github.com/mudler/luet/pkg/api/core/types" artifact "github.com/mudler/luet/pkg/api/core/types/artifact" "github.com/mudler/luet/pkg/compiler/backend" "github.com/mudler/luet/pkg/compiler/types/options" @@ -82,7 +82,7 @@ func NewLuetCompiler(backend CompilerBackend, db pkg.PackageDatabase, compilerOp c := NewCompiler(compilerOpts...) if c.Options.Context == nil { - c.Options.Context = types.NewContext() + c.Options.Context = context.NewContext() } // c.Options.BackendType c.Backend = backend @@ -239,8 +239,10 @@ func (cs *LuetCompiler) unpackFs(concurrency int, keepPermissions bool, p *compi return nil, err } + ctx := cs.Options.Context.WithLoggingContext(fmt.Sprintf("extract %s", runnerOpts.ImageName)) + _, rootfs, err := image.Extract( - cs.Options.Context, + ctx, img, image.ExtractFiles( cs.Options.Context, @@ -273,7 +275,7 @@ func (cs *LuetCompiler) unpackFs(concurrency int, keepPermissions bool, p *compi func (cs *LuetCompiler) unpackDelta(concurrency int, keepPermissions bool, p *compilerspec.LuetCompilationSpec, builderOpts, runnerOpts backend.Options) (*artifact.PackageArtifact, error) { - rootfs, err := cs.Options.Context.Config.System.TempDir("rootfs") + rootfs, err := cs.Options.Context.TempDir("rootfs") if err != nil { return nil, errors.Wrap(err, "Could not create tempdir") } @@ -350,7 +352,7 @@ func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImag p.SetSeedImage(image) // In this case, we ignore the build deps as we suppose that the image has them - otherwise we recompose the tree with a solver, // and we build all the images first. - buildDir, err := cs.Options.Context.Config.System.TempDir("build") + buildDir, err := cs.Options.Context.TempDir("build") if err != nil { return builderOpts, runnerOpts, err } @@ -458,7 +460,7 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder if p.EmptyPackage() { fakePackage := p.Rel(p.GetPackage().GetFingerPrint() + ".package.tar") - rootfs, err = cs.Options.Context.Config.System.TempDir("rootfs") + rootfs, err = cs.Options.Context.TempDir("rootfs") if err != nil { return nil, errors.Wrap(err, "Could not create tempdir") } @@ -939,7 +941,7 @@ func (cs *LuetCompiler) resolveFinalImages(concurrency int, keepPermissions bool } // otherwise, generate it and push it aside - joinDir, err := cs.Options.Context.Config.System.TempDir("join") + joinDir, err := cs.Options.Context.TempDir("join") if err != nil { return errors.Wrap(err, "could not create tempdir for joining images") } @@ -978,7 +980,7 @@ func (cs *LuetCompiler) resolveFinalImages(concurrency int, keepPermissions bool } } - artifactDir, err := cs.Options.Context.Config.System.TempDir("join") + artifactDir, err := cs.Options.Context.TempDir("join") if err != nil { return errors.Wrap(err, "could not create tempdir for final artifact") } @@ -1341,7 +1343,7 @@ func (cs *LuetCompiler) templatePackage(vals []map[string]interface{}, pack pkg. } else { bv := cs.Options.BuildValuesFile if len(vals) > 0 { - valuesdir, err := cs.Options.Context.Config.System.TempDir("genvalues") + valuesdir, err := cs.Options.Context.TempDir("genvalues") if err != nil { return nil, errors.Wrap(err, "Could not create tempdir") } diff --git a/pkg/compiler/compiler_test.go b/pkg/compiler/compiler_test.go index e1db2cfd..e342256f 100644 --- a/pkg/compiler/compiler_test.go +++ b/pkg/compiler/compiler_test.go @@ -24,8 +24,8 @@ import ( helpers "github.com/mudler/luet/tests/helpers" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/api/core/image" - "github.com/mudler/luet/pkg/api/core/types" "github.com/mudler/luet/pkg/api/core/types/artifact" . "github.com/mudler/luet/pkg/compiler" sd "github.com/mudler/luet/pkg/compiler/backend" @@ -40,7 +40,7 @@ import ( ) var _ = Describe("Compiler", func() { - ctx := types.NewContext() + ctx := context.NewContext() Context("Simple package build definition", func() { It("Compiles it correctly", func() { @@ -51,7 +51,7 @@ var _ = Describe("Compiler", func() { Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3)) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2), options.WithContext(context.NewContext())) spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}) Expect(err).ToNot(HaveOccurred()) @@ -94,7 +94,7 @@ var _ = Describe("Compiler", func() { Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3)) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2), options.WithContext(context.NewContext())) spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "c", Category: "test", Version: "1.2"}) Expect(err).ToNot(HaveOccurred()) @@ -124,7 +124,7 @@ var _ = Describe("Compiler", func() { Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3)) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2), options.WithContext(context.NewContext())) spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "c", Category: "test", Version: "1.2"}) Expect(err).ToNot(HaveOccurred()) @@ -156,7 +156,7 @@ var _ = Describe("Compiler", func() { Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3)) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(1), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(1), options.WithContext(context.NewContext())) spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}) Expect(err).ToNot(HaveOccurred()) @@ -190,7 +190,7 @@ var _ = Describe("Compiler", func() { err = generalRecipe.Load("../../tests/fixtures/templates") Expect(err).ToNot(HaveOccurred()) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(context.NewContext())) Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(1)) pkg, err := generalRecipe.GetDatabase().FindPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}) @@ -214,7 +214,7 @@ var _ = Describe("Compiler", func() { Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(4)) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2), options.WithContext(context.NewContext())) spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "c", Category: "test", Version: "1.0"}) Expect(err).ToNot(HaveOccurred()) @@ -270,7 +270,7 @@ var _ = Describe("Compiler", func() { Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(2)) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(1), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(1), options.WithContext(context.NewContext())) spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "extra", Category: "layer", Version: "1.0"}) Expect(err).ToNot(HaveOccurred()) @@ -794,7 +794,7 @@ var _ = Describe("Compiler", func() { Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3)) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2), options.WithContext(context.NewContext())) spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "c", Category: "test", Version: "1.0"}) Expect(err).ToNot(HaveOccurred()) @@ -983,7 +983,7 @@ var _ = Describe("Compiler", func() { Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(2)) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(context.NewContext())) spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "runtime", Category: "layer", Version: "0.1"}) Expect(err).ToNot(HaveOccurred()) @@ -1018,7 +1018,7 @@ var _ = Describe("Compiler", func() { err := generalRecipe.Load("../../tests/fixtures/includeimage") Expect(err).ToNot(HaveOccurred()) Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(2)) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(context.NewContext())) specs, err := compiler.FromDatabase(generalRecipe.GetDatabase(), true, "") Expect(err).ToNot(HaveOccurred()) @@ -1037,7 +1037,7 @@ var _ = Describe("Compiler", func() { Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(2)) - compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(types.NewContext())) + compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(context.NewContext())) spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "runtime", Category: "layer", Version: "0.1"}) Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/compiler/imagehashtree_test.go b/pkg/compiler/imagehashtree_test.go index 61707fb4..d625811b 100644 --- a/pkg/compiler/imagehashtree_test.go +++ b/pkg/compiler/imagehashtree_test.go @@ -16,7 +16,7 @@ package compiler_test import ( - "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/context" . "github.com/mudler/luet/pkg/compiler" sd "github.com/mudler/luet/pkg/compiler/backend" "github.com/mudler/luet/pkg/compiler/types/options" @@ -27,7 +27,7 @@ import ( ) var _ = Describe("ImageHashTree", func() { - ctx := types.NewContext() + ctx := context.NewContext() generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false)) compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.Concurrency(2)) hashtree := NewHashTree(generalRecipe.GetDatabase()) diff --git a/pkg/compiler/types/options/compiler_options.go b/pkg/compiler/types/options/compiler_options.go index 6e2961ce..9e5afdc8 100644 --- a/pkg/compiler/types/options/compiler_options.go +++ b/pkg/compiler/types/options/compiler_options.go @@ -53,7 +53,7 @@ type Compiler struct { // Image repository to push to PushFinalImagesRepository string - Context *types.Context + Context types.Context } func NewDefaultCompiler() *Compiler { @@ -237,7 +237,7 @@ func WithSolverOptions(c types.LuetSolverOptions) func(cfg *Compiler) error { } } -func WithContext(c *types.Context) func(cfg *Compiler) error { +func WithContext(c types.Context) func(cfg *Compiler) error { return func(cfg *Compiler) error { cfg.Context = c return nil diff --git a/pkg/helpers/docker/docker.go b/pkg/helpers/docker/docker.go index 0aeb80b1..ee61c905 100644 --- a/pkg/helpers/docker/docker.go +++ b/pkg/helpers/docker/docker.go @@ -127,7 +127,7 @@ type UnpackEventData struct { } // DownloadAndExtractDockerImage extracts a container image natively. It supports privileged/unprivileged mode -func DownloadAndExtractDockerImage(ctx *luettypes.Context, image, dest string, auth *types.AuthConfig, verify bool) (*images.Image, error) { +func DownloadAndExtractDockerImage(ctx luettypes.Context, image, dest string, auth *types.AuthConfig, verify bool) (*images.Image, error) { if verify { img, err := verifyImage(image, auth) if err != nil { diff --git a/pkg/helpers/terminal/terminal_check_bsd.go b/pkg/helpers/terminal/terminal_check_bsd.go deleted file mode 100644 index d03a4f3c..00000000 --- a/pkg/helpers/terminal/terminal_check_bsd.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build darwin dragonfly freebsd netbsd openbsd - -package terminal - -import "golang.org/x/sys/unix" - -const ioctlReadTermios = unix.TIOCGETA - -func isTerminal(fd int) bool { - _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - return err == nil -} diff --git a/pkg/helpers/terminal/terminal_check_general.go b/pkg/helpers/terminal/terminal_check_general.go deleted file mode 100644 index 8dc980e0..00000000 --- a/pkg/helpers/terminal/terminal_check_general.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build !windows,!nacl,!plan9 - -package terminal - -import ( - "io" - "os" -) - -func IsTerminal(w io.Writer) bool { - switch v := w.(type) { - case *os.File: - return isTerminal(int(v.Fd())) - default: - return false - } -} diff --git a/pkg/helpers/terminal/terminal_check_no_terminal.go b/pkg/helpers/terminal/terminal_check_no_terminal.go deleted file mode 100644 index f567a7ad..00000000 --- a/pkg/helpers/terminal/terminal_check_no_terminal.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build js nacl plan9 - -package terminal - -import ( - "io" -) - -func IsTerminal(w io.Writer) bool { - return false -} diff --git a/pkg/helpers/terminal/terminal_check_solaris.go b/pkg/helpers/terminal/terminal_check_solaris.go deleted file mode 100644 index 0a8e2565..00000000 --- a/pkg/helpers/terminal/terminal_check_solaris.go +++ /dev/null @@ -1,11 +0,0 @@ -package terminal - -import ( - "golang.org/x/sys/unix" -) - -// IsTerminal returns true if the given file descriptor is a terminal. -func isTerminal(fd int) bool { - _, err := unix.IoctlGetTermio(fd, unix.TCGETA) - return err == nil -} diff --git a/pkg/helpers/terminal/terminal_check_unix.go b/pkg/helpers/terminal/terminal_check_unix.go deleted file mode 100644 index 8c0da7f5..00000000 --- a/pkg/helpers/terminal/terminal_check_unix.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build linux aix zos - -package terminal - -import "golang.org/x/sys/unix" - -const ioctlReadTermios = unix.TCGETS - -func isTerminal(fd int) bool { - _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - return err == nil -} diff --git a/pkg/helpers/terminal/terminal_check_windows.go b/pkg/helpers/terminal/terminal_check_windows.go deleted file mode 100644 index a4f6cb8a..00000000 --- a/pkg/helpers/terminal/terminal_check_windows.go +++ /dev/null @@ -1,27 +0,0 @@ -// +build windows - -package terminal - -import ( - "io" - "os" - - "golang.org/x/sys/windows" -) - -func IsTerminal(w io.Writer) bool { - switch v := w.(type) { - case *os.File: - handle := windows.Handle(v.Fd()) - var mode uint32 - if err := windows.GetConsoleMode(handle, &mode); err != nil { - return false - } - mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING - if err := windows.SetConsoleMode(handle, mode); err != nil { - return false - } - return true - } - return false -} diff --git a/pkg/installer/client/docker.go b/pkg/installer/client/docker.go index e17ac426..8a517ab8 100644 --- a/pkg/installer/client/docker.go +++ b/pkg/installer/client/docker.go @@ -24,9 +24,9 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/go-units" + luettypes "github.com/mudler/luet/pkg/api/core/types" "github.com/pkg/errors" - luetTypes "github.com/mudler/luet/pkg/api/core/types" "github.com/mudler/luet/pkg/api/core/types/artifact" "github.com/mudler/luet/pkg/helpers" @@ -42,17 +42,17 @@ type DockerClient struct { RepoData RepoData auth *types.AuthConfig Cache *artifact.ArtifactCache - context *luetTypes.Context + context luettypes.Context } -func NewDockerClient(r RepoData, ctx *luetTypes.Context) *DockerClient { +func NewDockerClient(r RepoData, ctx luettypes.Context) *DockerClient { auth := &types.AuthConfig{} dat, _ := json.Marshal(r.Authentication) json.Unmarshal(dat, auth) return &DockerClient{RepoData: r, auth: auth, - Cache: artifact.NewCache(ctx.Config.GetSystem().GetSystemPkgsCacheDirPath()), + Cache: artifact.NewCache(ctx.GetConfig().System.PkgsCachePath), context: ctx, } } @@ -81,13 +81,13 @@ func (c *DockerClient) DownloadArtifact(a *artifact.PackageArtifact) (*artifact. // We discard checksum, that are checked while during pull and unpack by containerd resultingArtifact.Checksums = artifact.Checksums{} - temp, err := c.context.Config.GetSystem().TempDir("image") + temp, err := c.context.TempDir("image") if err != nil { return nil, err } defer os.RemoveAll(temp) - tempArtifact, err := c.context.Config.GetSystem().TempFile("artifact") + tempArtifact, err := c.context.TempFile("artifact") if err != nil { return nil, err } @@ -144,13 +144,13 @@ func (c *DockerClient) DownloadFile(name string) (string, error) { // Files should be in URI/repository: ok := false - temp, err = c.context.Config.GetSystem().TempDir("tree") + temp, err = c.context.TempDir("tree") if err != nil { return "", err } for _, uri := range c.RepoData.Urls { - file, err = c.context.Config.GetSystem().TempFile("DockerClient") + file, err = c.context.TempFile("DockerClient") if err != nil { continue } diff --git a/pkg/installer/client/docker_test.go b/pkg/installer/client/docker_test.go index c2cc9f8a..c36c22cb 100644 --- a/pkg/installer/client/docker_test.go +++ b/pkg/installer/client/docker_test.go @@ -20,7 +20,7 @@ import ( "os" "path/filepath" - "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/api/core/types/artifact" compilerspec "github.com/mudler/luet/pkg/compiler/types/spec" fileHelper "github.com/mudler/luet/pkg/helpers/file" @@ -38,7 +38,7 @@ import ( // mount/unmount layers. var _ = Describe("Docker client", func() { Context("With repository", func() { - ctx := types.NewContext() + ctx := context.NewContext() repoImage := os.Getenv("UNIT_TEST_DOCKER_IMAGE") var repoURL []string diff --git a/pkg/installer/client/http.go b/pkg/installer/client/http.go index 37cd2bf3..25479770 100644 --- a/pkg/installer/client/http.go +++ b/pkg/installer/client/http.go @@ -36,13 +36,13 @@ import ( type HttpClient struct { RepoData RepoData Cache *artifact.ArtifactCache - context *types.Context + context types.Context } -func NewHttpClient(r RepoData, ctx *types.Context) *HttpClient { +func NewHttpClient(r RepoData, ctx types.Context) *HttpClient { return &HttpClient{ RepoData: r, - Cache: artifact.NewCache(ctx.Config.GetSystem().GetSystemPkgsCacheDirPath()), + Cache: artifact.NewCache(ctx.GetConfig().System.PkgsCachePath), context: ctx, } } @@ -85,16 +85,16 @@ func Round(input float64) float64 { func (c *HttpClient) DownloadFile(p string) (string, error) { var file *os.File = nil var downloaded bool - temp, err := c.context.Config.GetSystem().TempDir("download") + temp, err := c.context.TempDir("download") if err != nil { return "", err } defer os.RemoveAll(temp) - client := NewGrabClient(c.context.Config.General.HTTPTimeout) + client := NewGrabClient(c.context.GetConfig().General.HTTPTimeout) for _, uri := range c.RepoData.Urls { - file, err = c.context.Config.GetSystem().TempFile("HttpClient") + file, err = c.context.TempFile("HttpClient") if err != nil { c.context.Debug("Failed downloading", p, "from", uri) @@ -117,9 +117,12 @@ func (c *HttpClient) DownloadFile(p string) (string, error) { // Initialize a progressbar only if we have one in the current context var pb *pterm.ProgressbarPrinter - if c.context.ProgressBar != nil { - pb, _ = c.context.ProgressBar.WithTotal(int(resp.Size())).WithTitle(filepath.Base(resp.Request.HTTPRequest.URL.RequestURI())).Start() + pbb := c.context.GetAnnotation("progressbar") + switch v := pbb.(type) { + case *pterm.ProgressbarPrinter: + pb, _ = v.WithTotal(int(resp.Size())).WithTitle(filepath.Base(resp.Request.HTTPRequest.URL.RequestURI())).Start() } + // start download loop t := time.NewTicker(500 * time.Millisecond) defer t.Stop() diff --git a/pkg/installer/client/http_test.go b/pkg/installer/client/http_test.go index a842ec85..798ceb72 100644 --- a/pkg/installer/client/http_test.go +++ b/pkg/installer/client/http_test.go @@ -22,7 +22,7 @@ import ( "os" "path/filepath" - "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/api/core/types/artifact" fileHelper "github.com/mudler/luet/pkg/helpers/file" . "github.com/mudler/luet/pkg/installer/client" @@ -32,7 +32,7 @@ import ( var _ = Describe("Http client", func() { Context("With repository", func() { - ctx := types.NewContext() + ctx := context.NewContext() It("Downloads single files", func() { // setup small staticfile webserver with content diff --git a/pkg/installer/client/local.go b/pkg/installer/client/local.go index b8bf93d1..72a19dd7 100644 --- a/pkg/installer/client/local.go +++ b/pkg/installer/client/local.go @@ -29,12 +29,12 @@ import ( type LocalClient struct { RepoData RepoData Cache *artifact.ArtifactCache - context *types.Context + context types.Context } -func NewLocalClient(r RepoData, ctx *types.Context) *LocalClient { +func NewLocalClient(r RepoData, ctx types.Context) *LocalClient { return &LocalClient{ - Cache: artifact.NewCache(ctx.Config.GetSystem().GetSystemPkgsCacheDirPath()), + Cache: artifact.NewCache(ctx.GetConfig().System.PkgsCachePath), RepoData: r, context: ctx, } @@ -78,11 +78,8 @@ func (c *LocalClient) DownloadFile(name string) (string, error) { rootfs := "" - if !c.context.Config.ConfigFromHost { - rootfs, err = c.context.Config.GetSystem().GetRootFsAbs() - if err != nil { - return "", err - } + if !c.context.GetConfig().ConfigFromHost { + rootfs = c.context.GetConfig().System.Rootfs } ok := false @@ -91,7 +88,7 @@ func (c *LocalClient) DownloadFile(name string) (string, error) { uri = filepath.Join(rootfs, uri) c.context.Info("Copying file", name, "from", uri) - file, err = c.context.Config.GetSystem().TempFile("localclient") + file, err = c.context.TempFile("localclient") if err != nil { continue } diff --git a/pkg/installer/client/local_test.go b/pkg/installer/client/local_test.go index e0bdab16..a865b070 100644 --- a/pkg/installer/client/local_test.go +++ b/pkg/installer/client/local_test.go @@ -20,7 +20,7 @@ import ( "os" "path/filepath" - "github.com/mudler/luet/pkg/api/core/types" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/api/core/types/artifact" fileHelper "github.com/mudler/luet/pkg/helpers/file" . "github.com/mudler/luet/pkg/installer/client" @@ -30,7 +30,7 @@ import ( var _ = Describe("Local client", func() { Context("With repository", func() { - ctx := types.NewContext() + ctx := context.NewContext() It("Downloads single files", func() { tmpdir, err := ioutil.TempDir("", "test") diff --git a/pkg/installer/finalizer.go b/pkg/installer/finalizer.go index f42f0340..3419c8e5 100644 --- a/pkg/installer/finalizer.go +++ b/pkg/installer/finalizer.go @@ -32,7 +32,7 @@ type LuetFinalizer struct { Uninstall []string `json:"uninstall"` // TODO: Where to store? } -func (f *LuetFinalizer) RunInstall(ctx *types.Context, s *System) error { +func (f *LuetFinalizer) RunInstall(ctx types.Context, s *System) error { var cmd string var args []string if len(f.Shell) == 0 { @@ -51,14 +51,14 @@ func (f *LuetFinalizer) RunInstall(ctx *types.Context, s *System) error { ctx.Info(":shell: Executing finalizer on ", s.Target, cmd, toRun) if s.Target == string(os.PathSeparator) { cmd := exec.Command(cmd, toRun...) - cmd.Env = ctx.Config.GetFinalizerEnvs() + cmd.Env = ctx.GetConfig().FinalizerEnvs.Slice() stdoutStderr, err := cmd.CombinedOutput() if err != nil { return errors.Wrap(err, "Failed running command: "+string(stdoutStderr)) } ctx.Info(string(stdoutStderr)) } else { - b := box.NewBox(cmd, toRun, []string{}, ctx.Config.GetFinalizerEnvs(), s.Target, false, true, true) + b := box.NewBox(cmd, toRun, []string{}, ctx.GetConfig().FinalizerEnvs.Slice(), s.Target, false, true, true) err := b.Run() if err != nil { return errors.Wrap(err, "Failed running command ") @@ -69,7 +69,7 @@ func (f *LuetFinalizer) RunInstall(ctx *types.Context, s *System) error { } // TODO: We don't store uninstall finalizers ?! -func (f *LuetFinalizer) RunUnInstall(ctx *types.Context) error { +func (f *LuetFinalizer) RunUnInstall(ctx types.Context) error { for _, c := range f.Uninstall { ctx.Debug("finalizer:", "sh", "-c", c) cmd := exec.Command("sh", "-c", c) diff --git a/pkg/installer/installer.go b/pkg/installer/installer.go index cae3f220..879f3e2e 100644 --- a/pkg/installer/installer.go +++ b/pkg/installer/installer.go @@ -25,6 +25,7 @@ import ( "sync" "github.com/mudler/luet/pkg/api/core/config" + "github.com/mudler/luet/pkg/api/core/logger" "github.com/mudler/luet/pkg/api/core/bus" "github.com/mudler/luet/pkg/api/core/types" @@ -54,7 +55,7 @@ type LuetInstallerOptions struct { PackageRepositories types.LuetRepositories AutoOSCheck bool - Context *types.Context + Context types.Context } type LuetInstaller struct { @@ -737,13 +738,15 @@ func (l *LuetInstaller) download(syncedRepos Repositories, toDownload map[string // Check if the terminal is big enough to display a progress bar // https://github.com/pterm/pterm/blob/4c725e56bfd9eb38e1c7b9dec187b50b93baa8bd/progressbar_printer.go#L190 - w, _, err := ctx.GetTerminalSize() + w, _, err := logger.GetTerminalSize() var pb *pterm.ProgressbarPrinter - if ctx.IsTerminal && err == nil && w > 100 { + if logger.IsTerminal() && err == nil && w > 100 { area, _ := pterm.DefaultArea.Start() - ctx.ProgressBar = pterm.DefaultProgressbar.WithPrintTogether(area).WithTotal(len(toDownload)).WithTitle("Downloading packages") - pb, _ = ctx.ProgressBar.Start() + pb = pterm.DefaultProgressbar.WithPrintTogether(area).WithTotal(len(toDownload)).WithTitle("Downloading packages") + pb, _ = pb.Start() + ctx.SetAnnotation("progressbar", pb) + defer area.Stop() } @@ -1046,7 +1049,7 @@ func (l *LuetInstaller) install(o Option, syncedRepos Repositories, toInstall ma return s.ExecuteFinalizers(l.Options.Context, toFinalize) } -func (l *LuetInstaller) getPackage(a ArtifactMatch, ctx *types.Context) (artifact *artifact.PackageArtifact, err error) { +func (l *LuetInstaller) getPackage(a ArtifactMatch, ctx types.Context) (artifact *artifact.PackageArtifact, err error) { cli := a.Repository.Client(ctx) @@ -1084,7 +1087,7 @@ func (l *LuetInstaller) installPackage(m ArtifactMatch, s *System) error { return s.Database.SetPackageFiles(&pkg.PackageFile{PackageFingerprint: m.Package.GetFingerPrint(), Files: files}) } -func (l *LuetInstaller) downloadWorker(i int, wg *sync.WaitGroup, pb *pterm.ProgressbarPrinter, c <-chan ArtifactMatch, ctx *types.Context) error { +func (l *LuetInstaller) downloadWorker(i int, wg *sync.WaitGroup, pb *pterm.ProgressbarPrinter, c <-chan ArtifactMatch, ctx types.Context) error { defer wg.Done() for p := range c { @@ -1114,7 +1117,7 @@ func (l *LuetInstaller) installerWorker(i int, wg *sync.WaitGroup, installLock * installLock.Unlock() if err != nil && !l.Options.Force { //TODO: Uninstall, rollback. - l.Options.Context.Fatal("Failed installing package "+p.Package.GetName(), err.Error()) + l.Options.Context.Error("Failed installing package "+p.Package.GetName(), err.Error()) return errors.Wrap(err, "Failed installing package "+p.Package.GetName()) } if err == nil { @@ -1127,7 +1130,7 @@ func (l *LuetInstaller) installerWorker(i int, wg *sync.WaitGroup, installLock * return nil } -func checkAndPrunePath(ctx *types.Context, target, path string) { +func checkAndPrunePath(ctx types.Context, target, path string) { // check if now the target path is empty targetPath := filepath.Dir(path) @@ -1159,7 +1162,7 @@ func checkAndPrunePath(ctx *types.Context, target, path string) { } // We will try to cleanup every path from the file, if the folders left behind are empty -func pruneEmptyFilePath(ctx *types.Context, target string, path string) { +func pruneEmptyFilePath(ctx types.Context, target string, path string) { checkAndPrunePath(ctx, target, path) // A path is for e.g. /usr/bin/bar @@ -1193,7 +1196,7 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error { return errors.Wrap(err, "Failed getting installed files") } - if !l.Options.Context.Config.ConfigProtectSkip { + if !l.Options.Context.GetConfig().ConfigProtectSkip { if p.HasAnnotation(string(pkg.ConfigProtectAnnnotation)) { dir, ok := p.GetAnnotations()[string(pkg.ConfigProtectAnnnotation)] @@ -1203,7 +1206,7 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error { } cp = config.NewConfigProtect(annotationDir) - cp.Map(files, l.Options.Context.Config.GetConfigProtectConfFiles()) + cp.Map(files, l.Options.Context.GetConfig().ConfigProtectConfFiles) } toRemove, notPresent := fileHelper.OrderFiles(s.Target, files) @@ -1212,15 +1215,15 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error { for _, f := range toRemove { target := filepath.Join(s.Target, f) - if !l.Options.Context.Config.ConfigProtectSkip && cp.Protected(f) { + if !l.Options.Context.GetConfig().ConfigProtectSkip && cp.Protected(f) { l.Options.Context.Debug("Preserving protected file:", f) continue } l.Options.Context.Debug("Removing", target) if l.Options.PreserveSystemEssentialData && - strings.HasPrefix(f, l.Options.Context.Config.GetSystem().GetSystemPkgsCacheDirPath()) || - strings.HasPrefix(f, l.Options.Context.Config.GetSystem().GetSystemRepoDatabaseDirPath()) { + strings.HasPrefix(f, l.Options.Context.GetConfig().System.PkgsCachePath) || + strings.HasPrefix(f, l.Options.Context.GetConfig().System.DatabasePath) { l.Options.Context.Warning("Preserve ", f, " which is required by luet ( you have to delete it manually if you really need to)") continue } @@ -1254,7 +1257,7 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error { for _, f := range notPresent { target := filepath.Join(s.Target, f) - if !l.Options.Context.Config.ConfigProtectSkip && cp.Protected(f) { + if !l.Options.Context.GetConfig().ConfigProtectSkip && cp.Protected(f) { l.Options.Context.Debug("Preserving protected file:", f) continue } diff --git a/pkg/installer/installer_test.go b/pkg/installer/installer_test.go index 1a839283..aece3c41 100644 --- a/pkg/installer/installer_test.go +++ b/pkg/installer/installer_test.go @@ -21,6 +21,7 @@ import ( "path/filepath" // . "github.com/mudler/luet/pkg/installer" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/api/core/types" compiler "github.com/mudler/luet/pkg/compiler" backend "github.com/mudler/luet/pkg/compiler/backend" @@ -45,16 +46,16 @@ func stubRepo(tmpdir, tree string) (*LuetSystemRepository, error) { WithPriority(1), WithSource(tmpdir), WithTree(tree), - WithContext(types.NewContext()), + WithContext(context.NewContext()), WithDatabase(pkg.NewInMemoryDatabase(false)), ) } var _ = Describe("Installer", func() { - ctx := types.NewContext() + ctx := context.NewContext() BeforeEach(func() { - ctx = types.NewContext() + ctx = context.NewContext() }) Context("Writes a repository definition", func() { diff --git a/pkg/installer/repository.go b/pkg/installer/repository.go index 09c5be60..facfd704 100644 --- a/pkg/installer/repository.go +++ b/pkg/installer/repository.go @@ -115,11 +115,11 @@ func SystemRepositories(t types.LuetRepositories) Repositories { } // LoadBuildTree loads to the tree the compilation specs from the system repositories -func LoadBuildTree(t tree.Builder, db pkg.PackageDatabase, ctx *types.Context) error { +func LoadBuildTree(t tree.Builder, db pkg.PackageDatabase, ctx types.Context) error { var reserr error - repos := SystemRepositories(ctx.Config.SystemRepositories) + repos := SystemRepositories(ctx.GetConfig().SystemRepositories) for _, r := range repos { - repodir, err := ctx.Config.GetSystem().TempDir(r.Name) + repodir, err := ctx.TempDir(r.Name) if err != nil { reserr = multierr.Append(reserr, err) } @@ -378,7 +378,7 @@ func (r *LuetSystemRepository) SetPriority(n int) { r.LuetRepository.Priority = n } -func (r *LuetSystemRepository) initialize(ctx *types.Context, src string) error { +func (r *LuetSystemRepository) initialize(ctx types.Context, src string) error { generator, err := r.getGenerator(ctx, r.snapshotID) if err != nil { return errors.Wrap(err, "while constructing repository generator") @@ -526,12 +526,12 @@ func (r *LuetSystemRepository) BumpRevision(repospec string, resetRevision bool) // AddMetadata adds the repository serialized content into the metadata key of the repository // It writes the serialized content to repospec, and writes the repository.meta.yaml file into dst -func (r *LuetSystemRepository) AddMetadata(ctx *types.Context, repospec, dst string) (*artifact.PackageArtifact, error) { +func (r *LuetSystemRepository) AddMetadata(ctx types.Context, repospec, dst string) (*artifact.PackageArtifact, error) { // Create Metadata struct and serialized repository meta, serialized := r.Serialize() // Create metadata file and repository file - metaTmpDir, err := ctx.Config.GetSystem().TempDir("metadata") + metaTmpDir, err := ctx.TempDir("metadata") defer os.RemoveAll(metaTmpDir) // clean up if err != nil { return nil, errors.Wrap(err, "Error met while creating tempdir for metadata") @@ -564,9 +564,9 @@ func (r *LuetSystemRepository) AddMetadata(ctx *types.Context, repospec, dst str // AddTree adds a tree.Builder with the given key to the repository. // It will generate an artifact which will be then embedded in the repository manifest // It returns the generated artifacts and an error -func (r *LuetSystemRepository) AddTree(ctx *types.Context, t tree.Builder, dst, key string, defaults LuetRepositoryFile) (*artifact.PackageArtifact, error) { +func (r *LuetSystemRepository) AddTree(ctx types.Context, t tree.Builder, dst, key string, defaults LuetRepositoryFile) (*artifact.PackageArtifact, error) { // Create tree and repository file - archive, err := ctx.Config.GetSystem().TempDir("archive") + archive, err := ctx.TempDir("archive") if err != nil { return nil, errors.Wrap(err, "Error met while creating tempdir for archive") } @@ -710,7 +710,7 @@ type RepositoryGenerator interface { Initialize(string, pkg.PackageDatabase) ([]*artifact.PackageArtifact, error) } -func (r *LuetSystemRepository) getGenerator(ctx *types.Context, snapshotID string) (RepositoryGenerator, error) { +func (r *LuetSystemRepository) getGenerator(ctx types.Context, snapshotID string) (RepositoryGenerator, error) { if snapshotID == "" { snapshotID = time.Now().Format("20060102150405") } @@ -735,7 +735,7 @@ func (r *LuetSystemRepository) getGenerator(ctx *types.Context, snapshotID strin } // Write writes the repository metadata to the supplied destination -func (r *LuetSystemRepository) Write(ctx *types.Context, dst string, resetRevision, force bool) error { +func (r *LuetSystemRepository) Write(ctx types.Context, dst string, resetRevision, force bool) error { rg, err := r.getGenerator(ctx, r.snapshotID) if err != nil { return err @@ -744,7 +744,7 @@ func (r *LuetSystemRepository) Write(ctx *types.Context, dst string, resetRevisi return rg.Generate(r, dst, resetRevision) } -func (r *LuetSystemRepository) Client(ctx *types.Context) Client { +func (r *LuetSystemRepository) Client(ctx types.Context) Client { switch r.GetType() { case DiskRepositoryType: return client.NewLocalClient(client.RepoData{Urls: r.GetUrls()}, ctx) @@ -803,7 +803,7 @@ func (r *LuetSystemRepository) getRepoFile(c Client, key string) (*artifact.Pack } -func (r *LuetSystemRepository) SyncBuildMetadata(ctx *types.Context, path string) error { +func (r *LuetSystemRepository) SyncBuildMetadata(ctx types.Context, path string) error { repo, err := r.Sync(ctx, false) if err != nil { @@ -852,11 +852,11 @@ func (r *LuetSystemRepository) referenceID() string { return repositoryReferenceID } -func (r *LuetSystemRepository) Sync(ctx *types.Context, force bool) (*LuetSystemRepository, error) { +func (r *LuetSystemRepository) Sync(ctx types.Context, force bool) (*LuetSystemRepository, error) { var repoUpdated bool = false var treefs, metafs string - repobasedir := ctx.Config.GetSystem().GetRepoDatabaseDirPath(r.GetName()) + repobasedir := ctx.GetConfig().System.GetRepoDatabaseDirPath(r.GetName()) toTimeSync := false dat, err := ioutil.ReadFile(filepath.Join(repobasedir, "SYNCTIME")) @@ -923,11 +923,11 @@ func (r *LuetSystemRepository) Sync(ctx *types.Context, force bool) (*LuetSystem } } else { - treefs, err = ctx.Config.GetSystem().TempDir("treefs") + treefs, err = ctx.TempDir("treefs") if err != nil { return nil, errors.Wrap(err, "Error met while creating tempdir for rootfs") } - metafs, err = ctx.Config.GetSystem().TempDir("metafs") + metafs, err = ctx.TempDir("metafs") if err != nil { return nil, errors.Wrap(err, "Error met whilte creating tempdir for metafs") } diff --git a/pkg/installer/repository_docker.go b/pkg/installer/repository_docker.go index a2049c02..eb46503f 100644 --- a/pkg/installer/repository_docker.go +++ b/pkg/installer/repository_docker.go @@ -40,7 +40,7 @@ type dockerRepositoryGenerator struct { b compiler.CompilerBackend imagePrefix, snapshotID string imagePush, force bool - context *types.Context + context types.Context } func (l *dockerRepositoryGenerator) Initialize(path string, db pkg.PackageDatabase) ([]*artifact.PackageArtifact, error) { @@ -115,7 +115,7 @@ func (l *dockerRepositoryGenerator) Initialize(path string, db pkg.PackageDataba return art, nil } -func pushImage(ctx *types.Context, b compiler.CompilerBackend, image string, force bool) error { +func pushImage(ctx types.Context, b compiler.CompilerBackend, image string, force bool) error { if b.ImageAvailable(image) && !force { ctx.Debug("Image", image, "already present, skipping") return nil @@ -138,7 +138,7 @@ func (d *dockerRepositoryGenerator) pushFileFromArtifact(a *artifact.PackageArti func (d *dockerRepositoryGenerator) pushRepoMetadata(repospec, tag string, r *LuetSystemRepository) error { // create temp dir for metafile - metaDir, err := d.context.Config.GetSystem().TempDir("metadata") + metaDir, err := d.context.TempDir("metadata") if err != nil { return errors.Wrap(err, "Error met while creating tempdir for metadata") } @@ -184,7 +184,7 @@ func (d *dockerRepositoryGenerator) Generate(r *LuetSystemRepository, imagePrefi r.LastUpdate = strconv.FormatInt(time.Now().Unix(), 10) - repoTemp, err := d.context.Config.GetSystem().TempDir("repo") + repoTemp, err := d.context.TempDir("repo") if err != nil { return errors.Wrap(err, "error met while creating tempdir for repository") } diff --git a/pkg/installer/repository_local.go b/pkg/installer/repository_local.go index 355ed190..ee9e11a0 100644 --- a/pkg/installer/repository_local.go +++ b/pkg/installer/repository_local.go @@ -33,7 +33,7 @@ import ( ) type localRepositoryGenerator struct { - context *types.Context + context types.Context snapshotID string } @@ -41,7 +41,7 @@ func (l *localRepositoryGenerator) Initialize(path string, db pkg.PackageDatabas return buildPackageIndex(l.context, path, db) } -func buildPackageIndex(ctx *types.Context, path string, db pkg.PackageDatabase) ([]*artifact.PackageArtifact, error) { +func buildPackageIndex(ctx types.Context, path string, db pkg.PackageDatabase) ([]*artifact.PackageArtifact, error) { var art []*artifact.PackageArtifact var ff = func(currentpath string, info os.FileInfo, err error) error { diff --git a/pkg/installer/repository_options.go b/pkg/installer/repository_options.go index 023fde3e..a6751b3e 100644 --- a/pkg/installer/repository_options.go +++ b/pkg/installer/repository_options.go @@ -33,7 +33,7 @@ type RepositoryConfig struct { CompilerBackend compiler.CompilerBackend ImagePrefix string - context *types.Context + context types.Context PushImages, Force, FromRepository, FromMetadata bool } @@ -51,7 +51,7 @@ func (cfg *RepositoryConfig) Apply(opts ...RepositoryOption) error { return nil } -func WithContext(c *types.Context) func(cfg *RepositoryConfig) error { +func WithContext(c types.Context) func(cfg *RepositoryConfig) error { return func(cfg *RepositoryConfig) error { cfg.context = c return nil diff --git a/pkg/installer/repository_test.go b/pkg/installer/repository_test.go index e61276ca..1d5fe3d1 100644 --- a/pkg/installer/repository_test.go +++ b/pkg/installer/repository_test.go @@ -24,6 +24,7 @@ import ( "os" "path/filepath" + "github.com/mudler/luet/pkg/api/core/context" "github.com/mudler/luet/pkg/api/core/types" artifact "github.com/mudler/luet/pkg/api/core/types/artifact" "github.com/mudler/luet/pkg/compiler" @@ -49,16 +50,16 @@ func dockerStubRepo(tmpdir, tree, image string, push, force bool) (*LuetSystemRe WithSource(tmpdir), WithTree(tree), WithDatabase(pkg.NewInMemoryDatabase(false)), - WithCompilerBackend(backend.NewSimpleDockerBackend(types.NewContext())), + WithCompilerBackend(backend.NewSimpleDockerBackend(context.NewContext())), WithImagePrefix(image), WithPushImages(push), - WithContext(types.NewContext()), + WithContext(context.NewContext()), WithForce(force)) } var _ = Describe("Repository", func() { Context("Generation", func() { - ctx := types.NewContext() + ctx := context.NewContext() It("Generate repository metadata", func() { tmpdir, err := ioutil.TempDir("", "tree") @@ -139,11 +140,11 @@ var _ = Describe("Repository", func() { Expect(len(generalRecipe2.GetDatabase().GetPackages())).To(Equal(1)) Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3)) - compiler2 := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(ctx), generalRecipe2.GetDatabase(), options.WithContext(types.NewContext())) + compiler2 := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(ctx), generalRecipe2.GetDatabase(), options.WithContext(context.NewContext())) spec2, err := compiler2.FromPackage(&pkg.DefaultPackage{Name: "alpine", Category: "seed", Version: "1.0"}) Expect(err).ToNot(HaveOccurred()) - compiler := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(types.NewContext())) + compiler := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(context.NewContext())) spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"}) Expect(err).ToNot(HaveOccurred()) @@ -466,12 +467,12 @@ urls: }) Context("Docker repository", func() { repoImage := os.Getenv("UNIT_TEST_DOCKER_IMAGE_REPOSITORY") - ctx := types.NewContext() + ctx := context.NewContext() BeforeEach(func() { if repoImage == "" { Skip("UNIT_TEST_DOCKER_IMAGE_REPOSITORY not specified") } - ctx = types.NewContext() + ctx = context.NewContext() }) It("generates images", func() { diff --git a/pkg/installer/system.go b/pkg/installer/system.go index 7171f853..dfb7b137 100644 --- a/pkg/installer/system.go +++ b/pkg/installer/system.go @@ -40,7 +40,7 @@ func (s *System) OSCheck() (notFound pkg.Packages) { return } -func (s *System) ExecuteFinalizers(ctx *types.Context, packs []pkg.Package) error { +func (s *System) ExecuteFinalizers(ctx types.Context, packs []pkg.Package) error { var errs error executedFinalizer := map[string]bool{} for _, p := range packs { diff --git a/vendor/github.com/ipfs/go-log/v2/LICENSE b/vendor/github.com/ipfs/go-log/v2/LICENSE new file mode 100644 index 00000000..c7386b3c --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Juan Batiz-Benet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-log/v2/README.md b/vendor/github.com/ipfs/go-log/v2/README.md new file mode 100644 index 00000000..c996715a --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/README.md @@ -0,0 +1,137 @@ +# go-log + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](https://ipfs.io/) +[![GoDoc](https://pkg.go.dev/badge/github.com/ipfs/go-log/v2.svg)](https://pkg.go.dev/github.com/ipfs/go-log/v2) + +> The logging library used by go-ipfs + +go-log wraps [zap](https://github.com/uber-go/zap) to provide a logging facade. go-log manages logging +instances and allows for their levels to be controlled individually. + +## Install + +```sh +go get github.com/ipfs/go-log +``` + +## Usage + +Once the package is imported under the name `logging`, an instance of `EventLogger` can be created like so: + +```go +var log = logging.Logger("subsystem name") +``` + +It can then be used to emit log messages in plain printf-style messages at seven standard levels: + +Levels may be set for all loggers: + +```go +lvl, err := logging.LevelFromString("error") +if err != nil { + panic(err) +} +logging.SetAllLoggers(lvl) +``` + +or individually: + +```go +err := logging.SetLogLevel("net:pubsub", "info") +if err != nil { + panic(err) +} +``` + +or by regular expression: + +```go +err := logging.SetLogLevelRegex("net:.*", "info") +if err != nil { + panic(err) +} +``` + +### Environment Variables + +This package can be configured through various environment variables. + +#### `GOLOG_LOG_LEVEL` + +Specifies the log-level, both globally and on a per-subsystem basis. + +For example, the following will set the global minimum log level to `error`, but reduce the minimum +log level for `subsystem1` to `info` and reduce the minimum log level for `subsystem2` to debug. + +```bash +export GOLOG_LOG_LEVEL="error,subsystem1=info,subsystem2=debug" +``` + +`IPFS_LOGGING` is a deprecated alias for this environment variable. + +#### `GOLOG_FILE` + +Specifies that logs should be written to the specified file. If this option is _not_ specified, logs are written to standard error. + +```bash +export GOLOG_FILE="/path/to/my/file.log" +``` + +#### `GOLOG_OUTPUT` + +Specifies where logging output should be written. Can take one or more of the following values, combined with `+`: + +- `stdout` -- write logs to standard out. +- `stderr` -- write logs to standard error. +- `file` -- write logs to the file specified by `GOLOG_FILE` + +For example, if you want to log to both a file and standard error: + +```bash +export GOLOG_FILE="/path/to/my/file.log" +export GOLOG_OUTPUT="stderr+file" +``` + +Setting _only_ `GOLOG_FILE` will prevent logs from being written to standard error. + +#### `GOLOG_LOG_FMT` + +Specifies the log message format. It supports the following values: + +- `color` -- human readable, colorized (ANSI) output +- `nocolor` -- human readable, plain-text output. +- `json` -- structured JSON. + +For example, to log structured JSON (for easier parsing): + +```bash +export GOLOG_LOG_FMT="json" +``` + +The logging format defaults to `color` when the output is a terminal, and `nocolor` otherwise. + +`IPFS_LOGGING_FMT` is a deprecated alias for this environment variable. + +#### `GOLOG_LOG_LABELS` + +Specifies a set of labels that should be added to all log messages as comma-separated key-value +pairs. For example, the following add `{"app": "example_app", "dc": "sjc-1"}` to every log entry. + +```bash +export GOLOG_LOG_LABELS="app=example_app,dc=sjc-1" +``` + +## Contribute + +Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/go-log/issues)! + +This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +### Want to hack on IPFS? + +[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md) + +## License + +MIT diff --git a/vendor/github.com/ipfs/go-log/v2/core.go b/vendor/github.com/ipfs/go-log/v2/core.go new file mode 100644 index 00000000..56672d3e --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/core.go @@ -0,0 +1,121 @@ +package log + +import ( + "reflect" + "sync" + + "go.uber.org/multierr" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +var _ zapcore.Core = (*lockedMultiCore)(nil) + +type lockedMultiCore struct { + mu sync.RWMutex // guards mutations to cores slice + cores []zapcore.Core +} + +func (l *lockedMultiCore) With(fields []zapcore.Field) zapcore.Core { + l.mu.RLock() + defer l.mu.RUnlock() + sub := &lockedMultiCore{ + cores: make([]zapcore.Core, len(l.cores)), + } + for i := range l.cores { + sub.cores[i] = l.cores[i].With(fields) + } + return sub +} + +func (l *lockedMultiCore) Enabled(lvl zapcore.Level) bool { + l.mu.RLock() + defer l.mu.RUnlock() + for i := range l.cores { + if l.cores[i].Enabled(lvl) { + return true + } + } + return false +} + +func (l *lockedMultiCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { + l.mu.RLock() + defer l.mu.RUnlock() + for i := range l.cores { + ce = l.cores[i].Check(ent, ce) + } + return ce +} + +func (l *lockedMultiCore) Write(ent zapcore.Entry, fields []zapcore.Field) error { + l.mu.RLock() + defer l.mu.RUnlock() + var err error + for i := range l.cores { + err = multierr.Append(err, l.cores[i].Write(ent, fields)) + } + return err +} + +func (l *lockedMultiCore) Sync() error { + l.mu.RLock() + defer l.mu.RUnlock() + var err error + for i := range l.cores { + err = multierr.Append(err, l.cores[i].Sync()) + } + return err +} + +func (l *lockedMultiCore) AddCore(core zapcore.Core) { + l.mu.Lock() + defer l.mu.Unlock() + + l.cores = append(l.cores, core) +} + +func (l *lockedMultiCore) DeleteCore(core zapcore.Core) { + l.mu.Lock() + defer l.mu.Unlock() + + w := 0 + for i := 0; i < len(l.cores); i++ { + if reflect.DeepEqual(l.cores[i], core) { + continue + } + l.cores[w] = l.cores[i] + w++ + } + l.cores = l.cores[:w] +} + +func (l *lockedMultiCore) ReplaceCore(original, replacement zapcore.Core) { + l.mu.Lock() + defer l.mu.Unlock() + + for i := 0; i < len(l.cores); i++ { + if reflect.DeepEqual(l.cores[i], original) { + l.cores[i] = replacement + } + } +} + +func newCore(format LogFormat, ws zapcore.WriteSyncer, level LogLevel) zapcore.Core { + encCfg := zap.NewProductionEncoderConfig() + encCfg.EncodeTime = zapcore.ISO8601TimeEncoder + + var encoder zapcore.Encoder + switch format { + case PlaintextOutput: + encCfg.EncodeLevel = zapcore.CapitalLevelEncoder + encoder = zapcore.NewConsoleEncoder(encCfg) + case JSONOutput: + encoder = zapcore.NewJSONEncoder(encCfg) + default: + encCfg.EncodeLevel = zapcore.CapitalColorLevelEncoder + encoder = zapcore.NewConsoleEncoder(encCfg) + } + + return zapcore.NewCore(encoder, ws, zap.NewAtomicLevelAt(zapcore.Level(level))) +} diff --git a/vendor/github.com/ipfs/go-log/v2/go.mod b/vendor/github.com/ipfs/go-log/v2/go.mod new file mode 100644 index 00000000..721cde56 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/go.mod @@ -0,0 +1,9 @@ +module github.com/ipfs/go-log/v2 + +require ( + github.com/mattn/go-isatty v0.0.14 + go.uber.org/multierr v1.6.0 + go.uber.org/zap v1.16.0 +) + +go 1.16 diff --git a/vendor/github.com/ipfs/go-log/v2/go.sum b/vendor/github.com/ipfs/go-log/v2/go.sum new file mode 100644 index 00000000..bc4d81e5 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/go.sum @@ -0,0 +1,57 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/github.com/ipfs/go-log/v2/levels.go b/vendor/github.com/ipfs/go-log/v2/levels.go new file mode 100644 index 00000000..9d43a597 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/levels.go @@ -0,0 +1,30 @@ +package log + +import "go.uber.org/zap/zapcore" + +// LogLevel represents a log severity level. Use the package variables as an +// enum. +type LogLevel zapcore.Level + +var ( + LevelDebug = LogLevel(zapcore.DebugLevel) + LevelInfo = LogLevel(zapcore.InfoLevel) + LevelWarn = LogLevel(zapcore.WarnLevel) + LevelError = LogLevel(zapcore.ErrorLevel) + LevelDPanic = LogLevel(zapcore.DPanicLevel) + LevelPanic = LogLevel(zapcore.PanicLevel) + LevelFatal = LogLevel(zapcore.FatalLevel) +) + +// LevelFromString parses a string-based level and returns the corresponding +// LogLevel. +// +// Supported strings are: DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL, and +// their lower-case forms. +// +// The returned LogLevel must be discarded if error is not nil. +func LevelFromString(level string) (LogLevel, error) { + lvl := zapcore.InfoLevel // zero value + err := lvl.Set(level) + return LogLevel(lvl), err +} diff --git a/vendor/github.com/ipfs/go-log/v2/log.go b/vendor/github.com/ipfs/go-log/v2/log.go new file mode 100644 index 00000000..6b0c444c --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/log.go @@ -0,0 +1,84 @@ +// Package log is the logging library used by IPFS & libp2p +// (https://github.com/ipfs/go-ipfs). +package log + +import ( + "time" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// StandardLogger provides API compatibility with standard printf loggers +// eg. go-logging +type StandardLogger interface { + Debug(args ...interface{}) + Debugf(format string, args ...interface{}) + Error(args ...interface{}) + Errorf(format string, args ...interface{}) + Fatal(args ...interface{}) + Fatalf(format string, args ...interface{}) + Info(args ...interface{}) + Infof(format string, args ...interface{}) + Panic(args ...interface{}) + Panicf(format string, args ...interface{}) + Warn(args ...interface{}) + Warnf(format string, args ...interface{}) +} + +// EventLogger extends the StandardLogger interface to allow for log items +// containing structured metadata +type EventLogger interface { + StandardLogger +} + +// Logger retrieves an event logger by name +func Logger(system string) *ZapEventLogger { + if len(system) == 0 { + setuplog := getLogger("setup-logger") + setuplog.Error("Missing name parameter") + system = "undefined" + } + + logger := getLogger(system) + skipLogger := logger.Desugar().WithOptions(zap.AddCallerSkip(1)).Sugar() + + return &ZapEventLogger{ + system: system, + SugaredLogger: *logger, + skipLogger: *skipLogger, + } +} + +// ZapEventLogger implements the EventLogger and wraps a go-logging Logger +type ZapEventLogger struct { + zap.SugaredLogger + // used to fix the caller location when calling Warning and Warningf. + skipLogger zap.SugaredLogger + system string +} + +// Warning is for compatibility +// Deprecated: use Warn(args ...interface{}) instead +func (logger *ZapEventLogger) Warning(args ...interface{}) { + logger.skipLogger.Warn(args...) +} + +// Warningf is for compatibility +// Deprecated: use Warnf(format string, args ...interface{}) instead +func (logger *ZapEventLogger) Warningf(format string, args ...interface{}) { + logger.skipLogger.Warnf(format, args...) +} + +// FormatRFC3339 returns the given time in UTC with RFC3999Nano format. +func FormatRFC3339(t time.Time) string { + return t.UTC().Format(time.RFC3339Nano) +} + +func WithStacktrace(l *ZapEventLogger, level LogLevel) *ZapEventLogger { + copyLogger := *l + copyLogger.SugaredLogger = *copyLogger.SugaredLogger.Desugar(). + WithOptions(zap.AddStacktrace(zapcore.Level(level))).Sugar() + copyLogger.skipLogger = *copyLogger.SugaredLogger.Desugar().WithOptions(zap.AddCallerSkip(1)).Sugar() + return ©Logger +} diff --git a/vendor/github.com/ipfs/go-log/v2/path_other.go b/vendor/github.com/ipfs/go-log/v2/path_other.go new file mode 100644 index 00000000..9f41957c --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/path_other.go @@ -0,0 +1,12 @@ +//go:build !windows +// +build !windows + +package log + +import ( + "path/filepath" +) + +func normalizePath(p string) (string, error) { + return filepath.Abs(p) +} diff --git a/vendor/github.com/ipfs/go-log/v2/path_windows.go b/vendor/github.com/ipfs/go-log/v2/path_windows.go new file mode 100644 index 00000000..01f589aa --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/path_windows.go @@ -0,0 +1,36 @@ +//go:build windows +// +build windows + +package log + +import ( + "fmt" + "path/filepath" + "strings" +) + +func normalizePath(p string) (string, error) { + if p == "" { + return "", fmt.Errorf("path empty") + } + p, err := filepath.Abs(p) + if err != nil { + return "", err + } + // Is this _really_ an absolute path? + if !strings.HasPrefix(p, "\\\\") { + // It's a drive: path! + // Return a UNC path. + p = "\\\\%3F\\" + p + } + + // This will return file:////?/c:/foobar + // + // Why? Because: + // 1. Go will choke on file://c:/ because the "domain" includes a :. + // 2. Windows will choke on file:///c:/ because the path will be + // /c:/... which is _relative_ to the current drive. + // + // This path (a) has no "domain" and (b) starts with a slash. Yay! + return "file://" + filepath.ToSlash(p), nil +} diff --git a/vendor/github.com/ipfs/go-log/v2/pipe.go b/vendor/github.com/ipfs/go-log/v2/pipe.go new file mode 100644 index 00000000..7435b9dc --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/pipe.go @@ -0,0 +1,90 @@ +package log + +import ( + "io" + + "go.uber.org/multierr" + "go.uber.org/zap/zapcore" +) + +// A PipeReader is a reader that reads from the logger. It is synchronous +// so blocking on read will affect logging performance. +type PipeReader struct { + r *io.PipeReader + closer io.Closer + core zapcore.Core +} + +// Read implements the standard Read interface +func (p *PipeReader) Read(data []byte) (int, error) { + return p.r.Read(data) +} + +// Close unregisters the reader from the logger. +func (p *PipeReader) Close() error { + if p.core != nil { + loggerCore.DeleteCore(p.core) + } + return multierr.Append(p.core.Sync(), p.closer.Close()) +} + +// NewPipeReader creates a new in-memory reader that reads from all loggers +// The caller must call Close on the returned reader when done. +// +// By default, it: +// +// 1. Logs JSON. This can be changed by passing the PipeFormat option. +// 2. Logs everything that would otherwise be logged to the "primary" log +// output. That is, everything enabled by SetLogLevel. The minimum log level +// can be increased by passing the PipeLevel option. +func NewPipeReader(opts ...PipeReaderOption) *PipeReader { + opt := pipeReaderOptions{ + format: JSONOutput, + level: LevelDebug, + } + + for _, o := range opts { + o.setOption(&opt) + } + + r, w := io.Pipe() + + p := &PipeReader{ + r: r, + closer: w, + core: newCore(opt.format, zapcore.AddSync(w), opt.level), + } + + loggerCore.AddCore(p.core) + + return p +} + +type pipeReaderOptions struct { + format LogFormat + level LogLevel +} + +type PipeReaderOption interface { + setOption(*pipeReaderOptions) +} + +type pipeReaderOptionFunc func(*pipeReaderOptions) + +func (p pipeReaderOptionFunc) setOption(o *pipeReaderOptions) { + p(o) +} + +// PipeFormat sets the output format of the pipe reader +func PipeFormat(format LogFormat) PipeReaderOption { + return pipeReaderOptionFunc(func(o *pipeReaderOptions) { + o.format = format + }) +} + +// PipeLevel sets the log level of logs sent to the pipe reader. +func PipeLevel(level LogLevel) PipeReaderOption { + return pipeReaderOptionFunc(func(o *pipeReaderOptions) { + o.level = level + }) +} diff --git a/vendor/github.com/ipfs/go-log/v2/setup.go b/vendor/github.com/ipfs/go-log/v2/setup.go new file mode 100644 index 00000000..ffd84fbe --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/setup.go @@ -0,0 +1,390 @@ +package log + +import ( + "errors" + "fmt" + "os" + "regexp" + "strings" + "sync" + + "github.com/mattn/go-isatty" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +func init() { + SetupLogging(configFromEnv()) +} + +// Logging environment variables +const ( + // IPFS_* prefixed env vars kept for backwards compatibility + // for this release. They will not be available in the next + // release. + // + // GOLOG_* env vars take precedences over IPFS_* env vars. + envIPFSLogging = "IPFS_LOGGING" + envIPFSLoggingFmt = "IPFS_LOGGING_FMT" + + envLogging = "GOLOG_LOG_LEVEL" + envLoggingFmt = "GOLOG_LOG_FMT" + + envLoggingFile = "GOLOG_FILE" // /path/to/file + envLoggingURL = "GOLOG_URL" // url that will be processed by sink in the zap + + envLoggingOutput = "GOLOG_OUTPUT" // possible values: stdout|stderr|file combine multiple values with '+' + envLoggingLabels = "GOLOG_LOG_LABELS" // comma-separated key-value pairs, i.e. "app=example_app,dc=sjc-1" +) + +type LogFormat int + +const ( + ColorizedOutput LogFormat = iota + PlaintextOutput + JSONOutput +) + +type Config struct { + // Format overrides the format of the log output. Defaults to ColorizedOutput + Format LogFormat + + // Level is the default minimum enabled logging level. + Level LogLevel + + // SubsystemLevels are the default levels per-subsystem. When unspecified, defaults to Level. + SubsystemLevels map[string]LogLevel + + // Stderr indicates whether logs should be written to stderr. + Stderr bool + + // Stdout indicates whether logs should be written to stdout. + Stdout bool + + // File is a path to a file that logs will be written to. + File string + + // URL with schema supported by zap. Use zap.RegisterSink + URL string + + // Labels is a set of key-values to apply to all loggers + Labels map[string]string +} + +// ErrNoSuchLogger is returned when the util pkg is asked for a non existant logger +var ErrNoSuchLogger = errors.New("error: No such logger") + +var loggerMutex sync.RWMutex // guards access to global logger state + +// loggers is the set of loggers in the system +var loggers = make(map[string]*zap.SugaredLogger) +var levels = make(map[string]zap.AtomicLevel) + +// primaryFormat is the format of the primary core used for logging +var primaryFormat LogFormat = ColorizedOutput + +// defaultLevel is the default log level +var defaultLevel LogLevel = LevelError + +// primaryCore is the primary logging core +var primaryCore zapcore.Core + +// loggerCore is the base for all loggers created by this package +var loggerCore = &lockedMultiCore{} + +// SetupLogging will initialize the logger backend and set the flags. +// TODO calling this in `init` pushes all configuration to env variables +// - move it out of `init`? then we need to change all the code (js-ipfs, go-ipfs) to call this explicitly +// - have it look for a config file? need to define what that is +func SetupLogging(cfg Config) { + loggerMutex.Lock() + defer loggerMutex.Unlock() + + primaryFormat = cfg.Format + defaultLevel = cfg.Level + + outputPaths := []string{} + + if cfg.Stderr { + outputPaths = append(outputPaths, "stderr") + } + if cfg.Stdout { + outputPaths = append(outputPaths, "stdout") + } + + // check if we log to a file + if len(cfg.File) > 0 { + if path, err := normalizePath(cfg.File); err != nil { + fmt.Fprintf(os.Stderr, "failed to resolve log path '%q', logging to %s\n", cfg.File, outputPaths) + } else { + outputPaths = append(outputPaths, path) + } + } + if len(cfg.URL) > 0 { + outputPaths = append(outputPaths, cfg.URL) + } + + ws, _, err := zap.Open(outputPaths...) + if err != nil { + panic(fmt.Sprintf("unable to open logging output: %v", err)) + } + + newPrimaryCore := newCore(primaryFormat, ws, LevelDebug) // the main core needs to log everything. + + for k, v := range cfg.Labels { + newPrimaryCore = newPrimaryCore.With([]zap.Field{zap.String(k, v)}) + } + + setPrimaryCore(newPrimaryCore) + setAllLoggers(defaultLevel) + + for name, level := range cfg.SubsystemLevels { + if leveler, ok := levels[name]; ok { + leveler.SetLevel(zapcore.Level(level)) + } else { + levels[name] = zap.NewAtomicLevelAt(zapcore.Level(level)) + } + } +} + +// SetPrimaryCore changes the primary logging core. If the SetupLogging was +// called then the previously configured core will be replaced. +func SetPrimaryCore(core zapcore.Core) { + loggerMutex.Lock() + defer loggerMutex.Unlock() + + setPrimaryCore(core) +} + +func setPrimaryCore(core zapcore.Core) { + if primaryCore != nil { + loggerCore.ReplaceCore(primaryCore, core) + } else { + loggerCore.AddCore(core) + } + primaryCore = core +} + +// SetDebugLogging calls SetAllLoggers with logging.DEBUG +func SetDebugLogging() { + SetAllLoggers(LevelDebug) +} + +// SetAllLoggers changes the logging level of all loggers to lvl +func SetAllLoggers(lvl LogLevel) { + loggerMutex.RLock() + defer loggerMutex.RUnlock() + + setAllLoggers(lvl) +} + +func setAllLoggers(lvl LogLevel) { + for _, l := range levels { + l.SetLevel(zapcore.Level(lvl)) + } +} + +// SetLogLevel changes the log level of a specific subsystem +// name=="*" changes all subsystems +func SetLogLevel(name, level string) error { + lvl, err := LevelFromString(level) + if err != nil { + return err + } + + // wildcard, change all + if name == "*" { + SetAllLoggers(lvl) + return nil + } + + loggerMutex.RLock() + defer loggerMutex.RUnlock() + + // Check if we have a logger by that name + if _, ok := levels[name]; !ok { + return ErrNoSuchLogger + } + + levels[name].SetLevel(zapcore.Level(lvl)) + + return nil +} + +// SetLogLevelRegex sets all loggers to level `l` that match expression `e`. +// An error is returned if `e` fails to compile. +func SetLogLevelRegex(e, l string) error { + lvl, err := LevelFromString(l) + if err != nil { + return err + } + + rem, err := regexp.Compile(e) + if err != nil { + return err + } + + loggerMutex.Lock() + defer loggerMutex.Unlock() + for name := range loggers { + if rem.MatchString(name) { + levels[name].SetLevel(zapcore.Level(lvl)) + } + } + return nil +} + +// GetSubsystems returns a slice containing the +// names of the current loggers +func GetSubsystems() []string { + loggerMutex.RLock() + defer loggerMutex.RUnlock() + subs := make([]string, 0, len(loggers)) + + for k := range loggers { + subs = append(subs, k) + } + return subs +} + +func getLogger(name string) *zap.SugaredLogger { + loggerMutex.Lock() + defer loggerMutex.Unlock() + log, ok := loggers[name] + if !ok { + level, ok := levels[name] + if !ok { + level = zap.NewAtomicLevelAt(zapcore.Level(defaultLevel)) + levels[name] = level + } + log = zap.New(loggerCore). + WithOptions( + zap.IncreaseLevel(level), + zap.AddCaller(), + ). + Named(name). + Sugar() + + loggers[name] = log + } + + return log +} + +// configFromEnv returns a Config with defaults populated using environment variables. +func configFromEnv() Config { + cfg := Config{ + Format: ColorizedOutput, + Stderr: true, + Level: LevelError, + SubsystemLevels: map[string]LogLevel{}, + Labels: map[string]string{}, + } + + format := os.Getenv(envLoggingFmt) + if format == "" { + format = os.Getenv(envIPFSLoggingFmt) + } + + var noExplicitFormat bool + + switch format { + case "color": + cfg.Format = ColorizedOutput + case "nocolor": + cfg.Format = PlaintextOutput + case "json": + cfg.Format = JSONOutput + default: + if format != "" { + fmt.Fprintf(os.Stderr, "ignoring unrecognized log format '%s'\n", format) + } + noExplicitFormat = true + } + + lvl := os.Getenv(envLogging) + if lvl == "" { + lvl = os.Getenv(envIPFSLogging) + } + if lvl != "" { + for _, kvs := range strings.Split(lvl, ",") { + kv := strings.SplitN(kvs, "=", 2) + lvl, err := LevelFromString(kv[len(kv)-1]) + if err != nil { + fmt.Fprintf(os.Stderr, "error setting log level %q: %s\n", kvs, err) + continue + } + switch len(kv) { + case 1: + cfg.Level = lvl + case 2: + cfg.SubsystemLevels[kv[0]] = lvl + } + } + } + + cfg.File = os.Getenv(envLoggingFile) + // Disable stderr logging when a file is specified + // https://github.com/ipfs/go-log/issues/83 + if cfg.File != "" { + cfg.Stderr = false + } + + cfg.URL = os.Getenv(envLoggingURL) + output := os.Getenv(envLoggingOutput) + outputOptions := strings.Split(output, "+") + for _, opt := range outputOptions { + switch opt { + case "stdout": + cfg.Stdout = true + case "stderr": + cfg.Stderr = true + case "file": + if cfg.File == "" { + fmt.Fprint(os.Stderr, "please specify a GOLOG_FILE value to write to") + } + case "url": + if cfg.URL == "" { + fmt.Fprint(os.Stderr, "please specify a GOLOG_URL value to write to") + } + } + } + + // Check that neither of the requested Std* nor the file are TTYs + // At this stage (configFromEnv) we do not have a uniform list to examine yet + if noExplicitFormat && + !(cfg.Stdout && isTerm(os.Stdout)) && + !(cfg.Stderr && isTerm(os.Stderr)) && + // check this last: expensive + !(cfg.File != "" && pathIsTerm(cfg.File)) { + cfg.Format = PlaintextOutput + } + + labels := os.Getenv(envLoggingLabels) + if labels != "" { + labelKVs := strings.Split(labels, ",") + for _, label := range labelKVs { + kv := strings.Split(label, "=") + if len(kv) != 2 { + fmt.Fprint(os.Stderr, "invalid label k=v: ", label) + continue + } + cfg.Labels[kv[0]] = kv[1] + } + } + + return cfg +} + +func isTerm(f *os.File) bool { + return isatty.IsTerminal(f.Fd()) || isatty.IsCygwinTerminal(f.Fd()) +} + +func pathIsTerm(p string) bool { + // !!!no!!! O_CREAT, if we fail - we fail + f, err := os.OpenFile(p, os.O_WRONLY, 0) + if f != nil { + defer f.Close() // nolint:errcheck + } + return err == nil && isTerm(f) +} diff --git a/vendor/github.com/ipfs/go-log/v2/version.json b/vendor/github.com/ipfs/go-log/v2/version.json new file mode 100644 index 00000000..96210899 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/version.json @@ -0,0 +1,3 @@ +{ + "version": "v2.4.0" +} diff --git a/vendor/github.com/mattn/go-isatty/LICENSE b/vendor/github.com/mattn/go-isatty/LICENSE new file mode 100644 index 00000000..65dc692b --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/LICENSE @@ -0,0 +1,9 @@ +Copyright (c) Yasuhiro MATSUMOTO + +MIT License (Expat) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/mattn/go-isatty/README.md b/vendor/github.com/mattn/go-isatty/README.md new file mode 100644 index 00000000..38418353 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/README.md @@ -0,0 +1,50 @@ +# go-isatty + +[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty) +[![Codecov](https://codecov.io/gh/mattn/go-isatty/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-isatty) +[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master) +[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty) + +isatty for golang + +## Usage + +```go +package main + +import ( + "fmt" + "github.com/mattn/go-isatty" + "os" +) + +func main() { + if isatty.IsTerminal(os.Stdout.Fd()) { + fmt.Println("Is Terminal") + } else if isatty.IsCygwinTerminal(os.Stdout.Fd()) { + fmt.Println("Is Cygwin/MSYS2 Terminal") + } else { + fmt.Println("Is Not Terminal") + } +} +``` + +## Installation + +``` +$ go get github.com/mattn/go-isatty +``` + +## License + +MIT + +## Author + +Yasuhiro Matsumoto (a.k.a mattn) + +## Thanks + +* k-takata: base idea for IsCygwinTerminal + + https://github.com/k-takata/go-iscygpty diff --git a/vendor/github.com/mattn/go-isatty/doc.go b/vendor/github.com/mattn/go-isatty/doc.go new file mode 100644 index 00000000..17d4f90e --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/doc.go @@ -0,0 +1,2 @@ +// Package isatty implements interface to isatty +package isatty diff --git a/vendor/github.com/mattn/go-isatty/go.mod b/vendor/github.com/mattn/go-isatty/go.mod new file mode 100644 index 00000000..c9a20b7f --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/go.mod @@ -0,0 +1,5 @@ +module github.com/mattn/go-isatty + +go 1.12 + +require golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c diff --git a/vendor/github.com/mattn/go-isatty/go.sum b/vendor/github.com/mattn/go-isatty/go.sum new file mode 100644 index 00000000..912e29cb --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/mattn/go-isatty/go.test.sh b/vendor/github.com/mattn/go-isatty/go.test.sh new file mode 100644 index 00000000..012162b0 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/go.test.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e +echo "" > coverage.txt + +for d in $(go list ./... | grep -v vendor); do + go test -race -coverprofile=profile.out -covermode=atomic "$d" + if [ -f profile.out ]; then + cat profile.out >> coverage.txt + rm profile.out + fi +done diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go new file mode 100644 index 00000000..39bbcf00 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go @@ -0,0 +1,19 @@ +//go:build (darwin || freebsd || openbsd || netbsd || dragonfly) && !appengine +// +build darwin freebsd openbsd netbsd dragonfly +// +build !appengine + +package isatty + +import "golang.org/x/sys/unix" + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + _, err := unix.IoctlGetTermios(int(fd), unix.TIOCGETA) + return err == nil +} + +// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go new file mode 100644 index 00000000..31503226 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_others.go @@ -0,0 +1,16 @@ +//go:build appengine || js || nacl || wasm +// +build appengine js nacl wasm + +package isatty + +// IsTerminal returns true if the file descriptor is terminal which +// is always false on js and appengine classic which is a sandboxed PaaS. +func IsTerminal(fd uintptr) bool { + return false +} + +// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_plan9.go b/vendor/github.com/mattn/go-isatty/isatty_plan9.go new file mode 100644 index 00000000..bae7f9bb --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_plan9.go @@ -0,0 +1,23 @@ +//go:build plan9 +// +build plan9 + +package isatty + +import ( + "syscall" +) + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd uintptr) bool { + path, err := syscall.Fd2path(int(fd)) + if err != nil { + return false + } + return path == "/dev/cons" || path == "/mnt/term/dev/cons" +} + +// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go new file mode 100644 index 00000000..0c3acf2d --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_solaris.go @@ -0,0 +1,21 @@ +//go:build solaris && !appengine +// +build solaris,!appengine + +package isatty + +import ( + "golang.org/x/sys/unix" +) + +// IsTerminal returns true if the given file descriptor is a terminal. +// see: https://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libc/port/gen/isatty.c +func IsTerminal(fd uintptr) bool { + _, err := unix.IoctlGetTermio(int(fd), unix.TCGETA) + return err == nil +} + +// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go new file mode 100644 index 00000000..67787657 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go @@ -0,0 +1,19 @@ +//go:build (linux || aix || zos) && !appengine +// +build linux aix zos +// +build !appengine + +package isatty + +import "golang.org/x/sys/unix" + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + _, err := unix.IoctlGetTermios(int(fd), unix.TCGETS) + return err == nil +} + +// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 +// terminal. This is also always false on this environment. +func IsCygwinTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go new file mode 100644 index 00000000..8e3c9917 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_windows.go @@ -0,0 +1,125 @@ +//go:build windows && !appengine +// +build windows,!appengine + +package isatty + +import ( + "errors" + "strings" + "syscall" + "unicode/utf16" + "unsafe" +) + +const ( + objectNameInfo uintptr = 1 + fileNameInfo = 2 + fileTypePipe = 3 +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + ntdll = syscall.NewLazyDLL("ntdll.dll") + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx") + procGetFileType = kernel32.NewProc("GetFileType") + procNtQueryObject = ntdll.NewProc("NtQueryObject") +) + +func init() { + // Check if GetFileInformationByHandleEx is available. + if procGetFileInformationByHandleEx.Find() != nil { + procGetFileInformationByHandleEx = nil + } +} + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} + +// Check pipe name is used for cygwin/msys2 pty. +// Cygwin/MSYS2 PTY has a name like: +// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master +func isCygwinPipeName(name string) bool { + token := strings.Split(name, "-") + if len(token) < 5 { + return false + } + + if token[0] != `\msys` && + token[0] != `\cygwin` && + token[0] != `\Device\NamedPipe\msys` && + token[0] != `\Device\NamedPipe\cygwin` { + return false + } + + if token[1] == "" { + return false + } + + if !strings.HasPrefix(token[2], "pty") { + return false + } + + if token[3] != `from` && token[3] != `to` { + return false + } + + if token[4] != "master" { + return false + } + + return true +} + +// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler +// since GetFileInformationByHandleEx is not available under windows Vista and still some old fashion +// guys are using Windows XP, this is a workaround for those guys, it will also work on system from +// Windows vista to 10 +// see https://stackoverflow.com/a/18792477 for details +func getFileNameByHandle(fd uintptr) (string, error) { + if procNtQueryObject == nil { + return "", errors.New("ntdll.dll: NtQueryObject not supported") + } + + var buf [4 + syscall.MAX_PATH]uint16 + var result int + r, _, e := syscall.Syscall6(procNtQueryObject.Addr(), 5, + fd, objectNameInfo, uintptr(unsafe.Pointer(&buf)), uintptr(2*len(buf)), uintptr(unsafe.Pointer(&result)), 0) + if r != 0 { + return "", e + } + return string(utf16.Decode(buf[4 : 4+buf[0]/2])), nil +} + +// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 +// terminal. +func IsCygwinTerminal(fd uintptr) bool { + if procGetFileInformationByHandleEx == nil { + name, err := getFileNameByHandle(fd) + if err != nil { + return false + } + return isCygwinPipeName(name) + } + + // Cygwin/msys's pty is a pipe. + ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0) + if ft != fileTypePipe || e != 0 { + return false + } + + var buf [2 + syscall.MAX_PATH]uint16 + r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), + 4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)), + uintptr(len(buf)*2), 0, 0) + if r == 0 || e != 0 { + return false + } + + l := *(*uint32)(unsafe.Pointer(&buf)) + return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2]))) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index d27b9f5f..53640dd9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -277,6 +277,9 @@ github.com/huandu/xstrings github.com/imdario/mergo # github.com/inconshreveable/mousetrap v1.0.0 github.com/inconshreveable/mousetrap +# github.com/ipfs/go-log/v2 v2.4.0 +## explicit +github.com/ipfs/go-log/v2 # github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 ## explicit github.com/jinzhu/copier @@ -303,6 +306,9 @@ github.com/magiconair/properties # github.com/marcsauter/single v0.0.0-20181104081128-f8bf46f26ec0 ## explicit github.com/marcsauter/single +# github.com/mattn/go-isatty v0.0.14 +## explicit +github.com/mattn/go-isatty # github.com/mattn/go-runewidth v0.0.13 github.com/mattn/go-runewidth # github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369