Compare commits

...

7 Commits

Author SHA1 Message Date
Ettore Di Giacinto
719ef16161 🆕 Tag 0.22.2 2021-12-28 16:01:35 +01:00
Ettore Di Giacinto
1a9073a97a 🎨 Display installed packages in luet search
Fixes #236
2021-12-28 15:04:00 +01:00
Ettore Di Giacinto
7e825400e2 🔧 Use crane.Insecure while checking image availability
As those checks are not consuming any digest, we just use them to assess
if we need to build or not certain packages. The backend will refuse the
image if not configured appropriately
2021-12-28 14:54:11 +01:00
Ettore Di Giacinto
39e62f3321 🆕 Tag 0.22.1 2021-12-28 14:36:44 +01:00
Ettore Di Giacinto
9dcaeb0870 🔧 Defer write repository synctime 2021-12-28 12:06:09 +01:00
Ettore Di Giacinto
c4affb0f0e 🔧 Fixup live-output CLI parameter 2021-12-27 23:11:16 +01:00
Ludea
4c1b9b92af Unpack local image (#277)
* [WIP] Unpack local docker images

* unpack local image

* PR feedback + missing new function call

Co-authored-by: Ettore Di Giacinto <mudler@users.noreply.github.com>
2021-12-26 20:06:15 +01:00
9 changed files with 139 additions and 34 deletions

View File

@@ -86,7 +86,6 @@ Build packages specifying multiple definition trees:
viper.BindPFlag("wait", cmd.Flags().Lookup("wait"))
viper.BindPFlag("keep-images", cmd.Flags().Lookup("keep-images"))
viper.BindPFlag("general.show_build_output", cmd.Flags().Lookup("live-output"))
viper.BindPFlag("backend-args", cmd.Flags().Lookup("backend-args"))
},
@@ -334,7 +333,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", true, "Enable live output of the build phase.")
buildCmd.Flags().Bool("from-repositories", false, "Consume the user-defined repositories to pull specfiles from")
buildCmd.Flags().Bool("rebuild", false, "To combine with --pull. Allows to rebuild the target package even if an image is available, against a local values file")
buildCmd.Flags().Bool("pretend", false, "Just print what packages will be compiled")

View File

@@ -30,7 +30,7 @@ var cfgFile string
var Verbose bool
const (
LuetCLIVersion = "0.22.0"
LuetCLIVersion = "0.22.2"
LuetEnvPrefix = "LUET"
)

View File

@@ -35,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 {
@@ -45,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),
@@ -80,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.System.Rootfs}
system := sys()
var err error
iMatches := pkg.Packages{}
@@ -104,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{
@@ -116,6 +136,7 @@ func searchLocally(term string, l *util.ListWriter, t *util.TableWriter, label,
Repository: "system",
Hidden: pack.IsHidden(),
Files: f,
Installed: true,
})
}
} else {
@@ -123,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{
@@ -134,6 +156,7 @@ func searchLocally(term string, l *util.ListWriter, t *util.TableWriter, label,
Repository: "system",
Hidden: revdep.IsHidden(),
Files: f,
Installed: i,
})
}
}
@@ -172,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
@@ -190,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(),
@@ -215,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{
@@ -226,6 +254,7 @@ func searchLocalFiles(term string, l *util.ListWriter, t *util.TableWriter) Resu
Repository: "system",
Hidden: pack.IsHidden(),
Files: f,
Installed: i,
})
}
@@ -255,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(),
@@ -265,6 +295,7 @@ 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

View File

@@ -89,7 +89,7 @@ func NewUnpackCommand() *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) {
@@ -107,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")
@@ -126,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))))
},
}
@@ -143,6 +152,7 @@ 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
}

View File

@@ -220,7 +220,7 @@ func setDefaults(viper *viper.Viper) {
viper.SetDefault("general.concurrency", runtime.NumCPU())
viper.SetDefault("general.debug", false)
viper.SetDefault("general.quiet", false)
viper.SetDefault("general.show_build_output", false)
viper.SetDefault("general.show_build_output", true)
viper.SetDefault("general.fatal_warnings", false)
viper.SetDefault("general.http_timeout", 360)
@@ -278,6 +278,7 @@ func InitViper(RootCmd *cobra.Command) {
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")
@@ -303,6 +304,7 @@ func InitViper(RootCmd *cobra.Command) {
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"))

View File

@@ -36,7 +36,7 @@ func TreePackages(treedir string) (searchResult SearchResult, err error) {
}
func imageAvailable(image string) bool {
_, err := crane.Digest(image)
_, err := crane.Digest(image, crane.Insecure)
return err == nil
}

View File

@@ -29,7 +29,9 @@ const (
)
func imageAvailable(image string) bool {
_, err := crane.Digest(image)
// 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
_, err := crane.Digest(image, crane.Insecure)
return err == nil
}

View File

@@ -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"
@@ -192,3 +193,60 @@ func DownloadAndExtractDockerImage(ctx luettypes.Context, image, dest string, au
},
}, 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
}

View File

@@ -866,6 +866,8 @@ func (r *LuetSystemRepository) Sync(ctx types.Context, force bool) (*LuetSystemR
toTimeSync = true
ctx.Debug(r.Name, "is old, refresh is suggested")
}
} else {
toTimeSync = true
}
ctx.Debug("Sync of the repository", r.Name, "in progress...")
@@ -893,6 +895,10 @@ func (r *LuetSystemRepository) Sync(ctx types.Context, force bool) (*LuetSystemR
return nil, err
}
defer os.RemoveAll(file)
defer func() {
now := time.Now().Format(time.RFC3339)
ioutil.WriteFile(filepath.Join(repobasedir, "SYNCTIME"), []byte(now), os.ModePerm)
}()
} else {
downloadedRepoMeta, err = r.ReadSpecFile(repoFile)
if err != nil {
@@ -990,8 +996,6 @@ func (r *LuetSystemRepository) Sync(ctx types.Context, force bool) (*LuetSystemR
downloadedRepoMeta.GetRevision(),
time.Unix(tsec, 0).String()))
now := time.Now().Format(time.RFC3339)
ioutil.WriteFile(filepath.Join(repobasedir, "SYNCTIME"), []byte(now), os.ModePerm)
}
meta, err := NewLuetSystemRepositoryMetadata(