mirror of
https://github.com/mudler/luet.git
synced 2025-09-05 17:20:29 +00:00
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4d60795fdc | ||
|
6b45b1d61c | ||
|
5eb5a42bf7 | ||
|
0bacdc75f2 | ||
|
917d0935ad |
@@ -30,7 +30,7 @@ var cfgFile string
|
|||||||
var Verbose bool
|
var Verbose bool
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LuetCLIVersion = "0.19.0"
|
LuetCLIVersion = "0.19.1"
|
||||||
LuetEnvPrefix = "LUET"
|
LuetEnvPrefix = "LUET"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -28,9 +28,11 @@ import (
|
|||||||
|
|
||||||
"github.com/kyokomi/emoji"
|
"github.com/kyokomi/emoji"
|
||||||
"github.com/mudler/luet/pkg/helpers/terminal"
|
"github.com/mudler/luet/pkg/helpers/terminal"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/pterm/pterm"
|
"github.com/pterm/pterm"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
|
"golang.org/x/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -48,13 +50,16 @@ type Context struct {
|
|||||||
NoSpinner bool
|
NoSpinner bool
|
||||||
|
|
||||||
s *pterm.SpinnerPrinter
|
s *pterm.SpinnerPrinter
|
||||||
spinnerLock sync.Mutex
|
spinnerLock *sync.Mutex
|
||||||
z *zap.Logger
|
z *zap.Logger
|
||||||
|
AreaPrinter *pterm.AreaPrinter
|
||||||
|
ProgressBar *pterm.ProgressbarPrinter
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContext() *Context {
|
func NewContext() *Context {
|
||||||
return &Context{
|
return &Context{
|
||||||
IsTerminal: terminal.IsTerminal(os.Stdout),
|
spinnerLock: &sync.Mutex{},
|
||||||
|
IsTerminal: terminal.IsTerminal(os.Stdout),
|
||||||
Config: &LuetConfig{
|
Config: &LuetConfig{
|
||||||
ConfigFromHost: true,
|
ConfigFromHost: true,
|
||||||
Logging: LuetLoggingConfig{},
|
Logging: LuetLoggingConfig{},
|
||||||
@@ -68,6 +73,35 @@ func NewContext() *Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
func (c *Context) Init() (err error) {
|
||||||
if c.IsTerminal {
|
if c.IsTerminal {
|
||||||
if !c.Config.Logging.Color {
|
if !c.Config.Logging.Color {
|
||||||
|
@@ -37,6 +37,8 @@ type LuetRepository struct {
|
|||||||
Verify bool `json:"verify,omitempty" yaml:"verify,omitempty" mapstructure:"verify"`
|
Verify bool `json:"verify,omitempty" yaml:"verify,omitempty" mapstructure:"verify"`
|
||||||
Arch string `json:"arch,omitempty" yaml:"arch,omitempty" mapstructure:"arch"`
|
Arch string `json:"arch,omitempty" yaml:"arch,omitempty" mapstructure:"arch"`
|
||||||
|
|
||||||
|
ReferenceID string `json:"reference,omitempty" yaml:"reference,omitempty" mapstructure:"reference"`
|
||||||
|
|
||||||
// Incremented value that identify revision of the repository in a user-friendly way.
|
// Incremented value that identify revision of the repository in a user-friendly way.
|
||||||
Revision int `json:"revision,omitempty" yaml:"-" mapstructure:"-"`
|
Revision int `json:"revision,omitempty" yaml:"-" mapstructure:"-"`
|
||||||
// Epoch time in seconds
|
// Epoch time in seconds
|
||||||
|
@@ -56,7 +56,7 @@ func (s *SimpleDocker) BuildImage(opts Options) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.ctx.Info(":whale: Building image " + name + " done")
|
s.ctx.Success(":whale: Building image " + name + " done")
|
||||||
|
|
||||||
bus.Manager.Publish(bus.EventImagePostBuild, opts)
|
bus.Manager.Publish(bus.EventImagePostBuild, opts)
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ func (s *SimpleDocker) CopyImage(src, dst string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed tagging image: "+string(out))
|
return errors.Wrap(err, "Failed tagging image: "+string(out))
|
||||||
}
|
}
|
||||||
s.ctx.Info(":whale: Tagged image:", src, "->", dst)
|
s.ctx.Success(":whale: Tagged image:", src, "->", dst)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ func (s *SimpleDocker) DownloadImage(opts Options) error {
|
|||||||
return errors.Wrap(err, "Failed pulling image: "+string(out))
|
return errors.Wrap(err, "Failed pulling image: "+string(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
s.ctx.Info(":whale: Downloaded image:", name)
|
s.ctx.Success(":whale: Downloaded image:", name)
|
||||||
bus.Manager.Publish(bus.EventImagePostPull, opts)
|
bus.Manager.Publish(bus.EventImagePostPull, opts)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -120,7 +120,7 @@ func (s *SimpleDocker) RemoveImage(opts Options) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed removing image: "+string(out))
|
return errors.Wrap(err, "Failed removing image: "+string(out))
|
||||||
}
|
}
|
||||||
s.ctx.Info(":whale: Removed image:", name)
|
s.ctx.Success(":whale: Removed image:", name)
|
||||||
//Info(string(out))
|
//Info(string(out))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ func (s *SimpleDocker) Push(opts Options) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed pushing image: "+string(out))
|
return errors.Wrap(err, "Failed pushing image: "+string(out))
|
||||||
}
|
}
|
||||||
s.ctx.Info(":whale: Pushed image:", name)
|
s.ctx.Success(":whale: Pushed image:", name)
|
||||||
bus.Manager.Publish(bus.EventImagePostPush, opts)
|
bus.Manager.Publish(bus.EventImagePostPush, opts)
|
||||||
|
|
||||||
//Info(string(out))
|
//Info(string(out))
|
||||||
|
@@ -447,7 +447,7 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return a, errors.Wrap(err, "Failed while writing metadata file")
|
return a, errors.Wrap(err, "Failed while writing metadata file")
|
||||||
}
|
}
|
||||||
cs.Options.Context.Info(pkgTag, " :white_check_mark: done (empty virtual package)")
|
cs.Options.Context.Success(pkgTag, " :white_check_mark: done (empty virtual package)")
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,7 +477,7 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return a, errors.Wrap(err, "Failed while writing metadata file")
|
return a, errors.Wrap(err, "Failed while writing metadata file")
|
||||||
}
|
}
|
||||||
cs.Options.Context.Info(pkgTag, " :white_check_mark: Done")
|
cs.Options.Context.Success(pkgTag, " :white_check_mark: Done")
|
||||||
|
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
@@ -965,7 +965,7 @@ func (cs *LuetCompiler) resolveMultiStageImages(concurrency int, keepPermissions
|
|||||||
Source: c.Source,
|
Source: c.Source,
|
||||||
Destination: c.Destination,
|
Destination: c.Destination,
|
||||||
})
|
})
|
||||||
cs.Options.Context.Info(copyTag2, ":white_check_mark: Done")
|
cs.Options.Context.Success(copyTag2, ":white_check_mark: Done")
|
||||||
} else {
|
} else {
|
||||||
resolvedCopyFields = append(resolvedCopyFields, c)
|
resolvedCopyFields = append(resolvedCopyFields, c)
|
||||||
}
|
}
|
||||||
@@ -1128,7 +1128,7 @@ func (cs *LuetCompiler) compile(concurrency int, keepPermissions bool, generateF
|
|||||||
|
|
||||||
a.PackageCacheImage = assertion.Hash.PackageHash
|
a.PackageCacheImage = assertion.Hash.PackageHash
|
||||||
|
|
||||||
cs.Options.Context.Info(pkgTag, ":white_check_mark: Done")
|
cs.Options.Context.Success(pkgTag, ":white_check_mark: Done")
|
||||||
|
|
||||||
bus.Manager.Publish(bus.EventPackagePostBuild, struct {
|
bus.Manager.Publish(bus.EventPackagePostBuild, struct {
|
||||||
CompileSpec *compilerspec.LuetCompilationSpec
|
CompileSpec *compilerspec.LuetCompilationSpec
|
||||||
|
@@ -38,8 +38,6 @@ type HttpClient struct {
|
|||||||
RepoData RepoData
|
RepoData RepoData
|
||||||
Cache *artifact.ArtifactCache
|
Cache *artifact.ArtifactCache
|
||||||
context *types.Context
|
context *types.Context
|
||||||
|
|
||||||
ProgressBarArea *pterm.AreaPrinter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHttpClient(r RepoData, ctx *types.Context) *HttpClient {
|
func NewHttpClient(r RepoData, ctx *types.Context) *HttpClient {
|
||||||
@@ -126,11 +124,16 @@ func (c *HttpClient) DownloadFile(p string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resp := client.Do(req)
|
resp := client.Do(req)
|
||||||
pb := pterm.DefaultProgressbar.WithTotal(int(resp.Size()))
|
|
||||||
if c.ProgressBarArea != nil {
|
// Initialize a progressbar only if we have one in the current context
|
||||||
pb = pb.WithPrintTogether(c.ProgressBarArea)
|
var pb *pterm.ProgressbarPrinter
|
||||||
|
if c.context.ProgressBar != nil {
|
||||||
|
pb = pterm.DefaultProgressbar.WithTotal(int(resp.Size()))
|
||||||
|
if c.context.AreaPrinter != nil {
|
||||||
|
pb = pb.WithPrintTogether(c.context.AreaPrinter)
|
||||||
|
}
|
||||||
|
pb, _ = pb.WithTitle(filepath.Base(resp.Request.HTTPRequest.URL.RequestURI())).Start()
|
||||||
}
|
}
|
||||||
pb, _ = pb.WithTitle(filepath.Base(resp.Request.HTTPRequest.URL.RequestURI())).Start()
|
|
||||||
// start download loop
|
// start download loop
|
||||||
t := time.NewTicker(500 * time.Millisecond)
|
t := time.NewTicker(500 * time.Millisecond)
|
||||||
defer t.Stop()
|
defer t.Stop()
|
||||||
@@ -140,11 +143,15 @@ func (c *HttpClient) DownloadFile(p string) (string, error) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.C:
|
case <-t.C:
|
||||||
// bar.Set64(resp.BytesComplete())
|
// update the progress bar
|
||||||
//pb.Increment()
|
if pb != nil {
|
||||||
pb.Increment().Current = int(resp.BytesComplete())
|
pb.Increment().Current = int(resp.BytesComplete())
|
||||||
|
}
|
||||||
case <-resp.Done:
|
case <-resp.Done:
|
||||||
pb.Increment().Current = int(resp.BytesComplete())
|
// update the progress bar
|
||||||
|
if pb != nil {
|
||||||
|
pb.Increment().Current = int(resp.BytesComplete())
|
||||||
|
}
|
||||||
// download is complete
|
// download is complete
|
||||||
break download_loop
|
break download_loop
|
||||||
}
|
}
|
||||||
@@ -157,7 +164,11 @@ func (c *HttpClient) DownloadFile(p string) (string, error) {
|
|||||||
c.context.Info("Downloaded", p, "of",
|
c.context.Info("Downloaded", p, "of",
|
||||||
fmt.Sprintf("%.2f", (float64(resp.BytesComplete())/1000)/1000), "MB (",
|
fmt.Sprintf("%.2f", (float64(resp.BytesComplete())/1000)/1000), "MB (",
|
||||||
fmt.Sprintf("%.2f", (float64(resp.BytesPerSecond())/1024)/1024), "MiB/s )")
|
fmt.Sprintf("%.2f", (float64(resp.BytesPerSecond())/1024)/1024), "MiB/s )")
|
||||||
pb.Stop()
|
|
||||||
|
if pb != nil {
|
||||||
|
// stop the progressbar if active
|
||||||
|
pb.Stop()
|
||||||
|
}
|
||||||
//bar.Finish()
|
//bar.Finish()
|
||||||
downloaded = true
|
downloaded = true
|
||||||
break
|
break
|
||||||
|
@@ -32,7 +32,6 @@ import (
|
|||||||
"github.com/mudler/luet/pkg/helpers"
|
"github.com/mudler/luet/pkg/helpers"
|
||||||
fileHelper "github.com/mudler/luet/pkg/helpers/file"
|
fileHelper "github.com/mudler/luet/pkg/helpers/file"
|
||||||
"github.com/mudler/luet/pkg/helpers/match"
|
"github.com/mudler/luet/pkg/helpers/match"
|
||||||
"github.com/mudler/luet/pkg/installer/client"
|
|
||||||
pkg "github.com/mudler/luet/pkg/package"
|
pkg "github.com/mudler/luet/pkg/package"
|
||||||
"github.com/mudler/luet/pkg/solver"
|
"github.com/mudler/luet/pkg/solver"
|
||||||
"github.com/pterm/pterm"
|
"github.com/pterm/pterm"
|
||||||
@@ -566,21 +565,30 @@ func (l *LuetInstaller) download(syncedRepos Repositories, toDownload map[string
|
|||||||
|
|
||||||
var wg = new(sync.WaitGroup)
|
var wg = new(sync.WaitGroup)
|
||||||
|
|
||||||
area, _ := pterm.DefaultArea.Start()
|
ctx := l.Options.Context.Copy()
|
||||||
|
|
||||||
p, _ := pterm.DefaultProgressbar.WithPrintTogether(area).WithTotal(len(toDownload)).WithTitle("Downloading packages").Start()
|
// Check if the terminal is big enough to display a progress bar
|
||||||
|
// https://github.com/pterm/pterm/blob/4c725e56bfd9eb38e1c7b9dec187b50b93baa8bd/progressbar_printer.go#L190
|
||||||
|
w, _, err := ctx.GetTerminalSize()
|
||||||
|
if ctx.IsTerminal && err == nil && w > 100 {
|
||||||
|
area, _ := pterm.DefaultArea.Start()
|
||||||
|
p, _ := pterm.DefaultProgressbar.WithPrintTogether(area).WithTotal(len(toDownload)).WithTitle("Downloading packages").Start()
|
||||||
|
|
||||||
|
ctx.AreaPrinter = area
|
||||||
|
ctx.ProgressBar = p
|
||||||
|
defer area.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
// Download
|
// Download
|
||||||
for i := 0; i < l.Options.Concurrency; i++ {
|
for i := 0; i < l.Options.Concurrency; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go l.downloadWorker(i, wg, all, p, area)
|
go l.downloadWorker(i, wg, all, ctx)
|
||||||
}
|
}
|
||||||
for _, c := range toDownload {
|
for _, c := range toDownload {
|
||||||
all <- c
|
all <- c
|
||||||
}
|
}
|
||||||
close(all)
|
close(all)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
area.Stop()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -772,7 +780,7 @@ func (l *LuetInstaller) checkFileconflicts(toInstall map[string]ArtifactMatch, c
|
|||||||
|
|
||||||
filesToInstall := []string{}
|
filesToInstall := []string{}
|
||||||
for _, m := range toInstall {
|
for _, m := range toInstall {
|
||||||
a, err := l.downloadPackage(m, nil)
|
a, err := l.downloadPackage(m, l.Options.Context)
|
||||||
if err != nil && !l.Options.Force {
|
if err != nil && !l.Options.Force {
|
||||||
return errors.Wrap(err, "Failed downloading package")
|
return errors.Wrap(err, "Failed downloading package")
|
||||||
}
|
}
|
||||||
@@ -867,14 +875,9 @@ func (l *LuetInstaller) install(o Option, syncedRepos Repositories, toInstall ma
|
|||||||
return s.ExecuteFinalizers(l.Options.Context, toFinalize)
|
return s.ExecuteFinalizers(l.Options.Context, toFinalize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LuetInstaller) downloadPackage(a ArtifactMatch, area *pterm.AreaPrinter) (*artifact.PackageArtifact, error) {
|
func (l *LuetInstaller) downloadPackage(a ArtifactMatch, ctx *types.Context) (*artifact.PackageArtifact, error) {
|
||||||
|
|
||||||
cli := a.Repository.Client(l.Options.Context)
|
cli := a.Repository.Client(ctx)
|
||||||
|
|
||||||
switch v := cli.(type) {
|
|
||||||
case *client.HttpClient:
|
|
||||||
v.ProgressBarArea = area
|
|
||||||
}
|
|
||||||
|
|
||||||
artifact, err := cli.DownloadArtifact(a.Artifact)
|
artifact, err := cli.DownloadArtifact(a.Artifact)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -890,7 +893,7 @@ func (l *LuetInstaller) downloadPackage(a ArtifactMatch, area *pterm.AreaPrinter
|
|||||||
|
|
||||||
func (l *LuetInstaller) installPackage(m ArtifactMatch, s *System) error {
|
func (l *LuetInstaller) installPackage(m ArtifactMatch, s *System) error {
|
||||||
|
|
||||||
a, err := l.downloadPackage(m, nil)
|
a, err := l.downloadPackage(m, l.Options.Context)
|
||||||
if err != nil && !l.Options.Force {
|
if err != nil && !l.Options.Force {
|
||||||
return errors.Wrap(err, "Failed downloading package")
|
return errors.Wrap(err, "Failed downloading package")
|
||||||
}
|
}
|
||||||
@@ -910,20 +913,21 @@ func (l *LuetInstaller) installPackage(m ArtifactMatch, s *System) error {
|
|||||||
return s.Database.SetPackageFiles(&pkg.PackageFile{PackageFingerprint: m.Package.GetFingerPrint(), Files: files})
|
return s.Database.SetPackageFiles(&pkg.PackageFile{PackageFingerprint: m.Package.GetFingerPrint(), Files: files})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LuetInstaller) downloadWorker(i int, wg *sync.WaitGroup, c <-chan ArtifactMatch, pb *pterm.ProgressbarPrinter, area *pterm.AreaPrinter) error {
|
func (l *LuetInstaller) downloadWorker(i int, wg *sync.WaitGroup, c <-chan ArtifactMatch, ctx *types.Context) error {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
for p := range c {
|
for p := range c {
|
||||||
// TODO: Keep trace of what was added from the tar, and save it into system
|
// TODO: Keep trace of what was added from the tar, and save it into system
|
||||||
_, err := l.downloadPackage(p, area)
|
_, err := l.downloadPackage(p, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Options.Context.Error("Failed downloading package "+p.Package.GetName(), err.Error())
|
l.Options.Context.Error("Failed downloading package "+p.Package.GetName(), err.Error())
|
||||||
return errors.Wrap(err, "Failed downloading package "+p.Package.GetName())
|
return errors.Wrap(err, "Failed downloading package "+p.Package.GetName())
|
||||||
} else {
|
} else {
|
||||||
l.Options.Context.Success(":package: Package ", p.Package.HumanReadableString(), "downloaded")
|
l.Options.Context.Success(":package: Package ", p.Package.HumanReadableString(), "downloaded")
|
||||||
}
|
}
|
||||||
pb.Increment()
|
if ctx.ProgressBar != nil {
|
||||||
|
ctx.ProgressBar.Increment()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@@ -539,6 +539,7 @@ func (r *LuetSystemRepository) AddMetadata(ctx *types.Context, repospec, dst str
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := r.AddRepositoryFile(metaTmpDir, REPOFILE_META_KEY, dst, NewDefaultMetaRepositoryFile())
|
a, err := r.AddRepositoryFile(metaTmpDir, REPOFILE_META_KEY, dst, NewDefaultMetaRepositoryFile())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return a, errors.Wrap(err, "Error met while adding archive to repository")
|
return a, errors.Wrap(err, "Error met while adding archive to repository")
|
||||||
@@ -558,7 +559,7 @@ func (r *LuetSystemRepository) AddMetadata(ctx *types.Context, repospec, dst str
|
|||||||
// AddTree adds a tree.Builder with the given key to the repository.
|
// AddTree adds a tree.Builder with the given key to the repository.
|
||||||
// It will generate an artifact which will be then embedded in the repository manifest
|
// It will generate an artifact which will be then embedded in the repository manifest
|
||||||
// It returns the generated artifacts and an error
|
// It returns the generated artifacts and an error
|
||||||
func (r *LuetSystemRepository) AddTree(ctx *types.Context, t tree.Builder, dst, key string, f LuetRepositoryFile) (*artifact.PackageArtifact, error) {
|
func (r *LuetSystemRepository) AddTree(ctx *types.Context, t tree.Builder, dst, key string, defaults LuetRepositoryFile) (*artifact.PackageArtifact, error) {
|
||||||
// Create tree and repository file
|
// Create tree and repository file
|
||||||
archive, err := ctx.Config.GetSystem().TempDir("archive")
|
archive, err := ctx.Config.GetSystem().TempDir("archive")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -570,13 +571,70 @@ func (r *LuetSystemRepository) AddTree(ctx *types.Context, t tree.Builder, dst,
|
|||||||
return nil, errors.Wrap(err, "Error met while saving the tree")
|
return nil, errors.Wrap(err, "Error met while saving the tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := r.AddRepositoryFile(archive, key, dst, f)
|
a, err := r.AddRepositoryFile(archive, key, dst, defaults)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Error met while adding archive to repository")
|
return nil, errors.Wrap(err, "Error met while adding archive to repository")
|
||||||
}
|
}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Snapshot creates a copy of the current repository index into dst.
|
||||||
|
// The copy will be prefixed with "id".
|
||||||
|
// This allows the clients to refer to old versions of the repository by using the reference_id
|
||||||
|
func (r *LuetSystemRepository) Snapshot(id, dst string) (artifacts []*artifact.PackageArtifact, snapshotIndex string, err error) {
|
||||||
|
|
||||||
|
var snapshotFmt string = "%s-%s"
|
||||||
|
|
||||||
|
repospec := filepath.Join(dst, REPOSITORY_SPECFILE)
|
||||||
|
snapshotIndex = filepath.Join(dst, fmt.Sprintf(snapshotFmt, id, REPOSITORY_SPECFILE))
|
||||||
|
|
||||||
|
err = fileHelper.CopyFile(repospec, filepath.Join(dst, snapshotIndex))
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "while copying repo spec")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadFile(repospec)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newRepoIndex := &LuetSystemRepository{}
|
||||||
|
err = yaml.Unmarshal(b, newRepoIndex)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range []string{REPOFILE_META_KEY, REPOFILE_TREE_KEY, REPOFILE_COMPILER_TREE_KEY} {
|
||||||
|
var luetFile LuetRepositoryFile
|
||||||
|
luetFile, err = r.GetRepositoryFile(key)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
newMetaFile := fmt.Sprintf(snapshotFmt, id, luetFile.FileName)
|
||||||
|
err = fileHelper.CopyFile(filepath.Join(dst, luetFile.FileName), filepath.Join(dst, newMetaFile))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &luetFile
|
||||||
|
m.FileName = newMetaFile
|
||||||
|
newRepoIndex.RepositoryFiles[key] = *m
|
||||||
|
artifacts = append(artifacts, artifact.NewPackageArtifact(filepath.Join(dst, newMetaFile)))
|
||||||
|
}
|
||||||
|
|
||||||
|
_, serialized := newRepoIndex.Serialize()
|
||||||
|
|
||||||
|
data, err := yaml.Marshal(serialized)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(snapshotIndex, data, os.ModePerm)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// AddRepositoryFile adds a path to a key in the repository manifest.
|
// AddRepositoryFile adds a path to a key in the repository manifest.
|
||||||
// The path will be compressed, and a default File has to be passed in case there is no entry into
|
// The path will be compressed, and a default File has to be passed in case there is no entry into
|
||||||
// the repository manifest
|
// the repository manifest
|
||||||
@@ -772,6 +830,14 @@ func (r *LuetSystemRepository) SyncBuildMetadata(ctx *types.Context, path string
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *LuetSystemRepository) referenceID() string {
|
||||||
|
repositoryReferenceID := REPOSITORY_SPECFILE
|
||||||
|
if r.ReferenceID != "" {
|
||||||
|
repositoryReferenceID = r.ReferenceID
|
||||||
|
}
|
||||||
|
return repositoryReferenceID
|
||||||
|
}
|
||||||
|
|
||||||
func (r *LuetSystemRepository) Sync(ctx *types.Context, force bool) (*LuetSystemRepository, error) {
|
func (r *LuetSystemRepository) Sync(ctx *types.Context, force bool) (*LuetSystemRepository, error) {
|
||||||
var repoUpdated bool = false
|
var repoUpdated bool = false
|
||||||
var treefs, metafs string
|
var treefs, metafs string
|
||||||
@@ -782,10 +848,12 @@ func (r *LuetSystemRepository) Sync(ctx *types.Context, force bool) (*LuetSystem
|
|||||||
return nil, errors.New("no client could be generated from repository")
|
return nil, errors.New("no client could be generated from repository")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repositoryReferenceID := r.referenceID()
|
||||||
|
|
||||||
// Retrieve remote repository.yaml for retrieve revision and date
|
// Retrieve remote repository.yaml for retrieve revision and date
|
||||||
file, err := c.DownloadFile(REPOSITORY_SPECFILE)
|
file, err := c.DownloadFile(repositoryReferenceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "while downloading "+REPOSITORY_SPECFILE)
|
return nil, errors.Wrap(err, "while downloading "+repositoryReferenceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
repobasedir := ctx.Config.GetSystem().GetRepoDatabaseDirPath(r.GetName())
|
repobasedir := ctx.Config.GetSystem().GetRepoDatabaseDirPath(r.GetName())
|
||||||
@@ -799,7 +867,7 @@ func (r *LuetSystemRepository) Sync(ctx *types.Context, force bool) (*LuetSystem
|
|||||||
|
|
||||||
if r.Cached {
|
if r.Cached {
|
||||||
if !force {
|
if !force {
|
||||||
localRepo, _ := r.ReadSpecFile(filepath.Join(repobasedir, REPOSITORY_SPECFILE))
|
localRepo, _ := r.ReadSpecFile(filepath.Join(repobasedir, repositoryReferenceID))
|
||||||
if localRepo != nil {
|
if localRepo != nil {
|
||||||
if localRepo.GetRevision() == downloadedRepoMeta.GetRevision() &&
|
if localRepo.GetRevision() == downloadedRepoMeta.GetRevision() &&
|
||||||
localRepo.GetLastUpdate() == downloadedRepoMeta.GetLastUpdate() {
|
localRepo.GetLastUpdate() == downloadedRepoMeta.GetLastUpdate() {
|
||||||
@@ -850,9 +918,9 @@ func (r *LuetSystemRepository) Sync(ctx *types.Context, force bool) (*LuetSystem
|
|||||||
|
|
||||||
if r.Cached {
|
if r.Cached {
|
||||||
// Copy updated repository.yaml file to repo dir now that the tree is synced.
|
// Copy updated repository.yaml file to repo dir now that the tree is synced.
|
||||||
err = fileHelper.CopyFile(file, filepath.Join(repobasedir, REPOSITORY_SPECFILE))
|
err = fileHelper.CopyFile(file, filepath.Join(repobasedir, repositoryReferenceID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Error on update "+REPOSITORY_SPECFILE)
|
return nil, errors.Wrap(err, "Error on update "+repositoryReferenceID)
|
||||||
}
|
}
|
||||||
// Remove previous tree
|
// Remove previous tree
|
||||||
os.RemoveAll(treefs)
|
os.RemoveAll(treefs)
|
||||||
|
@@ -136,7 +136,7 @@ func (d *dockerRepositoryGenerator) pushFileFromArtifact(a *artifact.PackageArti
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dockerRepositoryGenerator) pushRepoMetadata(repospec string, r *LuetSystemRepository) error {
|
func (d *dockerRepositoryGenerator) pushRepoMetadata(repospec, tag string, r *LuetSystemRepository) error {
|
||||||
// create temp dir for metafile
|
// create temp dir for metafile
|
||||||
metaDir, err := d.context.Config.GetSystem().TempDir("metadata")
|
metaDir, err := d.context.Config.GetSystem().TempDir("metadata")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -144,13 +144,13 @@ func (d *dockerRepositoryGenerator) pushRepoMetadata(repospec string, r *LuetSys
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(metaDir) // clean up
|
defer os.RemoveAll(metaDir) // clean up
|
||||||
|
|
||||||
tempRepoFile := filepath.Join(metaDir, REPOSITORY_SPECFILE+".tar")
|
tempRepoFile := filepath.Join(metaDir, tag+".tar")
|
||||||
if err := helpers.Tar(repospec, tempRepoFile); err != nil {
|
if err := helpers.Tar(repospec, tempRepoFile); err != nil {
|
||||||
return errors.Wrap(err, "Error met while archiving repository file")
|
return errors.Wrap(err, "Error met while archiving repository file")
|
||||||
}
|
}
|
||||||
|
|
||||||
a := artifact.NewPackageArtifact(tempRepoFile)
|
a := artifact.NewPackageArtifact(tempRepoFile)
|
||||||
imageRepo := fmt.Sprintf("%s:%s", d.imagePrefix, REPOSITORY_SPECFILE)
|
imageRepo := fmt.Sprintf("%s:%s", d.imagePrefix, tag)
|
||||||
|
|
||||||
if err := d.pushFileFromArtifact(a, imageRepo); err != nil {
|
if err := d.pushFileFromArtifact(a, imageRepo); err != nil {
|
||||||
return errors.Wrap(err, "while pushing file from artifact")
|
return errors.Wrap(err, "while pushing file from artifact")
|
||||||
@@ -242,14 +242,7 @@ func (d *dockerRepositoryGenerator) Generate(r *LuetSystemRepository, imagePrefi
|
|||||||
return errors.Wrap(err, "error met while pushing compiler tree")
|
return errors.Wrap(err, "error met while pushing compiler tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
// create temp dir for metafile
|
a, err = r.AddMetadata(d.context, repospec, repoTemp)
|
||||||
metaDir, err := d.context.Config.GetSystem().TempDir("metadata")
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "error met while creating tempdir for metadata")
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(metaDir) // clean up
|
|
||||||
|
|
||||||
a, err = r.AddMetadata(d.context, repospec, metaDir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed adding Metadata file to repository")
|
return errors.Wrap(err, "failed adding Metadata file to repository")
|
||||||
}
|
}
|
||||||
@@ -258,10 +251,28 @@ func (d *dockerRepositoryGenerator) Generate(r *LuetSystemRepository, imagePrefi
|
|||||||
return errors.Wrap(err, "error met while pushing docker image from artifact")
|
return errors.Wrap(err, "error met while pushing docker image from artifact")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.pushRepoMetadata(repospec, r); err != nil {
|
if err := d.pushRepoMetadata(repospec, REPOSITORY_SPECFILE, r); err != nil {
|
||||||
return errors.Wrap(err, "while pushing repository metadata tree")
|
return errors.Wrap(err, "while pushing repository metadata tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a named snapshot and push it.
|
||||||
|
// It edits the metadata pointing at the repository files associated with the snapshot
|
||||||
|
// And copies the new files
|
||||||
|
id := time.Now().Format("20060102150405")
|
||||||
|
artifacts, snapshotRepoFile, err := r.Snapshot(id, repoTemp)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "while creating snapshot")
|
||||||
|
}
|
||||||
|
if err := d.pushRepoMetadata(snapshotRepoFile, filepath.Base(snapshotRepoFile), r); err != nil {
|
||||||
|
return errors.Wrap(err, "while pushing repository snapshot metadata tree")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range artifacts {
|
||||||
|
if err := d.pushImageFromArtifact(a, d.b, false); err != nil {
|
||||||
|
return errors.Wrap(err, "error met while pushing docker image from artifact")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bus.Manager.Publish(bus.EventRepositoryPostBuild, struct {
|
bus.Manager.Publish(bus.EventRepositoryPostBuild, struct {
|
||||||
Repo LuetSystemRepository
|
Repo LuetSystemRepository
|
||||||
Path string
|
Path string
|
||||||
|
@@ -121,6 +121,13 @@ func (g *localRepositoryGenerator) Generate(r *LuetSystemRepository, dst string,
|
|||||||
return errors.Wrap(err, "failed adding Metadata file to repository")
|
return errors.Wrap(err, "failed adding Metadata file to repository")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create named snapshot.
|
||||||
|
// It edits the metadata pointing at the repository files associated with the snapshot
|
||||||
|
// And copies the new files
|
||||||
|
if _, _, err := r.Snapshot(time.Now().Format("20060102150405"), dst); err != nil {
|
||||||
|
return errors.Wrap(err, "while creating snapshot")
|
||||||
|
}
|
||||||
|
|
||||||
bus.Manager.Publish(bus.EventRepositoryPostBuild, struct {
|
bus.Manager.Publish(bus.EventRepositoryPostBuild, struct {
|
||||||
Repo LuetSystemRepository
|
Repo LuetSystemRepository
|
||||||
Path string
|
Path string
|
||||||
|
@@ -218,6 +218,124 @@ urls:
|
|||||||
Expect(err).To(HaveOccurred()) // should throw error
|
Expect(err).To(HaveOccurred()) // should throw error
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("Generates snapshots", func() {
|
||||||
|
|
||||||
|
tmpdir, err := ioutil.TempDir("", "tree")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer os.RemoveAll(tmpdir) // clean up
|
||||||
|
|
||||||
|
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||||
|
|
||||||
|
err = generalRecipe.Load("../../tests/fixtures/buildable")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
generalRecipe2 := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
|
||||||
|
|
||||||
|
err = generalRecipe2.Load("../../tests/fixtures/finalizers")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(generalRecipe2.GetDatabase().GetPackages())).To(Equal(1))
|
||||||
|
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3))
|
||||||
|
|
||||||
|
compiler2 := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(ctx), generalRecipe2.GetDatabase(), options.WithContext(ctx))
|
||||||
|
spec2, err := compiler2.FromPackage(&pkg.DefaultPackage{Name: "alpine", Category: "seed", Version: "1.0"})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
compiler := compiler.NewLuetCompiler(backend.NewSimpleDockerBackend(ctx), generalRecipe.GetDatabase(), options.WithContext(ctx))
|
||||||
|
|
||||||
|
spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(spec.GetPackage().GetPath()).ToNot(Equal(""))
|
||||||
|
Expect(spec2.GetPackage().GetPath()).ToNot(Equal(""))
|
||||||
|
|
||||||
|
tmpdir, err = ioutil.TempDir("", "tree")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer os.RemoveAll(tmpdir) // clean up
|
||||||
|
|
||||||
|
Expect(spec.BuildSteps()).To(Equal([]string{"echo artifact5 > /test5", "echo artifact6 > /test6", "chmod +x generate.sh", "./generate.sh"}))
|
||||||
|
Expect(spec.GetPreBuildSteps()).To(Equal([]string{"echo foo > /test", "echo bar > /test2"}))
|
||||||
|
|
||||||
|
spec.SetOutputPath(tmpdir)
|
||||||
|
spec2.SetOutputPath(tmpdir)
|
||||||
|
|
||||||
|
artifact, err := compiler.Compile(false, spec)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(fileHelper.Exists(artifact.Path)).To(BeTrue())
|
||||||
|
Expect(helpers.Untar(artifact.Path, tmpdir, false)).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
artifact2, err := compiler2.Compile(false, spec2)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(fileHelper.Exists(artifact2.Path)).To(BeTrue())
|
||||||
|
Expect(helpers.Untar(artifact2.Path, tmpdir, false)).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(fileHelper.Exists(spec.Rel("test5"))).To(BeTrue())
|
||||||
|
Expect(fileHelper.Exists(spec.Rel("test6"))).To(BeTrue())
|
||||||
|
|
||||||
|
content1, err := fileHelper.Read(spec.Rel("test5"))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
content2, err := fileHelper.Read(spec.Rel("test6"))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(content1).To(Equal("artifact5\n"))
|
||||||
|
Expect(content2).To(Equal("artifact6\n"))
|
||||||
|
|
||||||
|
// will contain both
|
||||||
|
Expect(fileHelper.Exists(spec.Rel("b-test-1.0.package.tar"))).To(BeTrue())
|
||||||
|
Expect(fileHelper.Exists(spec.Rel("b-test-1.0.metadata.yaml"))).To(BeTrue())
|
||||||
|
Expect(fileHelper.Exists(spec2.Rel("alpine-seed-1.0.package.tar"))).To(BeTrue())
|
||||||
|
Expect(fileHelper.Exists(spec2.Rel("alpine-seed-1.0.metadata.yaml"))).To(BeTrue())
|
||||||
|
|
||||||
|
repo, err := GenerateRepository(
|
||||||
|
WithName("test"),
|
||||||
|
WithDescription("description"),
|
||||||
|
WithType("disk"),
|
||||||
|
WithUrls(tmpdir),
|
||||||
|
WithPriority(1),
|
||||||
|
WithSource(tmpdir),
|
||||||
|
FromMetadata(true), // Enabling from metadata makes the package visible
|
||||||
|
WithTree("../../tests/fixtures/buildable"),
|
||||||
|
WithContext(ctx),
|
||||||
|
WithDatabase(pkg.NewInMemoryDatabase(false)),
|
||||||
|
)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(repo.GetName()).To(Equal("test"))
|
||||||
|
Expect(fileHelper.Exists(spec.Rel(REPOSITORY_SPECFILE))).ToNot(BeTrue())
|
||||||
|
Expect(fileHelper.Exists(spec.Rel(TREE_TARBALL + ".gz"))).ToNot(BeTrue())
|
||||||
|
Expect(fileHelper.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).ToNot(BeTrue())
|
||||||
|
err = repo.Write(ctx, tmpdir, false, true)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(fileHelper.Exists(spec.Rel(REPOSITORY_SPECFILE))).To(BeTrue())
|
||||||
|
Expect(fileHelper.Exists(spec.Rel(TREE_TARBALL + ".gz"))).To(BeTrue())
|
||||||
|
Expect(fileHelper.Exists(spec.Rel(REPOSITORY_METAFILE + ".tar"))).To(BeTrue())
|
||||||
|
|
||||||
|
artifacts, index, err := repo.Snapshot("foo", tmpdir)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(len(artifacts)).To(Equal(3))
|
||||||
|
Expect(index).To(ContainSubstring("foo-repository.yaml"))
|
||||||
|
r := &LuetSystemRepository{}
|
||||||
|
|
||||||
|
r, err = r.ReadSpecFile(index)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(r.RepositoryFiles)).To(Equal(3))
|
||||||
|
|
||||||
|
for k, v := range r.RepositoryFiles {
|
||||||
|
_, err := os.Stat(filepath.Join(tmpdir, "foo-compilertree.tar.gz"))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
switch k {
|
||||||
|
case REPOFILE_COMPILER_TREE_KEY:
|
||||||
|
Expect(v.FileName).To(Equal("foo-compilertree.tar.gz"))
|
||||||
|
case REPOFILE_META_KEY:
|
||||||
|
Expect(v.FileName).To(Equal("foo-repository.meta.yaml.tar"))
|
||||||
|
case REPOFILE_TREE_KEY:
|
||||||
|
Expect(v.FileName).To(Equal("foo-tree.tar.gz"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
It("Generate repository metadata of files referenced in a tree and from packages", func() {
|
It("Generate repository metadata of files referenced in a tree and from packages", func() {
|
||||||
|
|
||||||
tmpdir, err := ioutil.TempDir("", "tree")
|
tmpdir, err := ioutil.TempDir("", "tree")
|
||||||
|
Reference in New Issue
Block a user