mirror of
https://github.com/mudler/luet.git
synced 2025-09-02 15:54:39 +00:00
Compare commits
63 Commits
0.20.6
...
rel/0.22.7
Author | SHA1 | Date | |
---|---|---|---|
|
bff45b9bd9 | ||
|
7e589b07b8 | ||
|
9c61210b5b | ||
|
519058f13c | ||
|
f0200018c7 | ||
|
6198eba3b8 | ||
|
9bd6730aeb | ||
|
2bd623a61c | ||
|
80bc5429bc | ||
|
9274f87a80 | ||
|
1d651a5878 | ||
|
f7357a60a6 | ||
|
57eedf8e7e | ||
|
96aaf5235b | ||
|
196cdc5cfc | ||
|
719ef16161 | ||
|
1a9073a97a | ||
|
7e825400e2 | ||
|
39e62f3321 | ||
|
9dcaeb0870 | ||
|
c4affb0f0e | ||
|
4c1b9b92af | ||
|
7f7e1418c1 | ||
|
e8c5e237b2 | ||
|
a363b53043 | ||
|
c98f427156 | ||
|
fd90e0d627 | ||
|
20d01e43c7 | ||
|
ed63236516 | ||
|
50b23095b2 | ||
|
9665bc1481 | ||
|
37f4289cdd | ||
|
01638567a7 | ||
|
fbe9b038dd | ||
|
0a90129e34 | ||
|
b05b00c615 | ||
|
938d41fe9e | ||
|
163bd77d27 | ||
|
309f5c0559 | ||
|
1f6d0cc66c | ||
|
07e37ea059 | ||
|
432b1db116 | ||
|
8e16d3abd3 | ||
|
1f29fdd680 | ||
|
da85a7306f | ||
|
78307eef57 | ||
|
e11521ddce | ||
|
1e6aca0ba1 | ||
|
79e98af604 | ||
|
71d5b03382 | ||
|
a02ab16510 | ||
|
ba0551caab | ||
|
44e66cc729 | ||
|
80412e2e5d | ||
|
df2be8acfe | ||
|
a2d91a2aee | ||
|
bb88fe7e9c | ||
|
702a9f17db | ||
|
c58a462e79 | ||
|
1e78570c50 | ||
|
0589bead99 | ||
|
fba420865a | ||
|
9857bea5ff |
@@ -1,49 +0,0 @@
|
||||
{{ if .Versions -}}
|
||||
{{ if .Unreleased.CommitGroups -}}
|
||||
{{ range .Unreleased.CommitGroups -}}
|
||||
### {{ .Title }}
|
||||
{{ range .Commits -}}
|
||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
{{ else }}
|
||||
{{ range .Unreleased.Commits -}}
|
||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
||||
{{ range .Versions }}
|
||||
<a name="{{ .Tag.Name }}"></a>
|
||||
|
||||
{{ if .CommitGroups -}}
|
||||
{{ range .CommitGroups -}}
|
||||
### {{ .Title }}
|
||||
{{ range .Commits -}}
|
||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
{{ else }}
|
||||
{{ range .Commits -}}
|
||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} (https://github.com/mudler/luet/commit/{{.Hash.Short}})
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
|
||||
{{- if .NoteGroups -}}
|
||||
{{ range .NoteGroups -}}
|
||||
### {{ .Title }}
|
||||
{{ range .Notes }}
|
||||
{{ .Body }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
||||
{{- if .Versions }}
|
||||
[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
|
||||
{{ range .Versions -}}
|
||||
{{ if .Tag.Previous -}}
|
||||
[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
@@ -1,27 +0,0 @@
|
||||
style: github
|
||||
template: CHANGELOG.tpl.md
|
||||
info:
|
||||
title: CHANGELOG
|
||||
repository_url: https://github.com/mudler/luet
|
||||
options:
|
||||
commits:
|
||||
# filters:
|
||||
# Type:
|
||||
# - feat
|
||||
# - fix
|
||||
# - perf
|
||||
# - refactor
|
||||
commit_groups:
|
||||
title_maps:
|
||||
feat: Features
|
||||
fix: Bug Fixes
|
||||
perf: Performance Improvements
|
||||
refactor: Code Refactoring
|
||||
ci: Continous Integration
|
||||
header:
|
||||
pattern: "(.*)"
|
||||
pattern_maps:
|
||||
- Subject
|
||||
notes:
|
||||
keywords:
|
||||
- BREAKING CHANGE
|
6
.github/workflows/pr.yml
vendored
6
.github/workflows/pr.yml
vendored
@@ -74,4 +74,8 @@ jobs:
|
||||
- name: Build
|
||||
run: sudo -E env "PATH=$PATH" make multiarch-build-small
|
||||
- name: Tests
|
||||
run: sudo -E env "PATH=$PATH" make test-coverage
|
||||
run: sudo -E env "PATH=$PATH" make coverage
|
||||
- name: Codecov
|
||||
uses: codecov/codecov-action@v2.1.0
|
||||
with:
|
||||
file: coverage.txt
|
||||
|
7
.github/workflows/push.yml
vendored
7
.github/workflows/push.yml
vendored
@@ -84,4 +84,9 @@ jobs:
|
||||
env "TEST_DOCKER_IMAGE=${{ secrets.DOCKER_TESTING_IMAGE }}" \
|
||||
env "UNIT_TEST_DOCKER_IMAGE=${{ secrets.DOCKER_TESTING_IMAGE }}" \
|
||||
env "UNIT_TEST_DOCKER_IMAGE_REPOSITORY=${{ secrets.DOCKER_TESTING_UNIT_TEST_IMAGE }}" \
|
||||
make test-coverage
|
||||
make coverage
|
||||
- name: Codecov
|
||||
uses: codecov/codecov-action@v2.1.0
|
||||
with:
|
||||
file: coverage.txt
|
||||
|
||||
|
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -87,7 +87,11 @@ jobs:
|
||||
env "TEST_DOCKER_IMAGE=${{ secrets.DOCKER_TESTING_IMAGE }}" \
|
||||
env "UNIT_TEST_DOCKER_IMAGE=${{ secrets.DOCKER_TESTING_IMAGE }}" \
|
||||
env "UNIT_TEST_DOCKER_IMAGE_REPOSITORY=${{ secrets.DOCKER_TESTING_UNIT_TEST_IMAGE }}" \
|
||||
make test-coverage
|
||||
make coverage
|
||||
- name: Codecov
|
||||
uses: codecov/codecov-action@v2.1.0
|
||||
with:
|
||||
file: coverage.txt
|
||||
|
||||
release:
|
||||
name: Release
|
||||
@@ -108,4 +112,4 @@ jobs:
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
35
.travis.yml
35
.travis.yml
@@ -1,35 +0,0 @@
|
||||
dist: bionic
|
||||
language: go
|
||||
go:
|
||||
- "1.14"
|
||||
|
||||
env:
|
||||
global:
|
||||
- "GO15VENDOREXPERIMENT=1"
|
||||
jobs:
|
||||
- "DOCKER_BUILDKIT=0"
|
||||
- "DOCKER_BUILDKIT=1"
|
||||
before_install:
|
||||
- sudo rm -rf /var/lib/apt/lists/*
|
||||
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) edge"
|
||||
- sudo apt-get update
|
||||
- echo '{"experimental":true}' | sudo tee /etc/docker/daemon.json
|
||||
- export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
- mkdir -vp ~/.docker/cli-plugins/
|
||||
- curl --silent -L "https://github.com/docker/buildx/releases/download/v0.3.0/buildx-v0.3.0.linux-amd64" > ~/.docker/cli-plugins/docker-buildx
|
||||
- chmod a+x ~/.docker/cli-plugins/docker-buildx
|
||||
- docker buildx version
|
||||
- sudo -E env "PATH=$PATH" apt-get install -y libcap2-bin
|
||||
- sudo -E env "PATH=$PATH" make deps
|
||||
script:
|
||||
- sudo -E env "PATH=$PATH" make multiarch-build test-integration test-coverage
|
||||
|
||||
#after_success:
|
||||
# - |
|
||||
# if [ -n "$TRAVIS_TAG" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
|
||||
# sudo -E env "PATH=$PATH" git config --global user.name "Deployer" && git config --global user.email foo@bar.com
|
||||
# sudo -E env "PATH=$PATH" go get github.com/tcnksm/ghr
|
||||
# sudo -E env "PATH=$PATH" ghr -u mudler -r luet --replace $TRAVIS_TAG release/
|
||||
# fi
|
@@ -17,7 +17,7 @@ Join us in [slack](https://luet.slack.com/join/shared_invite/enQtOTQxMjcyNDQ0MDU
|
||||
## All Code Changes Happen Through Pull Requests
|
||||
Pull requests are the best way to propose changes to the codebase. We actively welcome your pull requests:
|
||||
|
||||
1. Fork the repo you want to contribute to and create your branch from `develop`.
|
||||
1. Fork the repo you want to contribute to and create your branch from `master`.
|
||||
2. If you've added code that should be tested, add tests.
|
||||
3. If you've changed APIs, update the [documentation](https://github.com/Luet-lab/docs).
|
||||
4. Ensure the test suite passes.
|
||||
|
11
Makefile
11
Makefile
@@ -17,9 +17,10 @@ fmt:
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
GO111MODULE=off go get github.com/onsi/ginkgo/ginkgo
|
||||
GO111MODULE=off go get github.com/onsi/ginkgo/v2
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo
|
||||
GO111MODULE=off go get github.com/onsi/gomega/...
|
||||
ginkgo -race -r -flakeAttempts 3 ./...
|
||||
ginkgo -r --flake-attempts=3 ./...
|
||||
|
||||
.PHONY: test-integration
|
||||
test-integration:
|
||||
@@ -27,11 +28,7 @@ test-integration:
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
go test ./... -race -coverprofile=coverage.txt -covermode=atomic
|
||||
|
||||
.PHONY: test-coverage
|
||||
test-coverage:
|
||||
scripts/ginkgo.coverage.sh --codecov
|
||||
ginkgo --flake-attempts=3 --fail-fast -cover -covermode=atomic -coverprofile=coverage.txt -r .
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
|
70
cmd/build.go
70
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 <package name> <package name> <package name> ...",
|
||||
Short: "build a package or a tree",
|
||||
Long: `Builds one or more packages from a tree (current directory is implied):
|
||||
@@ -83,9 +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 +93,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")
|
||||
@@ -110,14 +110,13 @@ Build packages specifying multiple definition trees:
|
||||
onlyTarget, _ := cmd.Flags().GetBool("only-target-package")
|
||||
full, _ := cmd.Flags().GetBool("full")
|
||||
rebuild, _ := cmd.Flags().GetBool("rebuild")
|
||||
pushFinalImages, _ := cmd.Flags().GetBool("push-final-images")
|
||||
pushFinalImagesRepository, _ := cmd.Flags().GetString("push-final-images-repository")
|
||||
pushFinalImagesForce, _ := cmd.Flags().GetBool("push-final-images-force")
|
||||
|
||||
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")
|
||||
|
||||
@@ -132,16 +131,21 @@ Build packages specifying multiple definition trees:
|
||||
|
||||
generalRecipe := tree.NewCompilerRecipe(db)
|
||||
|
||||
if fromRepo {
|
||||
if err := installer.LoadBuildTree(generalRecipe, db, util.DefaultContext); err != nil {
|
||||
util.DefaultContext.Warning("errors while loading trees from repositories", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
for _, src := range treePaths {
|
||||
util.DefaultContext.Info("Loading tree", src)
|
||||
helpers.CheckErr(generalRecipe.Load(src))
|
||||
}
|
||||
templateFolders := []string{}
|
||||
|
||||
if fromRepo {
|
||||
bt, err := installer.LoadBuildTree(generalRecipe, db, util.DefaultContext)
|
||||
if err != nil {
|
||||
util.DefaultContext.Warning("errors while loading trees from repositories", err.Error())
|
||||
}
|
||||
templateFolders = util.TemplateFolders(util.DefaultContext, bt, treePaths)
|
||||
} else {
|
||||
templateFolders = util.TemplateFolders(util.DefaultContext, installer.BuildTreeResult{}, treePaths)
|
||||
}
|
||||
|
||||
util.DefaultContext.Info("Building in", dst)
|
||||
|
||||
@@ -150,25 +154,20 @@ 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}
|
||||
|
||||
luetCompiler := compiler.NewLuetCompiler(compilerBackend, generalRecipe.GetDatabase(),
|
||||
options.NoDeps(nodeps),
|
||||
compileropts := []options.Option{options.NoDeps(nodeps),
|
||||
options.WithBackendType(backendType),
|
||||
options.PushImages(push),
|
||||
options.WithBuildValues(values),
|
||||
options.WithPullRepositories(pullRepo),
|
||||
options.WithPushRepository(imageRepository),
|
||||
options.Rebuild(rebuild),
|
||||
options.WithTemplateFolder(util.TemplateFolders(util.DefaultContext, fromRepo, treePaths)),
|
||||
options.WithSolverOptions(*opts),
|
||||
options.WithTemplateFolder(templateFolders),
|
||||
options.WithSolverOptions(opts),
|
||||
options.Wait(wait),
|
||||
options.OnlyTarget(onlyTarget),
|
||||
options.PullFirst(pull),
|
||||
@@ -177,8 +176,21 @@ Build packages specifying multiple definition trees:
|
||||
options.WithContext(util.DefaultContext),
|
||||
options.BackendArgs(backendArgs),
|
||||
options.Concurrency(concurrency),
|
||||
options.WithCompressionType(compression.Implementation(compressionType)),
|
||||
)
|
||||
options.WithCompressionType(compression.Implementation(compressionType))}
|
||||
|
||||
if pushFinalImages {
|
||||
compileropts = append(compileropts, options.EnablePushFinalImages)
|
||||
if pushFinalImagesForce {
|
||||
compileropts = append(compileropts, options.ForcePushFinalImages)
|
||||
}
|
||||
if pushFinalImagesRepository != "" {
|
||||
compileropts = append(compileropts, options.WithFinalRepository(pushFinalImagesRepository))
|
||||
} else if imageRepository != "" {
|
||||
compileropts = append(compileropts, options.WithFinalRepository(imageRepository))
|
||||
}
|
||||
}
|
||||
|
||||
luetCompiler := compiler.NewLuetCompiler(compilerBackend, generalRecipe.GetDatabase(), compileropts...)
|
||||
|
||||
if full {
|
||||
specs, err := luetCompiler.FromDatabase(generalRecipe.GetDatabase(), true, dst)
|
||||
@@ -302,6 +314,11 @@ func init() {
|
||||
buildCmd.Flags().Bool("privileged", true, "Privileged (Keep permissions)")
|
||||
buildCmd.Flags().Bool("revdeps", false, "Build with revdeps")
|
||||
buildCmd.Flags().Bool("all", false, "Build all specfiles in the tree")
|
||||
|
||||
buildCmd.Flags().Bool("push-final-images", false, "Push final images while building")
|
||||
buildCmd.Flags().Bool("push-final-images-force", false, "Override existing images")
|
||||
buildCmd.Flags().String("push-final-images-repository", "", "Repository where to push final images to")
|
||||
|
||||
buildCmd.Flags().Bool("full", false, "Build all packages (optimized)")
|
||||
buildCmd.Flags().StringSlice("values", []string{}, "Build values file to interpolate with each package")
|
||||
buildCmd.Flags().StringSliceP("backend-args", "a", []string{}, "Backend args")
|
||||
@@ -321,7 +338,6 @@ 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("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")
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -100,6 +100,7 @@ Create a repository from the metadata description defined in the luet.yaml confi
|
||||
helpers.CheckErr(err)
|
||||
force := viper.GetBool("force-push")
|
||||
imagePush := viper.GetBool("push-images")
|
||||
snapshotID, _ := cmd.Flags().GetString("snapshot-id")
|
||||
|
||||
opts := []installer.RepositoryOption{
|
||||
installer.WithSource(viper.GetString("packages")),
|
||||
@@ -163,7 +164,7 @@ Create a repository from the metadata description defined in the luet.yaml confi
|
||||
if metaName != "" {
|
||||
metaFile.SetFileName(metaName)
|
||||
}
|
||||
|
||||
repo.SetSnapshotID(snapshotID)
|
||||
repo.SetRepositoryFile(installer.REPOFILE_TREE_KEY, treeFile)
|
||||
repo.SetRepositoryFile(installer.REPOFILE_META_KEY, metaFile)
|
||||
|
||||
@@ -197,6 +198,7 @@ func init() {
|
||||
createrepoCmd.Flags().String("meta-compression", "none", "Compression alg: none, gzip, zstd")
|
||||
createrepoCmd.Flags().String("meta-filename", installer.REPOSITORY_METAFILE+".tar", "Repository metadata filename")
|
||||
createrepoCmd.Flags().Bool("from-repositories", false, "Consume the user-defined repositories to pull specfiles from")
|
||||
createrepoCmd.Flags().String("snapshot-id", "", "Unique ID to use when creating repository snapshots")
|
||||
|
||||
RootCmd.AddCommand(createrepoCmd)
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ import (
|
||||
)
|
||||
|
||||
func NewDatabaseCreateCommand() *cobra.Command {
|
||||
var ans = &cobra.Command{
|
||||
return &cobra.Command{
|
||||
Use: "create <artifact_metadata1.yaml> <artifact_metadata1.yaml>",
|
||||
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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ package cmd_helpers_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -18,7 +18,7 @@ package cmd_helpers_test
|
||||
import (
|
||||
. "github.com/mudler/luet/cmd/helpers"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -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")
|
||||
|
||||
|
124
cmd/oscheck.go
Normal file
124
cmd/oscheck.go
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
installer "github.com/mudler/luet/pkg/installer"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
|
||||
"github.com/mudler/luet/cmd/util"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var osCheckCmd = &cobra.Command{
|
||||
Use: "oscheck",
|
||||
Short: "Checks packages integrity",
|
||||
Long: `List packages that are installed in the system which files are missing in the system.
|
||||
|
||||
$ luet oscheck
|
||||
|
||||
To reinstall packages in the list:
|
||||
|
||||
$ luet oscheck --reinstall
|
||||
`,
|
||||
Aliases: []string{"i"},
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
viper.BindPFlag("onlydeps", cmd.Flags().Lookup("onlydeps"))
|
||||
viper.BindPFlag("nodeps", cmd.Flags().Lookup("nodeps"))
|
||||
viper.BindPFlag("force", cmd.Flags().Lookup("force"))
|
||||
viper.BindPFlag("yes", cmd.Flags().Lookup("yes"))
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
force := viper.GetBool("force")
|
||||
onlydeps := viper.GetBool("onlydeps")
|
||||
yes := viper.GetBool("yes")
|
||||
|
||||
downloadOnly, _ := cmd.Flags().GetBool("download-only")
|
||||
|
||||
system := &installer.System{
|
||||
Database: util.DefaultContext.Config.GetSystemDB(),
|
||||
Target: util.DefaultContext.Config.System.Rootfs,
|
||||
}
|
||||
packs := system.OSCheck(util.DefaultContext)
|
||||
if !util.DefaultContext.Config.General.Quiet {
|
||||
if len(packs) == 0 {
|
||||
util.DefaultContext.Success("All good!")
|
||||
os.Exit(0)
|
||||
} else {
|
||||
util.DefaultContext.Info("Following packages are missing files or are incomplete:")
|
||||
for _, p := range packs {
|
||||
util.DefaultContext.Info(p.HumanReadableString())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var s []string
|
||||
for _, p := range packs {
|
||||
s = append(s, p.HumanReadableString())
|
||||
}
|
||||
fmt.Println(strings.Join(s, " "))
|
||||
}
|
||||
|
||||
reinstall, _ := cmd.Flags().GetBool("reinstall")
|
||||
if reinstall {
|
||||
|
||||
// Strip version for reinstall
|
||||
toInstall := pkg.Packages{}
|
||||
for _, p := range packs {
|
||||
new := p.Clone()
|
||||
new.SetVersion(">=0")
|
||||
toInstall = append(toInstall, new)
|
||||
}
|
||||
|
||||
util.DefaultContext.Debug("Solver", util.DefaultContext.Config.Solver.CompactString())
|
||||
|
||||
inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{
|
||||
Concurrency: util.DefaultContext.Config.General.Concurrency,
|
||||
SolverOptions: util.DefaultContext.Config.Solver,
|
||||
NoDeps: true,
|
||||
Force: force,
|
||||
OnlyDeps: onlydeps,
|
||||
PreserveSystemEssentialData: true,
|
||||
Ask: !yes,
|
||||
DownloadOnly: downloadOnly,
|
||||
Context: util.DefaultContext,
|
||||
PackageRepositories: util.DefaultContext.Config.SystemRepositories,
|
||||
})
|
||||
|
||||
err := inst.Swap(packs, toInstall, system)
|
||||
if err != nil {
|
||||
util.DefaultContext.Fatal("Error: " + err.Error())
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
osCheckCmd.Flags().Bool("reinstall", false, "reinstall")
|
||||
|
||||
osCheckCmd.Flags().Bool("onlydeps", false, "Consider **only** package dependencies")
|
||||
osCheckCmd.Flags().Bool("force", false, "Skip errors and keep going (potentially harmful)")
|
||||
osCheckCmd.Flags().BoolP("yes", "y", false, "Don't ask questions")
|
||||
osCheckCmd.Flags().Bool("download-only", false, "Download only")
|
||||
|
||||
RootCmd.AddCommand(osCheckCmd)
|
||||
}
|
@@ -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")
|
||||
|
@@ -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)
|
||||
|
@@ -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"))
|
||||
@@ -52,30 +48,13 @@ var reinstallCmd = &cobra.Command{
|
||||
yes := viper.GetBool("yes")
|
||||
|
||||
downloadOnly, _ := cmd.Flags().GetBool("download-only")
|
||||
installed, _ := cmd.Flags().GetBool("installed")
|
||||
|
||||
util.SetSystemConfig(util.DefaultContext)
|
||||
|
||||
for _, a := range args {
|
||||
pack, err := helpers.ParsePackageStr(a)
|
||||
if err != nil {
|
||||
util.DefaultContext.Fatal("Invalid package string ", a, ": ", err.Error())
|
||||
}
|
||||
toUninstall = append(toUninstall, pack)
|
||||
toAdd = append(toAdd, pack)
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -86,7 +65,26 @@ 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() {
|
||||
toUninstall = append(toUninstall, p)
|
||||
c := p.Clone()
|
||||
c.SetVersion(">=0")
|
||||
toAdd = append(toAdd, c)
|
||||
}
|
||||
} else {
|
||||
for _, a := range args {
|
||||
pack, err := helpers.ParsePackageStr(a)
|
||||
if err != nil {
|
||||
util.DefaultContext.Fatal("Invalid package string ", a, ": ", err.Error())
|
||||
}
|
||||
toUninstall = append(toUninstall, pack)
|
||||
toAdd = append(toAdd, pack)
|
||||
}
|
||||
}
|
||||
|
||||
err := inst.Swap(toUninstall, toAdd, system)
|
||||
if err != nil {
|
||||
util.DefaultContext.Fatal("Error: " + err.Error())
|
||||
@@ -95,18 +93,9 @@ 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")
|
||||
|
||||
|
@@ -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")
|
||||
|
@@ -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)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
// Copyright © 2019 Ettore Di Giacinto <mudler@gentoo.org>
|
||||
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@@ -24,7 +25,7 @@ import (
|
||||
)
|
||||
|
||||
func NewRepoUpdateCommand() *cobra.Command {
|
||||
var ans = &cobra.Command{
|
||||
var repoUpdate = &cobra.Command{
|
||||
Use: "update [repo1] [repo2] [OPTIONS]",
|
||||
Short: "Update a specific cached repository or all cached repositories.",
|
||||
Example: `
|
||||
@@ -72,8 +73,8 @@ $> luet repo update repo1 repo2
|
||||
},
|
||||
}
|
||||
|
||||
ans.Flags().BoolP("ignore-errors", "i", false, "Ignore errors on sync repositories.")
|
||||
ans.Flags().BoolP("force", "f", false, "Force resync.")
|
||||
repoUpdate.Flags().BoolP("ignore-errors", "i", false, "Ignore errors on sync repositories.")
|
||||
repoUpdate.Flags().BoolP("force", "f", true, "Force resync.")
|
||||
|
||||
return ans
|
||||
return repoUpdate
|
||||
}
|
||||
|
22
cmd/root.go
22
cmd/root.go
@@ -30,7 +30,7 @@ var cfgFile string
|
||||
var Verbose bool
|
||||
|
||||
const (
|
||||
LuetCLIVersion = "0.20.6"
|
||||
LuetCLIVersion = "0.22.7"
|
||||
LuetEnvPrefix = "LUET"
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
105
cmd/search.go
105
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"
|
||||
@@ -36,6 +35,7 @@ type PackageResult struct {
|
||||
Target string `json:"target"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Files []string `json:"files"`
|
||||
Installed bool `json:"installed"`
|
||||
}
|
||||
|
||||
type Results struct {
|
||||
@@ -46,13 +46,13 @@ func (r PackageResult) String() string {
|
||||
return fmt.Sprintf("%s/%s-%s required for %s", r.Category, r.Name, r.Version, r.Target)
|
||||
}
|
||||
|
||||
var rows []string = []string{"Package", "Category", "Name", "Version", "Repository", "License"}
|
||||
var rows []string = []string{"Package", "Category", "Name", "Version", "Repository", "License", "Installed"}
|
||||
|
||||
func packageToRow(repo string, p pkg.Package) []string {
|
||||
return []string{p.HumanReadableString(), p.GetCategory(), p.GetName(), p.GetVersion(), repo, p.GetLicense()}
|
||||
func packageToRow(repo string, p pkg.Package, installed bool) []string {
|
||||
return []string{p.HumanReadableString(), p.GetCategory(), p.GetName(), p.GetVersion(), repo, p.GetLicense(), fmt.Sprintf("%t", installed)}
|
||||
}
|
||||
|
||||
func packageToList(l *util.ListWriter, repo string, p pkg.Package) {
|
||||
func packageToList(l *util.ListWriter, repo string, p pkg.Package, installed bool) {
|
||||
l.AppendItem(pterm.BulletListItem{
|
||||
Level: 0, Text: p.HumanReadableString(),
|
||||
TextStyle: pterm.NewStyle(pterm.FgCyan), Bullet: ">", BulletStyle: pterm.NewStyle(pterm.FgYellow),
|
||||
@@ -81,12 +81,32 @@ func packageToList(l *util.ListWriter, repo string, p pkg.Package) {
|
||||
Level: 1, Text: fmt.Sprintf("Uri: %s ", strings.Join(p.GetURI(), " ")),
|
||||
Bullet: "->", BulletStyle: pterm.NewStyle(pterm.FgDarkGray),
|
||||
})
|
||||
l.AppendItem(pterm.BulletListItem{
|
||||
Level: 1, Text: fmt.Sprintf("Installed: %t ", installed),
|
||||
Bullet: "->", BulletStyle: pterm.NewStyle(pterm.FgDarkGray),
|
||||
})
|
||||
}
|
||||
|
||||
var s *installer.System
|
||||
|
||||
func sys() *installer.System {
|
||||
if s != nil {
|
||||
return s
|
||||
}
|
||||
s = &installer.System{Database: util.DefaultContext.Config.GetSystemDB(), Target: util.DefaultContext.Config.System.Rootfs}
|
||||
return s
|
||||
}
|
||||
|
||||
func installed(p pkg.Package) bool {
|
||||
s := sys()
|
||||
_, err := s.Database.FindPackage(p)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
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 := sys()
|
||||
|
||||
var err error
|
||||
iMatches := pkg.Packages{}
|
||||
@@ -105,9 +125,8 @@ func searchLocally(term string, l *util.ListWriter, t *util.TableWriter, label,
|
||||
for _, pack := range iMatches {
|
||||
if !revdeps {
|
||||
if !pack.IsHidden() || pack.IsHidden() && hidden {
|
||||
|
||||
t.AppendRow(packageToRow("system", pack))
|
||||
packageToList(l, "system", pack)
|
||||
t.AppendRow(packageToRow("system", pack, true))
|
||||
packageToList(l, "system", pack, true)
|
||||
f, _ := system.Database.GetPackageFiles(pack)
|
||||
results.Packages = append(results.Packages,
|
||||
PackageResult{
|
||||
@@ -117,6 +136,7 @@ func searchLocally(term string, l *util.ListWriter, t *util.TableWriter, label,
|
||||
Repository: "system",
|
||||
Hidden: pack.IsHidden(),
|
||||
Files: f,
|
||||
Installed: true,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
@@ -124,8 +144,9 @@ func searchLocally(term string, l *util.ListWriter, t *util.TableWriter, label,
|
||||
packs, _ := system.Database.GetRevdeps(pack)
|
||||
for _, revdep := range packs {
|
||||
if !revdep.IsHidden() || revdep.IsHidden() && hidden {
|
||||
t.AppendRow(packageToRow("system", pack))
|
||||
packageToList(l, "system", pack)
|
||||
i := installed(pack)
|
||||
t.AppendRow(packageToRow("system", pack, i))
|
||||
packageToList(l, "system", pack, i)
|
||||
f, _ := system.Database.GetPackageFiles(revdep)
|
||||
results.Packages = append(results.Packages,
|
||||
PackageResult{
|
||||
@@ -135,6 +156,7 @@ func searchLocally(term string, l *util.ListWriter, t *util.TableWriter, label,
|
||||
Repository: "system",
|
||||
Hidden: revdep.IsHidden(),
|
||||
Files: f,
|
||||
Installed: i,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -148,8 +170,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,
|
||||
},
|
||||
@@ -173,14 +195,16 @@ func searchOnline(term string, l *util.ListWriter, t *util.TableWriter, label, l
|
||||
for _, m := range matches {
|
||||
if !revdeps {
|
||||
if !m.Package.IsHidden() || m.Package.IsHidden() && hidden {
|
||||
t.AppendRow(packageToRow(m.Repo.GetName(), m.Package))
|
||||
packageToList(l, m.Repo.GetName(), m.Package)
|
||||
i := installed(m.Package)
|
||||
t.AppendRow(packageToRow(m.Repo.GetName(), m.Package, i))
|
||||
packageToList(l, m.Repo.GetName(), m.Package, i)
|
||||
r := &PackageResult{
|
||||
Name: m.Package.GetName(),
|
||||
Version: m.Package.GetVersion(),
|
||||
Category: m.Package.GetCategory(),
|
||||
Repository: m.Repo.GetName(),
|
||||
Hidden: m.Package.IsHidden(),
|
||||
Installed: i,
|
||||
}
|
||||
if m.Artifact != nil {
|
||||
r.Files = m.Artifact.Files
|
||||
@@ -191,10 +215,12 @@ func searchOnline(term string, l *util.ListWriter, t *util.TableWriter, label, l
|
||||
packs, _ := m.Repo.GetTree().GetDatabase().GetRevdeps(m.Package)
|
||||
for _, revdep := range packs {
|
||||
if !revdep.IsHidden() || revdep.IsHidden() && hidden {
|
||||
t.AppendRow(packageToRow(m.Repo.GetName(), revdep))
|
||||
packageToList(l, m.Repo.GetName(), revdep)
|
||||
i := installed(revdep)
|
||||
t.AppendRow(packageToRow(m.Repo.GetName(), revdep, i))
|
||||
packageToList(l, m.Repo.GetName(), revdep, i)
|
||||
r := &PackageResult{
|
||||
Name: revdep.GetName(),
|
||||
Installed: i,
|
||||
Version: revdep.GetVersion(),
|
||||
Category: revdep.GetCategory(),
|
||||
Repository: m.Repo.GetName(),
|
||||
@@ -216,8 +242,9 @@ func searchLocalFiles(term string, l *util.ListWriter, t *util.TableWriter) Resu
|
||||
|
||||
matches, _ := util.DefaultContext.Config.GetSystemDB().FindPackageByFile(term)
|
||||
for _, pack := range matches {
|
||||
t.AppendRow(packageToRow("system", pack))
|
||||
packageToList(l, "system", pack)
|
||||
i := installed(pack)
|
||||
t.AppendRow(packageToRow("system", pack, i))
|
||||
packageToList(l, "system", pack, i)
|
||||
f, _ := util.DefaultContext.Config.GetSystemDB().GetPackageFiles(pack)
|
||||
results.Packages = append(results.Packages,
|
||||
PackageResult{
|
||||
@@ -227,6 +254,7 @@ func searchLocalFiles(term string, l *util.ListWriter, t *util.TableWriter) Resu
|
||||
Repository: "system",
|
||||
Hidden: pack.IsHidden(),
|
||||
Files: f,
|
||||
Installed: i,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -238,8 +266,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,
|
||||
},
|
||||
@@ -256,8 +284,9 @@ func searchFiles(term string, l *util.ListWriter, t *util.TableWriter) Results {
|
||||
matches = synced.SearchPackages(term, installer.FileSearch)
|
||||
|
||||
for _, m := range matches {
|
||||
t.AppendRow(packageToRow(m.Repo.GetName(), m.Package))
|
||||
packageToList(l, m.Repo.GetName(), m.Package)
|
||||
i := installed(m.Package)
|
||||
t.AppendRow(packageToRow(m.Repo.GetName(), m.Package, i))
|
||||
packageToList(l, m.Repo.GetName(), m.Package, i)
|
||||
results.Packages = append(results.Packages,
|
||||
PackageResult{
|
||||
Name: m.Package.GetName(),
|
||||
@@ -266,13 +295,18 @@ func searchFiles(term string, l *util.ListWriter, t *util.TableWriter) Results {
|
||||
Repository: m.Repo.GetName(),
|
||||
Hidden: m.Package.IsHidden(),
|
||||
Files: m.Artifact.Files,
|
||||
Installed: i,
|
||||
})
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
var searchCmd = &cobra.Command{
|
||||
Use: "search <term>",
|
||||
Use: "search <term>",
|
||||
// Skip processing output
|
||||
Annotations: map[string]string{
|
||||
util.CommandProcessOutput: "",
|
||||
},
|
||||
Short: "Search packages",
|
||||
Long: `Search for installed and available packages
|
||||
|
||||
@@ -309,8 +343,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 +362,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:
|
||||
@@ -371,6 +397,10 @@ Search can also return results in the terminal in different ways: as terminal ou
|
||||
default:
|
||||
if tableMode {
|
||||
t.Render()
|
||||
} else if util.DefaultContext.Config.General.Quiet {
|
||||
for _, tt := range results.Packages {
|
||||
fmt.Printf("%s/%s-%s\n", tt.Category, tt.Name, tt.Version)
|
||||
}
|
||||
} else {
|
||||
l.Render()
|
||||
}
|
||||
@@ -379,16 +409,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")
|
||||
|
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/mudler/luet/pkg/compiler"
|
||||
"github.com/mudler/luet/pkg/compiler/backend"
|
||||
"github.com/mudler/luet/pkg/compiler/types/options"
|
||||
"github.com/mudler/luet/pkg/installer"
|
||||
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/luet/pkg/solver"
|
||||
@@ -38,7 +39,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 +65,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 +76,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,
|
||||
@@ -85,7 +85,7 @@ func NewTreeImageCommand() *cobra.Command {
|
||||
options.WithContext(util.DefaultContext),
|
||||
options.WithPushRepository(imageRepository),
|
||||
options.WithPullRepositories(pullRepo),
|
||||
options.WithTemplateFolder(util.TemplateFolders(util.DefaultContext, false, treePath)),
|
||||
options.WithTemplateFolder(util.TemplateFolders(util.DefaultContext, installer.BuildTreeResult{}, treePath)),
|
||||
options.WithSolverOptions(opts),
|
||||
)
|
||||
|
||||
@@ -102,7 +102,12 @@ func NewTreeImageCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
ht := compiler.NewHashTree(reciper.GetDatabase())
|
||||
hashtree, err := ht.Query(luetCompiler, spec)
|
||||
|
||||
copy, err := compiler.CompilerFinalImages(luetCompiler)
|
||||
if err != nil {
|
||||
util.DefaultContext.Fatal("Error: " + err.Error())
|
||||
}
|
||||
hashtree, err := ht.Query(copy, spec)
|
||||
if err != nil {
|
||||
util.DefaultContext.Fatal("Error: " + err.Error())
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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")
|
||||
|
@@ -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)")
|
||||
|
@@ -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"))
|
||||
},
|
||||
@@ -43,22 +41,18 @@ var upgradeCmd = &cobra.Command{
|
||||
universe, _ := cmd.Flags().GetBool("universe")
|
||||
clean, _ := cmd.Flags().GetBool("clean")
|
||||
sync, _ := cmd.Flags().GetBool("sync")
|
||||
osCheck, _ := cmd.Flags().GetBool("oscheck")
|
||||
|
||||
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,
|
||||
@@ -67,12 +61,13 @@ var upgradeCmd = &cobra.Command{
|
||||
UpgradeNewRevisions: sync,
|
||||
PreserveSystemEssentialData: true,
|
||||
Ask: !yes,
|
||||
AutoOSCheck: osCheck,
|
||||
DownloadOnly: downloadOnly,
|
||||
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}
|
||||
if err := inst.Upgrade(system); err != nil {
|
||||
util.DefaultContext.Fatal("Error: " + err.Error())
|
||||
}
|
||||
@@ -80,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)")
|
||||
@@ -97,6 +84,7 @@ func init() {
|
||||
upgradeCmd.Flags().Bool("solver-concurrent", false, "Use concurrent solver (experimental)")
|
||||
upgradeCmd.Flags().BoolP("yes", "y", false, "Don't ask questions")
|
||||
upgradeCmd.Flags().Bool("download-only", false, "Download only")
|
||||
upgradeCmd.Flags().Bool("oscheck", false, "Perform automatically oschecks after upgrades")
|
||||
|
||||
RootCmd.AddCommand(upgradeCmd)
|
||||
}
|
||||
|
107
cmd/util.go
107
cmd/util.go
@@ -19,23 +19,77 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/mudler/luet/pkg/api/core/image"
|
||||
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 *context.Context, p, dst, imageName, arch, OS string) error {
|
||||
|
||||
tempimage, err := ctx.TempFile("tempimage")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error met while creating tempdir for "+p)
|
||||
}
|
||||
defer os.RemoveAll(tempimage.Name()) // clean up
|
||||
|
||||
if err := image.CreateTar(p, tempimage.Name(), imageName, arch, OS); err != nil {
|
||||
return errors.Wrap(err, "could not create image from tar")
|
||||
}
|
||||
|
||||
return fileHelper.CopyFile(tempimage.Name(), dst)
|
||||
}
|
||||
|
||||
func NewPackCommand() *cobra.Command {
|
||||
|
||||
c := &cobra.Command{
|
||||
Use: "pack image src.tar dst.tar",
|
||||
Short: "Pack a standard tar archive as a container image",
|
||||
Long: `Pack creates a tar which can be loaded as an image from a standard flat tar archive, for e.g. with docker load.
|
||||
It doesn't need the docker daemon to run, and allows to override default os/arch:
|
||||
|
||||
luet util pack --os arm64 image:tag src.tar dst.tar
|
||||
`,
|
||||
Args: cobra.MinimumNArgs(3),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
image := args[0]
|
||||
src := args[1]
|
||||
dst := args[2]
|
||||
|
||||
arch, _ := cmd.Flags().GetString("arch")
|
||||
os, _ := cmd.Flags().GetString("os")
|
||||
|
||||
err := pack(util.DefaultContext, src, dst, image, arch, os)
|
||||
if err != nil {
|
||||
util.DefaultContext.Fatal(err.Error())
|
||||
}
|
||||
util.DefaultContext.Info("Image packed as", image)
|
||||
},
|
||||
}
|
||||
|
||||
c.Flags().String("arch", runtime.GOARCH, "Image architecture")
|
||||
c.Flags().String("os", runtime.GOOS, "Image OS")
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func NewUnpackCommand() *cobra.Command {
|
||||
|
||||
c := &cobra.Command{
|
||||
Use: "unpack image path",
|
||||
Short: "Unpack a docker image natively",
|
||||
Long: `unpack doesn't need the docker daemon to run, and unpacks a docker image in the specified directory:
|
||||
|
||||
|
||||
luet util unpack golang:alpine /alpine
|
||||
`,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
@@ -53,7 +107,7 @@ func NewUnpackCommand() *cobra.Command {
|
||||
util.DefaultContext.Error("Invalid path %s", destination)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
local, _ := cmd.Flags().GetBool("local")
|
||||
verify, _ := cmd.Flags().GetBool("verify")
|
||||
user, _ := cmd.Flags().GetString("auth-username")
|
||||
pass, _ := cmd.Flags().GetString("auth-password")
|
||||
@@ -72,13 +126,22 @@ func NewUnpackCommand() *cobra.Command {
|
||||
RegistryToken: registryToken,
|
||||
}
|
||||
|
||||
info, err := docker.DownloadAndExtractDockerImage(util.DefaultContext, image, destination, auth, verify)
|
||||
if err != nil {
|
||||
util.DefaultContext.Error(err.Error())
|
||||
os.Exit(1)
|
||||
if !local {
|
||||
info, err := docker.DownloadAndExtractDockerImage(util.DefaultContext, image, destination, auth, verify)
|
||||
if err != nil {
|
||||
util.DefaultContext.Error(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
util.DefaultContext.Info(fmt.Sprintf("Pulled: %s %s", info.Target.Digest, info.Name))
|
||||
util.DefaultContext.Info(fmt.Sprintf("Size: %s", units.BytesSize(float64(info.Target.Size))))
|
||||
} else {
|
||||
info, err := docker.ExtractDockerImage(util.DefaultContext, image, destination)
|
||||
if err != nil {
|
||||
util.DefaultContext.Error(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
util.DefaultContext.Info(fmt.Sprintf("Size: %s", units.BytesSize(float64(info.Target.Size))))
|
||||
}
|
||||
util.DefaultContext.Info(fmt.Sprintf("Pulled: %s %s", info.Target.Digest, info.Name))
|
||||
util.DefaultContext.Info(fmt.Sprintf("Size: %s", units.BytesSize(float64(info.Target.Size))))
|
||||
},
|
||||
}
|
||||
|
||||
@@ -89,6 +152,32 @@ func NewUnpackCommand() *cobra.Command {
|
||||
c.Flags().String("auth-identity-token", "", "Authentication identity token")
|
||||
c.Flags().String("auth-registry-token", "", "Authentication registry token")
|
||||
c.Flags().Bool("verify", false, "Verify signed images to notary before to pull")
|
||||
c.Flags().Bool("local", false, "Unpack local image")
|
||||
return c
|
||||
}
|
||||
|
||||
func NewExistCommand() *cobra.Command {
|
||||
|
||||
c := &cobra.Command{
|
||||
Use: "image-exist image path",
|
||||
Short: "Check if an image exist",
|
||||
Long: `Exits 0 if the image exist, otherwise exits with 1`,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
if len(args) != 1 {
|
||||
util.DefaultContext.Fatal("Expects an image")
|
||||
}
|
||||
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if image.Available(args[0]) {
|
||||
os.Exit(0)
|
||||
} else {
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -102,5 +191,7 @@ func init() {
|
||||
|
||||
utilGroup.AddCommand(
|
||||
NewUnpackCommand(),
|
||||
NewPackCommand(),
|
||||
NewExistCommand(),
|
||||
)
|
||||
}
|
||||
|
@@ -16,9 +16,7 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/marcsauter/single"
|
||||
@@ -26,28 +24,15 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/mudler/luet/pkg/api/core/context"
|
||||
"github.com/mudler/luet/pkg/api/core/template"
|
||||
"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,62 +41,16 @@ 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, i installer.BuildTreeResult, treePaths []string) []string {
|
||||
templateFolders := []string{}
|
||||
for _, t := range treePaths {
|
||||
templateFolders = append(templateFolders, filepath.Join(t, "templates"))
|
||||
templateFolders = append(templateFolders, template.FindPossibleTemplatesDir(t)...)
|
||||
}
|
||||
if fromRepo {
|
||||
for _, s := range installer.SystemRepositories(ctx.Config.SystemRepositories) {
|
||||
templateFolders = append(templateFolders, filepath.Join(s.TreePath, "templates"))
|
||||
}
|
||||
for _, r := range i.TemplatesDir {
|
||||
templateFolders = append(templateFolders, r...)
|
||||
}
|
||||
|
||||
return templateFolders
|
||||
}
|
||||
|
||||
@@ -126,7 +65,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 +85,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 {
|
||||
@@ -156,11 +95,15 @@ func DisplayVersionBanner(c *types.Context, banner func(), version func() string
|
||||
}
|
||||
}
|
||||
if display {
|
||||
banner()
|
||||
pterm.DefaultCenter.Print(version())
|
||||
for _, l := range license {
|
||||
pterm.DefaultCenter.Print(l)
|
||||
|
||||
if c.Config.General.Quiet {
|
||||
pterm.Info.Printf("Luet %s\n", version())
|
||||
pterm.Info.Println(strings.Join(license, "\n"))
|
||||
} else {
|
||||
banner()
|
||||
pterm.DefaultCenter.Print(version())
|
||||
for _, l := range license {
|
||||
pterm.DefaultCenter.Print(l)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
@@ -120,7 +219,8 @@ func setDefaults(viper *viper.Viper) {
|
||||
|
||||
viper.SetDefault("general.concurrency", runtime.NumCPU())
|
||||
viper.SetDefault("general.debug", false)
|
||||
viper.SetDefault("general.show_build_output", false)
|
||||
viper.SetDefault("general.quiet", false)
|
||||
viper.SetDefault("general.show_build_output", true)
|
||||
viper.SetDefault("general.fatal_warnings", false)
|
||||
viper.SetDefault("general.http_timeout", 360)
|
||||
|
||||
@@ -155,43 +255,56 @@ 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)")
|
||||
pflags.BoolP("debug", "d", false, "verbose output")
|
||||
pflags.BoolP("debug", "d", false, "debug output")
|
||||
pflags.BoolP("quiet", "q", false, "quiet output")
|
||||
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("live-output", true, "Show live output during build")
|
||||
|
||||
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"))
|
||||
viper.BindPFlag("general.fatal_warnings", pflags.Lookup("fatal"))
|
||||
viper.BindPFlag("general.same_owner", pflags.Lookup("same-owner"))
|
||||
viper.BindPFlag("plugin", pflags.Lookup("plugin"))
|
||||
viper.BindPFlag("general.http_timeout", pflags.Lookup("http-timeout"))
|
||||
viper.BindPFlag("general.show_build_output", pflags.Lookup("live-output"))
|
||||
|
||||
// Currently I maintain this only from cli.
|
||||
viper.BindPFlag("no_spinner", pflags.Lookup("no-spinner"))
|
||||
|
25
go.mod
25
go.mod
@@ -10,44 +10,45 @@ require (
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef
|
||||
github.com/asdine/storm v0.0.0-20190418133842-e0f77eada154
|
||||
github.com/cavaliercoder/grab v1.0.1-0.20201108051000-98a5bfe305ec
|
||||
github.com/containerd/containerd v1.5.2
|
||||
github.com/containerd/containerd v1.5.7
|
||||
github.com/crillab/gophersat v1.3.2-0.20210701121804-72b19f5b6b38
|
||||
github.com/docker/cli v20.10.7+incompatible
|
||||
github.com/docker/cli v20.10.10+incompatible
|
||||
github.com/docker/distribution v2.7.1+incompatible
|
||||
github.com/docker/docker v20.10.7+incompatible
|
||||
github.com/docker/docker v20.10.10+incompatible
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/ecooper/qlearning v0.0.0-20160612200101-3075011a69fd
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/go-containerregistry v0.6.0
|
||||
github.com/google/go-containerregistry v0.7.0
|
||||
github.com/google/renameio v1.0.0
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gookit/color v1.5.0
|
||||
github.com/gorilla/mux v1.7.4 // indirect
|
||||
github.com/hashicorp/go-multierror v1.0.0
|
||||
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/compress v1.13.6
|
||||
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
|
||||
github.com/moby/moby v20.10.9+incompatible
|
||||
github.com/moby/sys/mount v0.2.0 // indirect
|
||||
github.com/mudler/cobra-extensions v0.0.0-20200612154940-31a47105fe3d
|
||||
github.com/mudler/go-pluggable v0.0.0-20211022125509-94dbf124830d
|
||||
github.com/mudler/go-pluggable v0.0.0-20211206135551-9263b05c562e
|
||||
github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290
|
||||
github.com/onsi/ginkgo v1.16.4
|
||||
github.com/onsi/gomega v1.16.0
|
||||
github.com/onsi/ginkgo/v2 v2.0.0
|
||||
github.com/onsi/gomega v1.17.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec v1.0.1
|
||||
github.com/opencontainers/image-spec v1.0.2-0.20210730191737-8e42a01fb1b7
|
||||
github.com/otiai10/copy v1.2.1-0.20200916181228-26f84a0b1578
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible
|
||||
@@ -64,12 +65,8 @@ require (
|
||||
go.uber.org/zap v1.17.0
|
||||
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/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
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
helm.sh/helm/v3 v3.3.4
|
||||
|
138
go.sum
138
go.sum
@@ -20,6 +20,12 @@ cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECH
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
||||
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
||||
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
||||
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
|
||||
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
|
||||
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
@@ -89,16 +95,17 @@ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugX
|
||||
github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
|
||||
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
|
||||
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
|
||||
github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
|
||||
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
|
||||
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
|
||||
github.com/Microsoft/hcsshim v0.8.16 h1:8/auA4LFIZFTGrqfKhGBSXwM6/4X1fHa/xniyEHu8ac=
|
||||
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
|
||||
github.com/Microsoft/hcsshim v0.8.21 h1:btRfUDThBE5IKcvI8O8jOiIkujUsAMBSRsYDYmEi6oM=
|
||||
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
||||
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
|
||||
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
|
||||
github.com/MottainaiCI/simplestreams-builder v0.1.0/go.mod h1:+Gbv6dg6TPHWq4oDjZY1vn978PLCEZ2hOu8kvn+S7t4=
|
||||
@@ -157,6 +164,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw=
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
@@ -182,6 +190,7 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
|
||||
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
|
||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 h1:xz6Nv3zcwO2Lila35hcb0QloCQsc38Al13RNEzWRpX4=
|
||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9/go.mod h1:2wSM9zJkl1UQEFZgSd68NfCgRz1VL1jzy/RjCg+ULrs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
@@ -191,6 +200,7 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE
|
||||
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
|
||||
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
|
||||
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ=
|
||||
@@ -198,7 +208,11 @@ github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
|
||||
@@ -234,8 +248,9 @@ github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7
|
||||
github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
|
||||
github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
|
||||
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
|
||||
github.com/containerd/containerd v1.5.2 h1:MG/Bg1pbmMb61j3wHCFWPxESXHieiKr2xG64px/k8zQ=
|
||||
github.com/containerd/containerd v1.5.2/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
|
||||
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
|
||||
github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM=
|
||||
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
@@ -265,8 +280,8 @@ github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJ
|
||||
github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
|
||||
github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
|
||||
github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.7.0 h1:1d/rydzTywc76lnjJb6qbPCiTiCwts49AzKps/Ecblw=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.7.0/go.mod h1:83VWDqHnurTKliEB0YvWMiCfLDwv4Cjj1X9Vk98GJZw=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.10.0 h1:glqzafvxBBAMo+x2w2sdDjUDZeTqqLJmqZPY05qehCU=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.10.0/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0=
|
||||
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
|
||||
github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
|
||||
github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
|
||||
@@ -310,6 +325,7 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/crillab/gophersat v1.3.2-0.20210701121804-72b19f5b6b38 h1:sOsE90v/iPmouqh4d3cKQl8JuqTOEXg+fP+7YuY7R6U=
|
||||
@@ -320,6 +336,7 @@ github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1S
|
||||
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
||||
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
|
||||
github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
|
||||
github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg=
|
||||
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=
|
||||
@@ -333,8 +350,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v20.10.7+incompatible h1:pv/3NqibQKphWZiAskMzdz8w0PRbtTaEB+f6NwdU7Is=
|
||||
github.com/docker/cli v20.10.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v20.10.10+incompatible h1:kcbwdgWbrBOH8QwQzaJmyriHwF7XIl4HT1qh0HTRys4=
|
||||
github.com/docker/cli v20.10.10+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
|
||||
github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
@@ -342,10 +359,11 @@ github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BU
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ=
|
||||
github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
|
||||
github.com/docker/docker v20.10.10+incompatible h1:GKkP0T7U4ks6X3lmmHKC2QDprnpRJor2Z5a8m62R9ZM=
|
||||
github.com/docker/docker v20.10.10+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o=
|
||||
github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c=
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
@@ -383,6 +401,7 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc=
|
||||
@@ -511,6 +530,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -554,8 +574,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-containerregistry v0.6.0 h1:niQ+8XD//kKgArIFwDVBXsWVWbde16LPdHMyNwSC8h4=
|
||||
github.com/google/go-containerregistry v0.6.0/go.mod h1:euCCtNbZ6tKqi1E72vwDj2xZcN5ttKpZLfa/wSo5iLw=
|
||||
github.com/google/go-containerregistry v0.7.0 h1:u0onUUOcyoCDHEiJoyR1R1gx5er1+r06V5DBhUU5ndk=
|
||||
github.com/google/go-containerregistry v0.7.0/go.mod h1:2zaoelrL0d08gGbpdP3LqyUuBmhWbpD6IOe2s9nLS2k=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -574,7 +594,10 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/renameio v1.0.0 h1:xhp2CnJmgQmpJU4RY8chagahUq5mbPPAbiSQstKpVMA=
|
||||
github.com/google/renameio v1.0.0/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
||||
@@ -586,6 +609,7 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
|
||||
@@ -601,8 +625,8 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
|
||||
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
|
||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
@@ -663,6 +687,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=
|
||||
@@ -696,9 +722,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.0 h1:2T7tUoQrQT+fQWdaY5rjWztFGAFwbGD04iPJg90ZiOs=
|
||||
github.com/klauspost/compress v1.13.0/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d h1:X4cedH4Kn3JPupAwwWuo4AzYp16P0OyLO9d7OnMZc/c=
|
||||
@@ -747,6 +772,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=
|
||||
@@ -810,8 +837,8 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P
|
||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
||||
github.com/mudler/cobra-extensions v0.0.0-20200612154940-31a47105fe3d h1:fKh+rvwZQCA+TPzK0EMwwbqhjvRHaQ6H8AsVU1Wt+NQ=
|
||||
github.com/mudler/cobra-extensions v0.0.0-20200612154940-31a47105fe3d/go.mod h1:puRUWSwyecW2V355tKncwPVPRAjQBduPsFjG0mrV/Nw=
|
||||
github.com/mudler/go-pluggable v0.0.0-20211022125509-94dbf124830d h1:NKvvf/q1dWDde+yg5cMiU5EuYZ2jNuKs/9hb8xod8A0=
|
||||
github.com/mudler/go-pluggable v0.0.0-20211022125509-94dbf124830d/go.mod h1:WmKcT8ONmhDQIqQ+HxU+tkGWjzBEyY/KFO8LTGCu4AI=
|
||||
github.com/mudler/go-pluggable v0.0.0-20211206135551-9263b05c562e h1:CZI+kJW2+WjZXLWWnVzi6NDQ6SfwSfeNqq5d1iDiwyY=
|
||||
github.com/mudler/go-pluggable v0.0.0-20211206135551-9263b05c562e/go.mod h1:WmKcT8ONmhDQIqQ+HxU+tkGWjzBEyY/KFO8LTGCu4AI=
|
||||
github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290 h1:426hFyXMpXeqIeGJn2cGAW9ogvM2Jf+Jv23gtVPvBLM=
|
||||
github.com/mudler/topsort v0.0.0-20201103161459-db5c7901c290/go.mod h1:uP5BBgFxq2wNWo7n1vnY5SSbgL0WDshVJrOO12tZ/lA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
@@ -848,6 +875,8 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
@@ -857,8 +886,9 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT
|
||||
github.com/onsi/gomega v1.10.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
|
||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
@@ -867,22 +897,26 @@ github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/image-spec v1.0.2-0.20210730191737-8e42a01fb1b7 h1:axgApq2XShTLwQii2zAnIkMPlhGVHbAXHUcHezu5G/k=
|
||||
github.com/opencontainers/image-spec v1.0.2-0.20210730191737-8e42a01fb1b7/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc93 h1:x2UMpOOVf3kQ8arv/EsDGwim8PTNqzL1/EYDr/+scOM=
|
||||
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
|
||||
github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg=
|
||||
github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
|
||||
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
||||
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
@@ -1079,6 +1113,9 @@ github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
|
||||
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
|
||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
||||
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
@@ -1139,15 +1176,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=
|
||||
@@ -1269,9 +1309,9 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a h1:c83jeVQW0KGKNaKBRfelNYNHaev+qawl9yaA825s8XE=
|
||||
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1285,8 +1325,11 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5 h1:Ati8dO7+U7mxpkPSxBZQEvzHVUYB/MqCklCN8ig5w/o=
|
||||
golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -1385,14 +1428,19 @@ golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08 h1:WecRHqgE09JBkh/584XIE6PMz5KKE/vER4izNUi30AQ=
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -1483,6 +1531,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1514,6 +1564,12 @@ google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBz
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
||||
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
||||
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
||||
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
||||
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -1570,8 +1626,21 @@ google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210811021853-ddbe55d93216 h1:qnrhhl4uoNFepTqE28u11llFcDH07Z6r/cQxpGR97A4=
|
||||
google.golang.org/genproto v0.0.0-20210811021853-ddbe55d93216/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211111162719-482062a4217b h1:qvEQEwKjZRAg6rjY/jqfJ7T8/w/D7jTIFJGcaSka96k=
|
||||
google.golang.org/genproto v0.0.0-20211111162719-482062a4217b/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
@@ -1602,8 +1671,11 @@ google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.1 h1:f37vZbBVTiJ6jKG5mWz8ySOBxNqy6ViPgyhSdVnxF3E=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
|
@@ -18,7 +18,7 @@ package client_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -20,8 +20,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/crane"
|
||||
"github.com/mudler/luet/pkg/api/client/utils"
|
||||
image "github.com/mudler/luet/pkg/api/core/image"
|
||||
)
|
||||
|
||||
func TreePackages(treedir string) (searchResult SearchResult, err error) {
|
||||
@@ -35,11 +35,6 @@ func TreePackages(treedir string) (searchResult SearchResult, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func imageAvailable(image string) bool {
|
||||
_, err := crane.Digest(image)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
type SearchResult struct {
|
||||
Packages []Package
|
||||
}
|
||||
@@ -66,7 +61,7 @@ func (p Package) ImageMetadata(repository string) string {
|
||||
}
|
||||
|
||||
func (p Package) ImageAvailable(repository string) bool {
|
||||
return imageAvailable(p.Image(repository))
|
||||
return image.Available(p.Image(repository))
|
||||
}
|
||||
|
||||
func (p Package) Equal(pp Package) bool {
|
||||
|
@@ -17,7 +17,7 @@ package client_test
|
||||
|
||||
import (
|
||||
. "github.com/mudler/luet/pkg/api/client"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package bus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/mudler/go-pluggable"
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
)
|
||||
@@ -13,6 +14,10 @@ var (
|
||||
EventPackageInstall pluggable.EventType = "package.install"
|
||||
// EventPackageUnInstall is the event fired when a new package is being uninstalled
|
||||
EventPackageUnInstall pluggable.EventType = "package.uninstall"
|
||||
// EventPreUpgrade is the event fired before an upgrade is attempted
|
||||
EventPreUpgrade pluggable.EventType = "package.pre.upgrade"
|
||||
// EventPostUpgrade is the event fired after an upgrade is done
|
||||
EventPostUpgrade pluggable.EventType = "package.post.upgrade"
|
||||
|
||||
// Package build
|
||||
|
||||
@@ -62,6 +67,8 @@ var Manager *Bus = &Bus{
|
||||
EventPackageInstall,
|
||||
EventPackageUnInstall,
|
||||
EventPackagePreBuild,
|
||||
EventPreUpgrade,
|
||||
EventPostUpgrade,
|
||||
EventPackagePreBuildArtifact,
|
||||
EventPackagePostBuildArtifact,
|
||||
EventPackagePostBuild,
|
||||
@@ -83,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 {
|
||||
|
@@ -18,9 +18,9 @@ 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/ginkgo/v2"
|
||||
. "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",
|
||||
|
@@ -19,7 +19,7 @@ package config_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
28
pkg/api/core/context/contest_suite_test.go
Normal file
28
pkg/api/core/context/contest_suite_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package context_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestContext(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Context Suite")
|
||||
}
|
159
pkg/api/core/context/context.go
Normal file
159
pkg/api/core/context/context.go
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package 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
|
||||
}
|
59
pkg/api/core/garbagecollector/garbagecollector.go
Normal file
59
pkg/api/core/garbagecollector/garbagecollector.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package 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)
|
||||
}
|
@@ -18,25 +18,25 @@ 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/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
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.
|
||||
})
|
||||
|
@@ -19,6 +19,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
containerdCompression "github.com/containerd/containerd/archive/compression"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||
@@ -27,13 +28,13 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func imageFromTar(imagename, architecture, OS string, r io.Reader) (name.Reference, v1.Image, error) {
|
||||
func imageFromTar(imagename, architecture, OS string, opener func() (io.ReadCloser, error)) (name.Reference, v1.Image, error) {
|
||||
newRef, err := name.ParseReference(imagename)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
layer, err := tarball.LayerFromReader(r)
|
||||
layer, err := tarball.LayerFromOpener(opener)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -67,28 +68,30 @@ func imageFromTar(imagename, architecture, OS string, r io.Reader) (name.Referen
|
||||
|
||||
// CreateTar a imagetarball from a standard tarball
|
||||
func CreateTar(srctar, dstimageTar, imagename, architecture, OS string) error {
|
||||
f, err := os.Open(srctar)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot open "+srctar)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return CreateTarReader(f, dstimageTar, imagename, architecture, OS)
|
||||
}
|
||||
|
||||
// CreateTarReader a imagetarball from a standard tarball
|
||||
func CreateTarReader(r io.Reader, dstimageTar, imagename, architecture, OS string) error {
|
||||
dstFile, err := os.Create(dstimageTar)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot create "+dstimageTar)
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
newRef, img, err := imageFromTar(imagename, architecture, OS, r)
|
||||
newRef, img, err := imageFromTar(imagename, architecture, OS, func() (io.ReadCloser, error) {
|
||||
f, err := os.Open(srctar)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Cannot open "+srctar)
|
||||
}
|
||||
decompressed, err := containerdCompression.DecompressStream(f)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Cannot open "+srctar)
|
||||
}
|
||||
|
||||
return decompressed, nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// NOTE: We might also stream that back to the daemon with daemon.Write(tag, img)
|
||||
return tarball.Write(newRef, img, dstFile)
|
||||
|
||||
}
|
||||
|
@@ -20,24 +20,24 @@ 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"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
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())
|
||||
|
||||
@@ -47,7 +47,7 @@ var _ = Describe("Create", func() {
|
||||
img, err := b.ImageReference("alpine", false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, dir, err := Extract(ctx, img, false, nil)
|
||||
_, dir, err := Extract(ctx, img, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
@@ -69,7 +69,7 @@ var _ = Describe("Create", func() {
|
||||
img, err = b.ImageReference("testimage", false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, dir, err = Extract(ctx, img, false, nil)
|
||||
_, dir, err = Extract(ctx, img, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
|
@@ -23,10 +23,10 @@ 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/ginkgo/v2"
|
||||
. "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())
|
||||
@@ -74,14 +74,18 @@ var _ = Describe("Delta", func() {
|
||||
_, tmpdir, err := Extract(
|
||||
ctx,
|
||||
img2,
|
||||
true,
|
||||
f,
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(tmpdir) // clean up
|
||||
|
||||
// No extra dirs are present
|
||||
Expect(file.Exists(filepath.Join(tmpdir, "home"))).To(BeFalse())
|
||||
// Cache from go
|
||||
Expect(file.Exists(filepath.Join(tmpdir, "root", ".cache"))).To(BeTrue())
|
||||
// sh is present from alpine, hence not in the result
|
||||
Expect(file.Exists(filepath.Join(tmpdir, "bin", "sh"))).To(BeFalse())
|
||||
// /usr/local/go is part of golang:alpine
|
||||
Expect(file.Exists(filepath.Join(tmpdir, "usr", "local", "go"))).To(BeTrue())
|
||||
Expect(file.Exists(filepath.Join(tmpdir, "usr", "local", "go", "bin"))).To(BeTrue())
|
||||
})
|
||||
@@ -94,7 +98,6 @@ var _ = Describe("Delta", func() {
|
||||
_, tmpdir, err := Extract(
|
||||
ctx,
|
||||
img2,
|
||||
true,
|
||||
f,
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -109,7 +112,6 @@ var _ = Describe("Delta", func() {
|
||||
_, tmpdir, err := Extract(
|
||||
ctx,
|
||||
img2,
|
||||
true,
|
||||
f,
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -124,7 +126,6 @@ var _ = Describe("Delta", func() {
|
||||
_, tmpdir, err := Extract(
|
||||
ctx,
|
||||
img2,
|
||||
true,
|
||||
f,
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
42
pkg/api/core/image/digest.go
Normal file
42
pkg/api/core/image/digest.go
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package image
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/crane"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
)
|
||||
|
||||
// Available checks if the image is available in the remote endpoint.
|
||||
func Available(image string, opt ...crane.Option) bool {
|
||||
// We use crane.insecure as we just check if the image is available
|
||||
// It's the daemon duty to use it or not based on the host settings
|
||||
transport := remote.DefaultTransport.Clone()
|
||||
transport.TLSClientConfig = &tls.Config{
|
||||
InsecureSkipVerify: true, //nolint: gosec
|
||||
}
|
||||
|
||||
var rt http.RoundTripper = transport
|
||||
if len(opt) == 0 {
|
||||
opt = append(opt, crane.Insecure, crane.WithTransport(rt))
|
||||
}
|
||||
|
||||
_, err := crane.Digest(image, opt...)
|
||||
return err == nil
|
||||
}
|
@@ -22,10 +22,8 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
containerdarchive "github.com/containerd/containerd/archive"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
@@ -37,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) {
|
||||
@@ -45,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
|
||||
}
|
||||
@@ -67,12 +65,7 @@ func ExtractDeltaAdditionsFiles(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch hdr.Typeflag {
|
||||
case tar.TypeDir:
|
||||
filesSrc.Set(filepath.Dir(hdr.Name), "")
|
||||
default:
|
||||
filesSrc.Set(hdr.Name, "")
|
||||
}
|
||||
filesSrc.Set(hdr.Name, "")
|
||||
}
|
||||
|
||||
return func(h *tar.Header) (bool, error) {
|
||||
@@ -130,7 +123,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) {
|
||||
@@ -195,7 +188,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, keepPerms bool, 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.
|
||||
@@ -203,34 +196,7 @@ func ExtractReader(ctx *types.Context, reader io.ReadCloser, output string, keep
|
||||
filter = func(h *tar.Header) (bool, error) { return true, nil }
|
||||
}
|
||||
|
||||
// Keep records of permissions as we walk the tar
|
||||
type permData struct {
|
||||
PAX, Xattrs map[string]string
|
||||
Uid, Gid int
|
||||
Name string
|
||||
}
|
||||
|
||||
permstore, err := ctx.Config.System.TempDir("permstore")
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
perms := NewCache(permstore, 50*1024*1024, 10000)
|
||||
|
||||
f := func(h *tar.Header) (bool, error) {
|
||||
res, err := filter(h)
|
||||
if res {
|
||||
perms.SetValue(h.Name, permData{
|
||||
PAX: h.PAXRecords,
|
||||
Uid: h.Uid, Gid: h.Gid,
|
||||
Xattrs: h.Xattrs,
|
||||
Name: h.Name,
|
||||
})
|
||||
//perms = append(perms, })
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
opts = append(opts, containerdarchive.WithFilter(f))
|
||||
opts = append(opts, containerdarchive.WithFilter(filter))
|
||||
|
||||
// Handle the extraction
|
||||
c, err := containerdarchive.Apply(context.Background(), output, reader, opts...)
|
||||
@@ -238,42 +204,19 @@ func ExtractReader(ctx *types.Context, reader io.ReadCloser, output string, keep
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
// Reconstruct permissions
|
||||
if keepPerms {
|
||||
ctx.Debug("Reconstructing permissions")
|
||||
perms.All(func(cr CacheResult) {
|
||||
p := &permData{}
|
||||
cr.Unmarshal(p)
|
||||
ff := filepath.Join(output, p.Name)
|
||||
if _, err := os.Lstat(ff); err == nil {
|
||||
if err := os.Lchown(ff, p.Uid, p.Gid); err != nil {
|
||||
ctx.Warning(err, "failed chowning file")
|
||||
}
|
||||
}
|
||||
for _, attrs := range []map[string]string{p.Xattrs, p.PAX} {
|
||||
for k, attr := range attrs {
|
||||
if err := system.Lsetxattr(ff, k, []byte(attr), 0); err != nil {
|
||||
if errors.Is(err, syscall.ENOTSUP) {
|
||||
ctx.Debug("ignored xattr %s in archive", ff)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return c, output, nil
|
||||
}
|
||||
|
||||
// Extract is just syntax sugar around ExtractReader. It extracts an image into a dir
|
||||
func Extract(ctx *types.Context, img v1.Image, keepPerms bool, 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")
|
||||
}
|
||||
return ExtractReader(ctx, mutate.Extract(img), tmpdiffs, keepPerms, filter, opts...)
|
||||
return ExtractReader(ctx, mutate.Extract(img), tmpdiffs, filter, opts...)
|
||||
}
|
||||
|
||||
// ExtractTo is just syntax sugar around ExtractReader
|
||||
func ExtractTo(ctx *types.Context, img v1.Image, output string, keepPerms bool, filter func(h *tar.Header) (bool, error), opts ...containerdarchive.ApplyOpt) (int64, string, error) {
|
||||
return ExtractReader(ctx, mutate.Extract(img), output, keepPerms, filter, opts...)
|
||||
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...)
|
||||
}
|
||||
|
@@ -23,10 +23,10 @@ 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/ginkgo/v2"
|
||||
. "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())
|
||||
@@ -58,7 +58,6 @@ var _ = Describe("Extract", func() {
|
||||
_, tmpdir, err := Extract(
|
||||
ctx,
|
||||
img,
|
||||
true,
|
||||
ExtractFiles(ctx, "", []string{}, []string{}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -72,7 +71,6 @@ var _ = Describe("Extract", func() {
|
||||
_, tmpdir, err := Extract(
|
||||
ctx,
|
||||
img,
|
||||
true,
|
||||
ExtractFiles(ctx, "/usr", []string{}, []string{}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -86,7 +84,6 @@ var _ = Describe("Extract", func() {
|
||||
_, tmpdir, err := Extract(
|
||||
ctx,
|
||||
img,
|
||||
true,
|
||||
ExtractFiles(ctx, "/usr", []string{"bin"}, []string{"sbin"}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -101,7 +98,6 @@ var _ = Describe("Extract", func() {
|
||||
_, tmpdir, err := Extract(
|
||||
ctx,
|
||||
img,
|
||||
true,
|
||||
ExtractFiles(ctx, "", []string{"/usr|/usr/bin"}, []string{"^/bin"}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
@@ -18,17 +18,17 @@ 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/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestMutator(t *testing.T) {
|
||||
func TestImageApi(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"})
|
||||
|
||||
RunSpecs(t, "Mutator API Suite")
|
||||
RunSpecs(t, "Image API Suite")
|
||||
}
|
||||
|
28
pkg/api/core/logger/config_suite_test.go
Normal file
28
pkg/api/core/logger/config_suite_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package logger_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestAPITypes(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Types Suite")
|
||||
}
|
367
pkg/api/core/logger/logger.go
Normal file
367
pkg/api/core/logger/logger.go
Normal file
@@ -0,0 +1,367 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package 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(joinMsg(prefixCodeLine(sanitizedF)...), args...)
|
||||
if l.logToFile {
|
||||
l.fileLogger.Sugar().Debugf(joinMsg(prefixCodeLine(sanitizedF)...), 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()
|
||||
}
|
||||
}
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types_test
|
||||
package logger_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
@@ -21,8 +21,9 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/gookit/color"
|
||||
types "github.com/mudler/luet/pkg/api/core/types"
|
||||
. "github.com/onsi/ginkgo"
|
||||
"github.com/mudler/luet/pkg/api/core/logger"
|
||||
. "github.com/mudler/luet/pkg/api/core/logger"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "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"))
|
43
pkg/api/core/logger/terminal.go
Normal file
43
pkg/api/core/logger/terminal.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package 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
|
||||
}
|
39
pkg/api/core/template/directory.go
Normal file
39
pkg/api/core/template/directory.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright © 2022 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const Directory = "templates"
|
||||
|
||||
// FindPossibleTemplatesDir returns templates dir located at root
|
||||
func FindPossibleTemplatesDir(root string) (res []string) {
|
||||
var ff = func(currentpath string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if info.IsDir() && info.Name() == Directory {
|
||||
res = append(res, currentpath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
filepath.Walk(root, ff)
|
||||
return
|
||||
}
|
@@ -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,8 +70,8 @@ type PackageArtifact struct {
|
||||
Runtime *pkg.DefaultPackage `json:"runtime,omitempty"`
|
||||
}
|
||||
|
||||
func ImageToArtifact(ctx *types.Context, img v1.Image, t compression.Implementation, output string, keepPerms bool, filter func(h *tar.Header) (bool, error)) (*PackageArtifact, error) {
|
||||
_, tmpdiffs, err := image.Extract(ctx, img, keepPerms, filter)
|
||||
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,25 +210,15 @@ 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 {
|
||||
archiveFile, err := os.Open(a.Path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot open "+a.Path)
|
||||
}
|
||||
defer archiveFile.Close()
|
||||
func (a *PackageArtifact) GenerateFinalImage(ctx types.Context, imageName string, b ImageBuilder, keepPerms bool) error {
|
||||
|
||||
decompressed, err := containerdCompression.DecompressStream(archiveFile)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot open "+a.Path)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
defer os.RemoveAll(tempimage.Name()) // clean up
|
||||
|
||||
if err := image.CreateTarReader(decompressed, tempimage.Name(), imageName, runtime.GOARCH, runtime.GOOS); err != nil {
|
||||
if err := image.CreateTar(a.Path, tempimage.Name(), imageName, runtime.GOARCH, runtime.GOOS); err != nil {
|
||||
return errors.Wrap(err, "could not create image from tar")
|
||||
}
|
||||
|
||||
@@ -438,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
|
||||
@@ -505,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 &&
|
||||
@@ -521,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)
|
||||
@@ -531,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")
|
||||
@@ -570,7 +560,7 @@ func (a *PackageArtifact) Unpack(ctx *types.Context, dst string, keepPerms bool)
|
||||
// // tarModifier.Modifier()
|
||||
// return true, nil
|
||||
// },
|
||||
_, _, err = image.ExtractReader(ctx, replacerArchive, dst, ctx.Config.GetGeneral().SameOwner, nil)
|
||||
_, _, err = image.ExtractReader(ctx, replacerArchive, dst, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@@ -18,7 +18,7 @@ package artifact_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -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"
|
||||
@@ -33,13 +32,13 @@ import (
|
||||
fileHelper "github.com/mudler/luet/pkg/helpers/file"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/luet/pkg/tree"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
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`)
|
||||
|
||||
@@ -161,7 +160,6 @@ RUN echo bar > /test2`))
|
||||
ctx,
|
||||
img,
|
||||
result,
|
||||
false,
|
||||
nil,
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -178,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")
|
||||
@@ -210,7 +208,6 @@ RUN echo bar > /test2`))
|
||||
ctx,
|
||||
img,
|
||||
result,
|
||||
false,
|
||||
nil,
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
@@ -20,13 +20,13 @@ 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"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
. "github.com/mudler/luet/pkg/api/core/types/artifact"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -1,6 +1,4 @@
|
||||
// Copyright © 2019 Ettore Di Giacinto <mudler@gentoo.org>
|
||||
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||
// 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
// Copyright © 2019-2021 Ettore Di Giacinto <mudler@gentoo.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@@ -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 {
|
||||
@@ -61,6 +62,7 @@ type LuetGeneralConfig struct {
|
||||
ShowBuildOutput bool `yaml:"show_build_output,omitempty" mapstructure:"show_build_output"`
|
||||
FatalWarns bool `yaml:"fatal_warnings,omitempty" mapstructure:"fatal_warnings"`
|
||||
HTTPTimeout int `yaml:"http_timeout,omitempty" mapstructure:"http_timeout"`
|
||||
Quiet bool `yaml:"quiet" mapstructure:"quiet"`
|
||||
}
|
||||
|
||||
type LuetSolverOptions struct {
|
||||
@@ -107,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
|
||||
}
|
||||
@@ -117,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)
|
||||
@@ -127,43 +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() (ans 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) {
|
||||
ans = cachepath
|
||||
} else {
|
||||
ans = filepath.Join(sc.GetSystemRepoDatabaseDirPath(), cachepath)
|
||||
}
|
||||
|
||||
return
|
||||
sc.PkgsCachePath = cachepath // Be consistent with the path we set
|
||||
}
|
||||
|
||||
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"`
|
||||
@@ -176,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)
|
||||
}
|
||||
@@ -195,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 {
|
||||
@@ -279,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
|
||||
}
|
||||
|
||||
@@ -310,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
|
||||
}
|
||||
|
||||
@@ -356,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
|
||||
}
|
||||
|
||||
@@ -387,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 {
|
||||
@@ -426,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)
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ package types_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -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/ginkgo/v2"
|
||||
. "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())
|
||||
|
@@ -15,402 +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
|
||||
|
||||
s *pterm.SpinnerPrinter
|
||||
spinnerLock *sync.Mutex
|
||||
z *zap.Logger
|
||||
AreaPrinter *pterm.AreaPrinter
|
||||
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) 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()
|
||||
}
|
||||
|
||||
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.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
|
||||
}
|
||||
|
25
pkg/api/core/types/garbagecollector.go
Normal file
25
pkg/api/core/types/garbagecollector.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import "os"
|
||||
|
||||
type GarbageCollector interface {
|
||||
Clean() error
|
||||
TempDir(pattern string) (string, error)
|
||||
TempFile(s string) (*os.File, error)
|
||||
String() string
|
||||
}
|
41
pkg/api/core/types/logger.go
Normal file
41
pkg/api/core/types/logger.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright © 2021 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
// 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)
|
||||
}
|
@@ -19,7 +19,7 @@ import (
|
||||
"runtime"
|
||||
|
||||
types "github.com/mudler/luet/pkg/api/core/types"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -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 {
|
||||
|
@@ -18,7 +18,7 @@ package backend_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -19,8 +19,6 @@ import (
|
||||
"os/exec"
|
||||
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/crane"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -29,11 +27,6 @@ const (
|
||||
DockerBackend = "docker"
|
||||
)
|
||||
|
||||
func imageAvailable(image string) bool {
|
||||
_, err := crane.Digest(image)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
ImageName string
|
||||
SourcePath string
|
||||
@@ -43,9 +36,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
|
||||
|
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/google/go-containerregistry/pkg/v1/daemon"
|
||||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||
bus "github.com/mudler/luet/pkg/api/core/bus"
|
||||
"github.com/mudler/luet/pkg/api/core/image"
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
@@ -32,10 +33,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}
|
||||
}
|
||||
|
||||
@@ -118,7 +119,7 @@ func (s *SimpleDocker) ImageExists(imagename string) bool {
|
||||
}
|
||||
|
||||
func (*SimpleDocker) ImageAvailable(imagename string) bool {
|
||||
return imageAvailable(imagename)
|
||||
return image.Available(imagename)
|
||||
}
|
||||
|
||||
func (s *SimpleDocker) RemoveImage(opts Options) error {
|
||||
@@ -190,7 +191,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
|
||||
}
|
||||
|
@@ -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"
|
||||
@@ -28,13 +28,13 @@ import (
|
||||
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/luet/pkg/tree"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
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))
|
||||
|
||||
|
@@ -22,16 +22,17 @@ import (
|
||||
"github.com/google/go-containerregistry/pkg/crane"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
bus "github.com/mudler/luet/pkg/api/core/bus"
|
||||
"github.com/mudler/luet/pkg/api/core/image"
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
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 +78,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
|
||||
}
|
||||
@@ -135,7 +136,7 @@ func (s *SimpleImg) CopyImage(src, dst string) error {
|
||||
}
|
||||
|
||||
func (s *SimpleImg) ImageAvailable(imagename string) bool {
|
||||
return imageAvailable(imagename)
|
||||
return image.Available(imagename)
|
||||
}
|
||||
|
||||
// ImageExists check if the given image is available locally
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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,23 +239,11 @@ func (cs *LuetCompiler) unpackFs(concurrency int, keepPermissions bool, p *compi
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// artifact.ImageToArtifact(
|
||||
// cs.Options.Context,
|
||||
// img,
|
||||
// cs.Options.CompressionType,
|
||||
// p.Rel(p.GetPackage().GetFingerPrint()+".package.tar"),
|
||||
// image.ExtractFiles(
|
||||
// cs.Options.Context,
|
||||
// strings.TrimLeft(p.GetPackageDir(), "/"),
|
||||
// p.GetIncludes(),
|
||||
// p.GetExcludes(),
|
||||
// ),
|
||||
// )
|
||||
// TODO: Trim includes/excludes from "/" ?
|
||||
ctx := cs.Options.Context.WithLoggingContext(fmt.Sprintf("extract %s", runnerOpts.ImageName))
|
||||
|
||||
_, rootfs, err := image.Extract(
|
||||
cs.Options.Context,
|
||||
ctx,
|
||||
img,
|
||||
keepPermissions,
|
||||
image.ExtractFiles(
|
||||
cs.Options.Context,
|
||||
p.GetPackageDir(),
|
||||
@@ -287,11 +275,11 @@ 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 := ioutil.TempDir(p.GetOutputPath(), "rootfs")
|
||||
rootfs, err := cs.Options.Context.TempDir("rootfs")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not create tempdir")
|
||||
}
|
||||
defer os.RemoveAll(rootfs) // clean up
|
||||
defer os.RemoveAll(rootfs)
|
||||
|
||||
pkgTag := ":package: " + p.GetPackage().HumanReadableString()
|
||||
if cs.Options.PullFirst {
|
||||
@@ -338,7 +326,6 @@ func (cs *LuetCompiler) unpackDelta(concurrency int, keepPermissions bool, p *co
|
||||
ref2,
|
||||
cs.Options.CompressionType,
|
||||
p.Rel(fmt.Sprintf("%s%s", p.GetPackage().GetFingerPrint(), ".package.tar")),
|
||||
keepPermissions,
|
||||
filter,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -365,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
|
||||
}
|
||||
@@ -386,7 +373,7 @@ func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImag
|
||||
}
|
||||
|
||||
// First we create the builder image
|
||||
if err := p.WriteBuildImageDefinition(filepath.Join(buildDir, p.GetPackage().GetFingerPrint()+"-builder.dockerfile")); err != nil {
|
||||
if err := p.WriteBuildImageDefinition(filepath.Join(buildDir, p.GetPackage().ImageID()+"-builder.dockerfile")); err != nil {
|
||||
return builderOpts, runnerOpts, errors.Wrap(err, "Could not generate image definition")
|
||||
}
|
||||
|
||||
@@ -401,21 +388,21 @@ func (cs *LuetCompiler) buildPackageImage(image, buildertaggedImage, packageImag
|
||||
// steps in prelude are == 0 those are equivalent.
|
||||
|
||||
// Then we write the step image, which uses the builder one
|
||||
if err := p.WriteStepImageDefinition(buildertaggedImage, filepath.Join(buildDir, p.GetPackage().GetFingerPrint()+".dockerfile")); err != nil {
|
||||
if err := p.WriteStepImageDefinition(buildertaggedImage, filepath.Join(buildDir, p.GetPackage().ImageID()+".dockerfile")); err != nil {
|
||||
return builderOpts, runnerOpts, errors.Wrap(err, "Could not generate image definition")
|
||||
}
|
||||
|
||||
builderOpts = backend.Options{
|
||||
ImageName: buildertaggedImage,
|
||||
SourcePath: buildDir,
|
||||
DockerFileName: p.GetPackage().GetFingerPrint() + "-builder.dockerfile",
|
||||
DockerFileName: p.GetPackage().ImageID() + "-builder.dockerfile",
|
||||
Destination: p.Rel(p.GetPackage().GetFingerPrint() + "-builder.image.tar"),
|
||||
BackendArgs: cs.Options.BackendArgs,
|
||||
}
|
||||
runnerOpts = backend.Options{
|
||||
ImageName: packageImage,
|
||||
SourcePath: buildDir,
|
||||
DockerFileName: p.GetPackage().GetFingerPrint() + ".dockerfile",
|
||||
DockerFileName: p.GetPackage().ImageID() + ".dockerfile",
|
||||
Destination: p.Rel(p.GetPackage().GetFingerPrint() + ".image.tar"),
|
||||
BackendArgs: cs.Options.BackendArgs,
|
||||
}
|
||||
@@ -473,11 +460,11 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder
|
||||
if p.EmptyPackage() {
|
||||
fakePackage := p.Rel(p.GetPackage().GetFingerPrint() + ".package.tar")
|
||||
|
||||
rootfs, err = ioutil.TempDir(p.GetOutputPath(), "rootfs")
|
||||
rootfs, err = cs.Options.Context.TempDir("rootfs")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not create tempdir")
|
||||
}
|
||||
defer os.RemoveAll(rootfs) // clean up
|
||||
defer os.RemoveAll(rootfs)
|
||||
|
||||
a := artifact.NewPackageArtifact(fakePackage)
|
||||
a.CompressionType = cs.Options.CompressionType
|
||||
@@ -488,12 +475,16 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder
|
||||
|
||||
a.CompileSpec = p
|
||||
a.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String())
|
||||
|
||||
err = a.WriteYAML(p.GetOutputPath())
|
||||
if err != nil {
|
||||
return a, errors.Wrap(err, "Failed while writing metadata file")
|
||||
}
|
||||
cs.Options.Context.Success(pkgTag, " :white_check_mark: done (empty virtual package)")
|
||||
if cs.Options.PushFinalImages {
|
||||
if err := cs.pushFinalArtifact(a, p, keepPermissions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
@@ -511,23 +502,69 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder
|
||||
}
|
||||
}
|
||||
|
||||
filelist, err := a.FileList()
|
||||
if err != nil {
|
||||
return a, errors.Wrapf(err, "Failed getting package list for '%s' '%s'", a.Path, a.CompileSpec.Package.HumanReadableString())
|
||||
if !p.Package.Hidden {
|
||||
filelist, err := a.FileList()
|
||||
if err != nil {
|
||||
return a, errors.Wrapf(err, "Failed getting package list for '%s' '%s'", a.Path, a.CompileSpec.Package.HumanReadableString())
|
||||
}
|
||||
a.Files = filelist
|
||||
}
|
||||
|
||||
a.Files = filelist
|
||||
a.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String())
|
||||
|
||||
err = a.WriteYAML(p.GetOutputPath())
|
||||
if err != nil {
|
||||
return a, errors.Wrap(err, "Failed while writing metadata file")
|
||||
}
|
||||
cs.Options.Context.Success(pkgTag, " :white_check_mark: Done")
|
||||
cs.Options.Context.Success(pkgTag, " :white_check_mark: Done building")
|
||||
|
||||
if cs.Options.PushFinalImages {
|
||||
if err := cs.pushFinalArtifact(a, p, keepPermissions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// TODO: A small readaptation of repository_docker.go pushImageFromArtifact()
|
||||
// Move this to a common place
|
||||
func (cs *LuetCompiler) pushFinalArtifact(a *artifact.PackageArtifact, p *compilerspec.LuetCompilationSpec, keepPermissions bool) error {
|
||||
cs.Options.Context.Info("Pushing final image for", a.CompileSpec.Package.HumanReadableString())
|
||||
imageID := fmt.Sprintf("%s:%s", cs.Options.PushFinalImagesRepository, a.CompileSpec.Package.ImageID())
|
||||
|
||||
// First push the package image
|
||||
if !cs.Backend.ImageAvailable(imageID) || cs.Options.PushFinalImagesForce {
|
||||
cs.Options.Context.Info("Generating and pushing final image for", a.CompileSpec.Package.HumanReadableString(), "as", imageID)
|
||||
|
||||
if err := a.GenerateFinalImage(cs.Options.Context, imageID, cs.GetBackend(), true); err != nil {
|
||||
return errors.Wrap(err, "while creating final image")
|
||||
}
|
||||
if err := cs.Backend.Push(backend.Options{ImageName: imageID}); err != nil {
|
||||
return errors.Wrapf(err, "Could not push image: %s", imageID)
|
||||
}
|
||||
}
|
||||
|
||||
// Then the image ID
|
||||
metadataImageID := fmt.Sprintf("%s:%s", cs.Options.PushFinalImagesRepository, helpers.SanitizeImageString(a.CompileSpec.GetPackage().GetMetadataFilePath()))
|
||||
if !cs.Backend.ImageAvailable(metadataImageID) || cs.Options.PushFinalImagesForce {
|
||||
cs.Options.Context.Info("Generating metadata image for", a.CompileSpec.Package.HumanReadableString(), metadataImageID)
|
||||
|
||||
a := artifact.NewPackageArtifact(filepath.Join(p.GetOutputPath(), a.CompileSpec.GetPackage().GetMetadataFilePath()))
|
||||
metadataArchive, err := artifact.CreateArtifactForFile(cs.Options.Context, a.Path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed generating checksums for tree")
|
||||
}
|
||||
if err := metadataArchive.GenerateFinalImage(cs.Options.Context, metadataImageID, cs.Backend, keepPermissions); err != nil {
|
||||
return errors.Wrap(err, "Failed generating metadata tree "+metadataImageID)
|
||||
}
|
||||
if err = cs.Backend.Push(backend.Options{ImageName: metadataImageID}); err != nil {
|
||||
return errors.Wrapf(err, "Could not push image: %s", metadataImageID)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) waitForImages(images []string) {
|
||||
if cs.Options.PullFirst && cs.Options.Wait {
|
||||
available, _ := oneOfImagesAvailable(images, cs.Backend)
|
||||
@@ -906,11 +943,11 @@ func (cs *LuetCompiler) resolveFinalImages(concurrency int, keepPermissions bool
|
||||
}
|
||||
|
||||
// otherwise, generate it and push it aside
|
||||
joinDir, err := ioutil.TempDir(p.GetOutputPath(), "join")
|
||||
joinDir, err := cs.Options.Context.TempDir("join")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not create tempdir for joining images")
|
||||
}
|
||||
defer os.RemoveAll(joinDir) // clean up
|
||||
defer os.RemoveAll(joinDir)
|
||||
|
||||
for _, p := range fromPackages {
|
||||
cs.Options.Context.Info(joinTag, ":arrow_right_hook:", p.HumanReadableString(), ":leaves:")
|
||||
@@ -945,11 +982,11 @@ func (cs *LuetCompiler) resolveFinalImages(concurrency int, keepPermissions bool
|
||||
}
|
||||
}
|
||||
|
||||
artifactDir, err := ioutil.TempDir(p.GetOutputPath(), "artifact")
|
||||
artifactDir, err := cs.Options.Context.TempDir("join")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not create tempdir for final artifact")
|
||||
}
|
||||
defer os.RemoveAll(joinDir) // clean up
|
||||
defer os.RemoveAll(artifactDir)
|
||||
|
||||
cs.Options.Context.Info(joinTag, ":droplet: generating artifact for source image of", p.GetPackage().HumanReadableString())
|
||||
|
||||
@@ -1020,6 +1057,36 @@ func (cs *LuetCompiler) resolveMultiStageImages(concurrency int, keepPermissions
|
||||
return nil
|
||||
}
|
||||
|
||||
func CompilerFinalImages(cs *LuetCompiler) (*LuetCompiler, error) {
|
||||
// When computing the hash tree, we need to take into consideration
|
||||
// that packages that require final images have to be seen as packages without deps
|
||||
// This is because we don't really want to calculate the deptree of them as
|
||||
// as it is handled already when we are creating the images in resolveFinalImages().
|
||||
c := *cs
|
||||
copy := &c
|
||||
memDB := pkg.NewInMemoryDatabase(false)
|
||||
// Create a copy to avoid races
|
||||
dbCopy := pkg.NewInMemoryDatabase(false)
|
||||
err := cs.Database.Clone(dbCopy)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed cloning db")
|
||||
}
|
||||
for _, p := range dbCopy.World() {
|
||||
copy := p.Clone()
|
||||
spec, err := cs.FromPackage(p)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed getting compile spec for package "+p.HumanReadableString())
|
||||
}
|
||||
if spec.RequiresFinalImages {
|
||||
copy.Requires([]*pkg.DefaultPackage{})
|
||||
}
|
||||
|
||||
memDB.CreatePackage(copy)
|
||||
}
|
||||
copy.Database = memDB
|
||||
return copy, nil
|
||||
}
|
||||
|
||||
func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, generateFinalArtifact *bool, generateDependenciesFinalArtifact *bool, p *compilerspec.LuetCompilationSpec) (*artifact.PackageArtifact, error) {
|
||||
cs.Options.Context.Info(":package: Compiling", p.GetPackage().HumanReadableString(), ".... :coffee:")
|
||||
|
||||
@@ -1043,8 +1110,11 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, generateF
|
||||
}
|
||||
|
||||
ht := NewHashTree(cs.Database)
|
||||
|
||||
packageHashTree, err := ht.Query(cs, p)
|
||||
copy, err := CompilerFinalImages(cs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packageHashTree, err := ht.Query(copy, p)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed querying hashtree")
|
||||
}
|
||||
@@ -1102,6 +1172,7 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, generateF
|
||||
buildTarget := !cs.Options.OnlyDeps
|
||||
|
||||
if buildDeps {
|
||||
|
||||
cs.Options.Context.Info(":deciduous_tree: Build dependencies for " + p.GetPackage().HumanReadableString())
|
||||
for _, assertion := range dependencies { //highly dependent on the order
|
||||
depsN++
|
||||
@@ -1117,6 +1188,7 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, generateF
|
||||
return nil, errors.Wrap(err, "Error while generating compilespec for "+assertion.Package.GetName())
|
||||
}
|
||||
compileSpec.BuildOptions.PullImageRepository = append(compileSpec.BuildOptions.PullImageRepository, p.BuildOptions.PullImageRepository...)
|
||||
|
||||
cs.Options.Context.Debug("PullImage repos:", compileSpec.BuildOptions.PullImageRepository)
|
||||
|
||||
compileSpec.SetOutputPath(p.GetOutputPath())
|
||||
@@ -1273,11 +1345,12 @@ func (cs *LuetCompiler) templatePackage(vals []map[string]interface{}, pack pkg.
|
||||
} else {
|
||||
bv := cs.Options.BuildValuesFile
|
||||
if len(vals) > 0 {
|
||||
valuesdir, err := ioutil.TempDir("", "genvalues")
|
||||
valuesdir, err := cs.Options.Context.TempDir("genvalues")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not create tempdir")
|
||||
}
|
||||
defer os.RemoveAll(valuesdir) // clean up
|
||||
defer os.RemoveAll(valuesdir)
|
||||
|
||||
for _, b := range vals {
|
||||
out, err := yaml.Marshal(b)
|
||||
if err != nil {
|
||||
|
@@ -18,7 +18,7 @@ package compiler_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -16,11 +16,16 @@
|
||||
package compiler_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
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/artifact"
|
||||
. "github.com/mudler/luet/pkg/compiler"
|
||||
sd "github.com/mudler/luet/pkg/compiler/backend"
|
||||
@@ -30,12 +35,12 @@ import (
|
||||
fileHelper "github.com/mudler/luet/pkg/helpers/file"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/luet/pkg/tree"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Compiler", func() {
|
||||
ctx := types.NewContext()
|
||||
ctx := context.NewContext()
|
||||
|
||||
Context("Simple package build definition", func() {
|
||||
It("Compiles it correctly", func() {
|
||||
@@ -46,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())
|
||||
@@ -89,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())
|
||||
@@ -119,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())
|
||||
@@ -151,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())
|
||||
@@ -185,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"})
|
||||
@@ -209,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())
|
||||
@@ -265,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())
|
||||
@@ -789,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())
|
||||
@@ -853,6 +858,67 @@ var _ = Describe("Compiler", func() {
|
||||
Expect(fileHelper.Exists(spec.Rel("bin/busybox"))).To(BeTrue())
|
||||
Expect(fileHelper.Exists(spec.Rel("var"))).ToNot(BeTrue())
|
||||
})
|
||||
|
||||
It("Pushes final images along", func() {
|
||||
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||
|
||||
randString := strings.ToLower(helpers.String(10))
|
||||
imageName := fmt.Sprintf("ttl.sh/%s", randString)
|
||||
b := sd.NewSimpleDockerBackend(ctx)
|
||||
|
||||
err := generalRecipe.Load("../../tests/fixtures/packagelayers")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(2))
|
||||
|
||||
compiler := NewLuetCompiler(b, generalRecipe.GetDatabase(),
|
||||
options.EnablePushFinalImages, options.ForcePushFinalImages, options.WithFinalRepository(imageName))
|
||||
|
||||
spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "runtime", Category: "layer", Version: "0.1"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
spec2, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "build", Category: "layer", Version: "0.1"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "tree")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(tmpdir) // clean up
|
||||
|
||||
spec.SetOutputPath(tmpdir)
|
||||
|
||||
artifacts, errs := compiler.CompileParallel(false, compilerspec.NewLuetCompilationspecs(spec, spec2))
|
||||
Expect(errs).To(BeNil())
|
||||
Expect(len(artifacts)).To(Equal(2))
|
||||
//Expect(len(artifacts[0].Dependencies)).To(Equal(1))
|
||||
|
||||
Expect(b.ImageAvailable(fmt.Sprintf("%s:%s", imageName, artifacts[0].Runtime.ImageID()))).To(BeTrue())
|
||||
Expect(b.ImageAvailable(fmt.Sprintf("%s:%s", imageName, artifacts[0].Runtime.GetMetadataFilePath()))).To(BeTrue())
|
||||
|
||||
Expect(b.ImageAvailable(fmt.Sprintf("%s:%s", imageName, artifacts[1].Runtime.ImageID()))).To(BeTrue())
|
||||
Expect(b.ImageAvailable(fmt.Sprintf("%s:%s", imageName, artifacts[1].Runtime.GetMetadataFilePath()))).To(BeTrue())
|
||||
|
||||
img, err := b.ImageReference(fmt.Sprintf("%s:%s", imageName, artifacts[0].Runtime.ImageID()), true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, path, err := image.Extract(ctx, img, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(path) // clean up
|
||||
|
||||
Expect(fileHelper.Exists(filepath.Join(path, "bin/busybox"))).To(BeTrue())
|
||||
|
||||
img, err = b.ImageReference(fmt.Sprintf("%s:%s", imageName, artifacts[1].Runtime.GetMetadataFilePath()), true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, path, err = image.Extract(ctx, img, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(path) // clean up
|
||||
|
||||
meta := filepath.Join(path, artifacts[1].Runtime.GetMetadataFilePath())
|
||||
Expect(fileHelper.Exists(meta)).To(BeTrue())
|
||||
|
||||
d, err := ioutil.ReadFile(meta)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(string(d)).To(ContainSubstring(artifacts[1].CompileSpec.GetPackage().GetName()))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Packages which conents are a package folder", func() {
|
||||
@@ -917,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())
|
||||
@@ -952,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())
|
||||
@@ -971,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())
|
||||
@@ -998,5 +1064,41 @@ var _ = Describe("Compiler", func() {
|
||||
files := art.Files
|
||||
Expect(files).To(ContainElement("bin/busybox"))
|
||||
})
|
||||
|
||||
It("is not generated after the compilation process and annotated in the metadata if a package is hidden", func() {
|
||||
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||
|
||||
err := generalRecipe.Load("../../tests/fixtures/packagelayers_hidden")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(2))
|
||||
|
||||
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())
|
||||
compiler.Options.CompressionType = compression.GZip
|
||||
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "tree")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer os.RemoveAll(tmpdir) // clean up
|
||||
|
||||
spec.SetOutputPath(tmpdir)
|
||||
|
||||
artifacts, errs := compiler.CompileParallel(false, compilerspec.NewLuetCompilationspecs(spec))
|
||||
Expect(errs).To(BeNil())
|
||||
Expect(len(artifacts)).To(Equal(1))
|
||||
Expect(len(artifacts[0].Dependencies)).To(Equal(1))
|
||||
Expect(artifacts[0].Files).ToNot(ContainElement("bin/busybox"))
|
||||
|
||||
Expect(fileHelper.Exists(spec.Rel("runtime-layer-0.1.metadata.yaml"))).To(BeTrue())
|
||||
|
||||
art, err := LoadArtifactFromYaml(spec)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
files := art.Files
|
||||
Expect(files).ToNot(ContainElement("bin/busybox"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@@ -16,18 +16,18 @@
|
||||
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"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/luet/pkg/tree"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
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())
|
||||
|
@@ -47,7 +47,13 @@ type Compiler struct {
|
||||
// TemplatesFolder. should default to tree/templates
|
||||
TemplatesFolder []string
|
||||
|
||||
Context *types.Context
|
||||
// Tells wether to push final container images after building
|
||||
PushFinalImages bool
|
||||
PushFinalImagesForce bool
|
||||
// Image repository to push to
|
||||
PushFinalImagesRepository string
|
||||
|
||||
Context types.Context
|
||||
}
|
||||
|
||||
func NewDefaultCompiler() *Compiler {
|
||||
@@ -85,6 +91,25 @@ func WithOptions(opt *Compiler) func(cfg *Compiler) error {
|
||||
}
|
||||
}
|
||||
|
||||
// WithFinalRepository Sets the final repository where to push
|
||||
// images of built artifacts
|
||||
func WithFinalRepository(r string) func(cfg *Compiler) error {
|
||||
return func(cfg *Compiler) error {
|
||||
cfg.PushFinalImagesRepository = r
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func EnablePushFinalImages(cfg *Compiler) error {
|
||||
cfg.PushFinalImages = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func ForcePushFinalImages(cfg *Compiler) error {
|
||||
cfg.PushFinalImagesForce = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithBackendType(r string) func(cfg *Compiler) error {
|
||||
return func(cfg *Compiler) error {
|
||||
cfg.BackendType = r
|
||||
@@ -113,6 +138,8 @@ func WithPullRepositories(r []string) func(cfg *Compiler) error {
|
||||
}
|
||||
}
|
||||
|
||||
// WithPushRepository Sets the image reference where to push
|
||||
// cache images
|
||||
func WithPushRepository(r string) func(cfg *Compiler) error {
|
||||
return func(cfg *Compiler) error {
|
||||
if len(cfg.PullImageRepository) == 0 {
|
||||
@@ -210,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
|
||||
|
@@ -18,7 +18,7 @@ package compilerspec_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -27,7 +27,7 @@ import (
|
||||
. "github.com/mudler/luet/pkg/compiler"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/luet/pkg/tree"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -33,6 +33,7 @@ import (
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/daemon"
|
||||
"github.com/mudler/luet/pkg/api/core/bus"
|
||||
"github.com/opencontainers/go-digest"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
@@ -127,7 +128,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 {
|
||||
@@ -174,7 +175,6 @@ func DownloadAndExtractDockerImage(ctx *luettypes.Context, image, dest string, a
|
||||
ctx,
|
||||
img,
|
||||
dest,
|
||||
true,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -193,3 +193,60 @@ func DownloadAndExtractDockerImage(ctx *luettypes.Context, image, dest string, a
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ExtractDockerImage(ctx luettypes.Context, local, dest string)(*images.Image, error) {
|
||||
if !fileHelper.Exists(dest) {
|
||||
if err := os.MkdirAll(dest, os.ModePerm); err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot create destination directory")
|
||||
}
|
||||
}
|
||||
|
||||
ref, err := name.ParseReference(local)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img, err := daemon.Image(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m, err := img.Manifest()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mt, err := img.MediaType()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d, err := img.Digest()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var c int64
|
||||
c, _, err = luetimages.ExtractTo(
|
||||
ctx,
|
||||
img,
|
||||
dest,
|
||||
nil,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bus.Manager.Publish(bus.EventImagePostUnPack, UnpackEventData{Image: local, Dest: dest})
|
||||
|
||||
return &images.Image{
|
||||
Name: local,
|
||||
Labels: m.Annotations,
|
||||
Target: specs.Descriptor{
|
||||
MediaType: string(mt),
|
||||
Digest: digest.Digest(d.String()),
|
||||
Size: c,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
fileHelper "github.com/mudler/luet/pkg/helpers/file"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -21,7 +21,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/mudler/luet/pkg/helpers"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -18,7 +18,7 @@ package helpers_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -18,7 +18,7 @@ package helpers_test
|
||||
|
||||
import (
|
||||
. "github.com/mudler/luet/pkg/helpers"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -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
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
// +build js nacl plan9
|
||||
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
func IsTerminal(w io.Writer) bool {
|
||||
return false
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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
|
||||
}
|
@@ -88,7 +88,7 @@ func printMatches(artefacts map[string]ArtifactMatch) {
|
||||
for _, m := range artefacts {
|
||||
d = append(d, []string{
|
||||
fmt.Sprintf("%s/%s", m.Package.GetCategory(), m.Package.GetName()),
|
||||
pterm.LightGreen(m.Package.GetVersion()), m.Package.GetLicense(), m.Repository.Name})
|
||||
pterm.LightGreen(m.Package.GetVersion()), m.Package.GetLicense(), m.Repository.GetName()})
|
||||
}
|
||||
pterm.DefaultTable.WithHasHeader().WithData(d).Render()
|
||||
fmt.Println()
|
||||
|
@@ -18,7 +18,7 @@ package client_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
|
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -64,11 +64,13 @@ func (c *DockerClient) DownloadArtifact(a *artifact.PackageArtifact) (*artifact.
|
||||
c.context.Spinner()
|
||||
defer c.context.SpinnerStop()
|
||||
|
||||
resultingArtifact := a.ShallowCopy()
|
||||
artifactName := path.Base(a.Path)
|
||||
|
||||
downloaded := false
|
||||
|
||||
resultingArtifact, err := c.CacheGet(a)
|
||||
if err == nil {
|
||||
return resultingArtifact, nil
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// Files are in URI/packagename:version (GetPackageImageName() method)
|
||||
// use downloadAndExtract .. and egenrate an archive to consume. Checksum should be already checked while downloading the image
|
||||
@@ -79,71 +81,57 @@ 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{}
|
||||
|
||||
// Check if file is already in cache
|
||||
fileName, err := c.Cache.Get(resultingArtifact)
|
||||
// Check if file is already in cache
|
||||
if err == nil {
|
||||
resultingArtifact = a
|
||||
resultingArtifact.Path = fileName
|
||||
resultingArtifact.Checksums = artifact.Checksums{}
|
||||
c.context.Debug("Use artifact", artifactName, "from cache.")
|
||||
} else {
|
||||
temp, err := c.context.TempDir("image")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(temp)
|
||||
|
||||
temp, err := c.context.Config.GetSystem().TempDir("image")
|
||||
tempArtifact, err := c.context.TempFile("artifact")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(tempArtifact.Name())
|
||||
for _, uri := range c.RepoData.Urls {
|
||||
|
||||
imageName := fmt.Sprintf("%s:%s", uri, a.CompileSpec.GetPackage().ImageID())
|
||||
c.context.Info("Downloading image", imageName)
|
||||
|
||||
// imageName := fmt.Sprintf("%s/%s", uri, artifact.GetCompileSpec().GetPackage().GetPackageImageName())
|
||||
info, err := docker.DownloadAndExtractDockerImage(c.context, imageName, temp, c.auth, c.RepoData.Verify)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
c.context.Warning(fmt.Sprintf(errImageDownloadMsg, imageName, err.Error()))
|
||||
continue
|
||||
}
|
||||
defer os.RemoveAll(temp)
|
||||
|
||||
tempArtifact, err := c.context.Config.GetSystem().TempFile("artifact")
|
||||
c.context.Info(
|
||||
fmt.Sprintf("Image: %s. Pulled: %s. Size: %s",
|
||||
imageName,
|
||||
info.Target.Digest,
|
||||
units.BytesSize(float64(info.Target.Size)),
|
||||
),
|
||||
)
|
||||
c.context.Debug("\nCompressing result ", filepath.Join(temp), "to", tempArtifact.Name())
|
||||
|
||||
resultingArtifact.Path = tempArtifact.Name() // First set to cache file
|
||||
err = resultingArtifact.Compress(temp, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(tempArtifact.Name())
|
||||
for _, uri := range c.RepoData.Urls {
|
||||
|
||||
imageName := fmt.Sprintf("%s:%s", uri, a.CompileSpec.GetPackage().ImageID())
|
||||
c.context.Info("Downloading image", imageName)
|
||||
|
||||
// imageName := fmt.Sprintf("%s/%s", uri, artifact.GetCompileSpec().GetPackage().GetPackageImageName())
|
||||
info, err := docker.DownloadAndExtractDockerImage(c.context, imageName, temp, c.auth, c.RepoData.Verify)
|
||||
if err != nil {
|
||||
c.context.Warning(fmt.Sprintf(errImageDownloadMsg, imageName, err.Error()))
|
||||
continue
|
||||
}
|
||||
|
||||
c.context.Info(fmt.Sprintf("Pulled: %s", info.Target.Digest))
|
||||
c.context.Info(fmt.Sprintf("Size: %s", units.BytesSize(float64(info.Target.Size))))
|
||||
c.context.Debug("\nCompressing result ", filepath.Join(temp), "to", tempArtifact.Name())
|
||||
|
||||
resultingArtifact.Path = tempArtifact.Name() // First set to cache file
|
||||
err = resultingArtifact.Compress(temp, 1)
|
||||
if err != nil {
|
||||
c.context.Error(fmt.Sprintf("Failed compressing package %s: %s", imageName, err.Error()))
|
||||
continue
|
||||
}
|
||||
|
||||
_, _, err = c.Cache.Put(resultingArtifact)
|
||||
if err != nil {
|
||||
c.context.Error(fmt.Sprintf("Failed storing package %s from cache: %s", imageName, err.Error()))
|
||||
continue
|
||||
}
|
||||
|
||||
fileName, err := c.Cache.Get(resultingArtifact)
|
||||
if err != nil {
|
||||
c.context.Error(fmt.Sprintf("Failed getting package %s from cache: %s", imageName, err.Error()))
|
||||
continue
|
||||
}
|
||||
|
||||
resultingArtifact.Path = fileName // Cache is persistent. tempArtifact is not
|
||||
|
||||
downloaded = true
|
||||
break
|
||||
c.context.Error(fmt.Sprintf("Failed compressing package %s: %s", imageName, err.Error()))
|
||||
continue
|
||||
}
|
||||
|
||||
if !downloaded {
|
||||
return nil, errors.Wrap(err, "no image available from repositories")
|
||||
_, _, err = c.Cache.Put(resultingArtifact)
|
||||
if err != nil {
|
||||
c.context.Error(fmt.Sprintf("Failed storing package %s from cache: %s", imageName, err.Error()))
|
||||
continue
|
||||
}
|
||||
downloaded = true
|
||||
|
||||
return c.CacheGet(resultingArtifact)
|
||||
}
|
||||
|
||||
if !downloaded {
|
||||
return nil, errors.Wrap(err, "no image available from repositories")
|
||||
}
|
||||
|
||||
return resultingArtifact, nil
|
||||
@@ -156,13 +144,13 @@ func (c *DockerClient) DownloadFile(name string) (string, error) {
|
||||
// Files should be in URI/repository:<file>
|
||||
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
|
||||
}
|
||||
@@ -194,3 +182,29 @@ func (c *DockerClient) DownloadFile(name string) (string, error) {
|
||||
|
||||
return file.Name(), err
|
||||
}
|
||||
|
||||
func (c *DockerClient) CacheGet(a *artifact.PackageArtifact) (*artifact.PackageArtifact, error) {
|
||||
resultingArtifact := a.ShallowCopy()
|
||||
// TODO:
|
||||
// Files are in URI/packagename:version (GetPackageImageName() method)
|
||||
// use downloadAndExtract .. and egenrate an archive to consume. Checksum should be already checked while downloading the image
|
||||
// with the above functions, because Docker images already contain such metadata
|
||||
// - Check how verification is done when calling DownloadArtifact outside, similarly we need to check DownloadFile, and how verification
|
||||
// is done in such cases (see repository.go)
|
||||
|
||||
// We discard checksum, that are checked while during pull and unpack by containerd
|
||||
resultingArtifact.Checksums = artifact.Checksums{}
|
||||
|
||||
// Check if file is already in cache
|
||||
fileName, err := c.Cache.Get(resultingArtifact)
|
||||
// Check if file is already in cache
|
||||
if err == nil {
|
||||
artifactName := path.Base(a.Path)
|
||||
c.context.Debug("Use artifact", artifactName, "from cache.")
|
||||
resultingArtifact = a
|
||||
resultingArtifact.Path = fileName
|
||||
resultingArtifact.Checksums = artifact.Checksums{}
|
||||
}
|
||||
|
||||
return resultingArtifact, err
|
||||
}
|
||||
|
@@ -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"
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
|
||||
. "github.com/mudler/luet/pkg/installer/client"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user