mirror of
https://github.com/mudler/luet.git
synced 2025-06-25 06:52:59 +00:00
Merge pull request #183 from mudler/docker-debug-output
Add realtime output for building phase
This commit is contained in:
commit
101df40eec
@ -83,6 +83,8 @@ Build packages specifying multiple definition trees:
|
|||||||
LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount"))
|
LuetCfg.Viper.BindPFlag("solver.discount", cmd.Flags().Lookup("solver-discount"))
|
||||||
LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate"))
|
LuetCfg.Viper.BindPFlag("solver.rate", cmd.Flags().Lookup("solver-rate"))
|
||||||
LuetCfg.Viper.BindPFlag("solver.max_attempts", cmd.Flags().Lookup("solver-attempts"))
|
LuetCfg.Viper.BindPFlag("solver.max_attempts", cmd.Flags().Lookup("solver-attempts"))
|
||||||
|
LuetCfg.Viper.BindPFlag("general.show_build_output", cmd.Flags().Lookup("live-output"))
|
||||||
|
|
||||||
},
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
@ -155,6 +157,8 @@ Build packages specifying multiple definition trees:
|
|||||||
LuetCfg.GetSolverOptions().Discount = float32(discount)
|
LuetCfg.GetSolverOptions().Discount = float32(discount)
|
||||||
LuetCfg.GetSolverOptions().MaxAttempts = attempts
|
LuetCfg.GetSolverOptions().MaxAttempts = attempts
|
||||||
|
|
||||||
|
LuetCfg.GetGeneral().ShowBuildOutput = LuetCfg.Viper.GetBool("general.show_build_output")
|
||||||
|
|
||||||
Debug("Solver", LuetCfg.GetSolverOptions().CompactString())
|
Debug("Solver", LuetCfg.GetSolverOptions().CompactString())
|
||||||
|
|
||||||
opts := compiler.NewDefaultCompilerOptions()
|
opts := compiler.NewDefaultCompilerOptions()
|
||||||
@ -317,6 +321,7 @@ func init() {
|
|||||||
buildCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate")
|
buildCmd.Flags().Float32("solver-discount", 1.0, "Solver discount rate")
|
||||||
buildCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts")
|
buildCmd.Flags().Int("solver-attempts", 9000, "Solver maximum attempts")
|
||||||
buildCmd.Flags().Bool("solver-concurrent", false, "Use concurrent solver (experimental)")
|
buildCmd.Flags().Bool("solver-concurrent", false, "Use concurrent solver (experimental)")
|
||||||
|
buildCmd.Flags().Bool("live-output", LuetCfg.GetGeneral().ShowBuildOutput, "Enable live output of the build phase.")
|
||||||
|
|
||||||
buildCmd.Flags().Bool("pretend", false, "Just print what packages will be compiled")
|
buildCmd.Flags().Bool("pretend", false, "Just print what packages will be compiled")
|
||||||
|
|
||||||
|
@ -16,8 +16,14 @@
|
|||||||
package backend
|
package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/google/go-containerregistry/pkg/crane"
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
"github.com/mudler/luet/pkg/compiler"
|
"github.com/mudler/luet/pkg/compiler"
|
||||||
|
"github.com/mudler/luet/pkg/config"
|
||||||
|
|
||||||
|
"github.com/google/go-containerregistry/pkg/crane"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -41,3 +47,38 @@ func NewBackend(s string) compiler.CompilerBackend {
|
|||||||
}
|
}
|
||||||
return compilerBackend
|
return compilerBackend
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runCommand(cmd *exec.Cmd) (string, error) {
|
||||||
|
ans := ""
|
||||||
|
writer := NewBackendWriter(!config.LuetCfg.GetGeneral().ShowBuildOutput)
|
||||||
|
|
||||||
|
cmd.Stdout = writer
|
||||||
|
cmd.Stderr = writer
|
||||||
|
|
||||||
|
err := cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "Failed starting build")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cmd.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "Failed waiting for building command")
|
||||||
|
}
|
||||||
|
|
||||||
|
res := cmd.ProcessState.ExitCode()
|
||||||
|
if res != 0 {
|
||||||
|
errMsg := fmt.Sprintf("Failed building image (exiting with %d)", res)
|
||||||
|
if !config.LuetCfg.GetGeneral().ShowBuildOutput {
|
||||||
|
errMsg = fmt.Sprintf("Failed building image (exiting with %d): %s",
|
||||||
|
res, writer.GetCombinedOutput())
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.Wrap(err, errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !config.LuetCfg.GetGeneral().ShowBuildOutput {
|
||||||
|
ans = writer.GetCombinedOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans, nil
|
||||||
|
}
|
||||||
|
@ -53,19 +53,31 @@ func (*SimpleDocker) BuildImage(opts compiler.CompilerBackendOptions) error {
|
|||||||
}
|
}
|
||||||
buildarg := []string{"build", "-f", dockerfileName, "-t", name, context}
|
buildarg := []string{"build", "-f", dockerfileName, "-t", name, context}
|
||||||
|
|
||||||
|
if !config.LuetCfg.GetGeneral().ShowBuildOutput {
|
||||||
|
Spinner(22)
|
||||||
|
defer SpinnerStop()
|
||||||
|
}
|
||||||
|
|
||||||
Info(":whale2: Building image " + name)
|
Info(":whale2: Building image " + name)
|
||||||
cmd := exec.Command("docker", buildarg...)
|
cmd := exec.Command("docker", buildarg...)
|
||||||
cmd.Dir = path
|
cmd.Dir = path
|
||||||
out, err := cmd.CombinedOutput()
|
_, err := runCommand(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed building image: "+string(out))
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !config.LuetCfg.GetGeneral().ShowBuildOutput {
|
||||||
|
SpinnerStop()
|
||||||
|
}
|
||||||
|
|
||||||
Info(":whale: Building image " + name + " done")
|
Info(":whale: Building image " + name + " done")
|
||||||
|
|
||||||
if os.Getenv("DOCKER_SQUASH") == "true" {
|
if os.Getenv("DOCKER_SQUASH") == "true" {
|
||||||
Info(":whale: Squashing image " + name)
|
Info(":whale: Squashing image " + name)
|
||||||
var client *docker.Client
|
var client *docker.Client
|
||||||
|
|
||||||
|
Spinner(22)
|
||||||
|
|
||||||
client, err = docker.NewClientFromEnv()
|
client, err = docker.NewClientFromEnv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "could not connect to the Docker daemon")
|
return errors.Wrap(err, "could not connect to the Docker daemon")
|
||||||
@ -74,13 +86,8 @@ func (*SimpleDocker) BuildImage(opts compiler.CompilerBackendOptions) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed squashing image")
|
return errors.Wrap(err, "Failed squashing image")
|
||||||
}
|
}
|
||||||
Info(":whale: Squashing image " + name + " done")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.LuetCfg.GetGeneral().ShowBuildOutput {
|
Info(":whale: Squashing image " + name + " done")
|
||||||
Info(string(out))
|
|
||||||
} else {
|
|
||||||
Debug(string(out))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -101,11 +108,16 @@ func (*SimpleDocker) DownloadImage(opts compiler.CompilerBackendOptions) error {
|
|||||||
name := opts.ImageName
|
name := opts.ImageName
|
||||||
buildarg := []string{"pull", name}
|
buildarg := []string{"pull", name}
|
||||||
Debug(":whale: Downloading image " + name)
|
Debug(":whale: Downloading image " + name)
|
||||||
|
|
||||||
|
Spinner(22)
|
||||||
|
defer SpinnerStop()
|
||||||
|
|
||||||
cmd := exec.Command("docker", buildarg...)
|
cmd := exec.Command("docker", buildarg...)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed pulling image: "+string(out))
|
return errors.Wrap(err, "Failed pulling image: "+string(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
Info(":whale: Downloaded image:", name)
|
Info(":whale: Downloaded image:", name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -142,6 +154,10 @@ func (*SimpleDocker) RemoveImage(opts compiler.CompilerBackendOptions) error {
|
|||||||
func (*SimpleDocker) Push(opts compiler.CompilerBackendOptions) error {
|
func (*SimpleDocker) Push(opts compiler.CompilerBackendOptions) error {
|
||||||
name := opts.ImageName
|
name := opts.ImageName
|
||||||
pusharg := []string{"push", name}
|
pusharg := []string{"push", name}
|
||||||
|
|
||||||
|
Spinner(22)
|
||||||
|
defer SpinnerStop()
|
||||||
|
|
||||||
out, err := exec.Command("docker", pusharg...).CombinedOutput()
|
out, err := exec.Command("docker", pusharg...).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed pushing image: "+string(out))
|
return errors.Wrap(err, "Failed pushing image: "+string(out))
|
||||||
@ -170,6 +186,10 @@ func (*SimpleDocker) ExportImage(opts compiler.CompilerBackendOptions) error {
|
|||||||
|
|
||||||
buildarg := []string{"save", name, "-o", path}
|
buildarg := []string{"save", name, "-o", path}
|
||||||
Debug(":whale: Saving image " + name)
|
Debug(":whale: Saving image " + name)
|
||||||
|
|
||||||
|
Spinner(22)
|
||||||
|
defer SpinnerStop()
|
||||||
|
|
||||||
out, err := exec.Command("docker", buildarg...).CombinedOutput()
|
out, err := exec.Command("docker", buildarg...).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed exporting image: "+string(out))
|
return errors.Wrap(err, "Failed exporting image: "+string(out))
|
||||||
@ -194,10 +214,16 @@ func (b *SimpleDocker) ExtractRootfs(opts compiler.CompilerBackendOptions, keepP
|
|||||||
defer os.RemoveAll(tempexport) // clean up
|
defer os.RemoveAll(tempexport) // clean up
|
||||||
|
|
||||||
imageExport := filepath.Join(tempexport, "image.tar")
|
imageExport := filepath.Join(tempexport, "image.tar")
|
||||||
|
|
||||||
|
Spinner(22)
|
||||||
|
defer SpinnerStop()
|
||||||
|
|
||||||
if err := b.ExportImage(compiler.CompilerBackendOptions{ImageName: name, Destination: imageExport}); err != nil {
|
if err := b.ExportImage(compiler.CompilerBackendOptions{ImageName: name, Destination: imageExport}); err != nil {
|
||||||
return errors.Wrap(err, "failed while extracting rootfs for "+name)
|
return errors.Wrap(err, "failed while extracting rootfs for "+name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpinnerStop()
|
||||||
|
|
||||||
src := imageExport
|
src := imageExport
|
||||||
|
|
||||||
if src == "" && opts.ImageName != "" {
|
if src == "" && opts.ImageName != "" {
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mudler/luet/pkg/compiler"
|
"github.com/mudler/luet/pkg/compiler"
|
||||||
|
"github.com/mudler/luet/pkg/config"
|
||||||
. "github.com/mudler/luet/pkg/logger"
|
. "github.com/mudler/luet/pkg/logger"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -44,17 +45,23 @@ func (*SimpleImg) BuildImage(opts compiler.CompilerBackendOptions) error {
|
|||||||
dockerfileName := opts.DockerFileName
|
dockerfileName := opts.DockerFileName
|
||||||
|
|
||||||
buildarg := []string{"build", "-f", dockerfileName, "-t", name, context}
|
buildarg := []string{"build", "-f", dockerfileName, "-t", name, context}
|
||||||
Spinner(22)
|
|
||||||
defer SpinnerStop()
|
|
||||||
Info(":tea: Building image " + name)
|
Info(":tea: Building image " + name)
|
||||||
|
|
||||||
|
if !config.LuetCfg.GetGeneral().ShowBuildOutput {
|
||||||
|
Spinner(22)
|
||||||
|
defer SpinnerStop()
|
||||||
|
}
|
||||||
|
|
||||||
cmd := exec.Command("img", buildarg...)
|
cmd := exec.Command("img", buildarg...)
|
||||||
cmd.Dir = path
|
cmd.Dir = path
|
||||||
out, err := cmd.CombinedOutput()
|
_, err := runCommand(cmd)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed building image: "+string(out))
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
Info(":tea: Building image " + name + " done")
|
Info(":tea: Building image " + name + " done")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,11 +80,13 @@ func (*SimpleImg) RemoveImage(opts compiler.CompilerBackendOptions) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (*SimpleImg) DownloadImage(opts compiler.CompilerBackendOptions) error {
|
func (*SimpleImg) DownloadImage(opts compiler.CompilerBackendOptions) error {
|
||||||
|
|
||||||
name := opts.ImageName
|
name := opts.ImageName
|
||||||
buildarg := []string{"pull", name}
|
buildarg := []string{"pull", name}
|
||||||
|
|
||||||
Debug(":tea: Downloading image " + name)
|
Debug(":tea: Downloading image " + name)
|
||||||
|
|
||||||
|
Spinner(22)
|
||||||
|
defer SpinnerStop()
|
||||||
|
|
||||||
cmd := exec.Command("img", buildarg...)
|
cmd := exec.Command("img", buildarg...)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -138,6 +147,10 @@ func (*SimpleImg) ExportImage(opts compiler.CompilerBackendOptions) error {
|
|||||||
path := opts.Destination
|
path := opts.Destination
|
||||||
buildarg := []string{"save", "-o", path, name}
|
buildarg := []string{"save", "-o", path, name}
|
||||||
Debug(":tea: Saving image " + name)
|
Debug(":tea: Saving image " + name)
|
||||||
|
|
||||||
|
Spinner(22)
|
||||||
|
defer SpinnerStop()
|
||||||
|
|
||||||
out, err := exec.Command("img", buildarg...).CombinedOutput()
|
out, err := exec.Command("img", buildarg...).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed exporting image: "+string(out))
|
return errors.Wrap(err, "Failed exporting image: "+string(out))
|
||||||
@ -158,8 +171,13 @@ func (s *SimpleImg) ExtractRootfs(opts compiler.CompilerBackendOptions, keepPerm
|
|||||||
}
|
}
|
||||||
|
|
||||||
os.RemoveAll(path)
|
os.RemoveAll(path)
|
||||||
|
|
||||||
buildarg := []string{"unpack", "-o", path, name}
|
buildarg := []string{"unpack", "-o", path, name}
|
||||||
Debug(":tea: Extracting image " + name)
|
Debug(":tea: Extracting image " + name)
|
||||||
|
|
||||||
|
Spinner(22)
|
||||||
|
defer SpinnerStop()
|
||||||
|
|
||||||
out, err := exec.Command("img", buildarg...).CombinedOutput()
|
out, err := exec.Command("img", buildarg...).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed extracting image: "+string(out))
|
return errors.Wrap(err, "Failed extracting image: "+string(out))
|
||||||
|
45
pkg/compiler/backend/writer.go
Normal file
45
pkg/compiler/backend/writer.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright © 2021 Daniele Rondina <geaaru@sabayonlinux.org>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package backend
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
. "github.com/mudler/luet/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackendWriter struct {
|
||||||
|
BufferedOutput bool
|
||||||
|
Buffer bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBackendWriter(buffered bool) *BackendWriter {
|
||||||
|
return &BackendWriter{
|
||||||
|
BufferedOutput: buffered,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BackendWriter) Write(p []byte) (int, error) {
|
||||||
|
if b.BufferedOutput {
|
||||||
|
return b.Buffer.Write(p)
|
||||||
|
} else {
|
||||||
|
Msg("info", false, false, (string(p)))
|
||||||
|
}
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BackendWriter) Close() error { return nil }
|
||||||
|
func (b *BackendWriter) GetCombinedOutput() string { return b.Buffer.String() }
|
@ -148,8 +148,6 @@ func (cs *LuetCompiler) CompileWithReverseDeps(keepPermissions bool, ps Compilat
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cs *LuetCompiler) CompileParallel(keepPermissions bool, ps CompilationSpecs) ([]Artifact, []error) {
|
func (cs *LuetCompiler) CompileParallel(keepPermissions bool, ps CompilationSpecs) ([]Artifact, []error) {
|
||||||
Spinner(22)
|
|
||||||
defer SpinnerStop()
|
|
||||||
all := make(chan CompilationSpec)
|
all := make(chan CompilationSpec)
|
||||||
artifacts := []Artifact{}
|
artifacts := []Artifact{}
|
||||||
mutex := &sync.Mutex{}
|
mutex := &sync.Mutex{}
|
||||||
|
@ -173,7 +173,7 @@ func level2AtomicLevel(level string) zap.AtomicLevel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func msg(level string, withoutColor bool, msg ...interface{}) {
|
func Msg(level string, withoutColor, ln bool, msg ...interface{}) {
|
||||||
var message string
|
var message string
|
||||||
var confLevel, msgLevel int
|
var confLevel, msgLevel int
|
||||||
|
|
||||||
@ -219,11 +219,16 @@ func msg(level string, withoutColor bool, msg ...interface{}) {
|
|||||||
log2File(level, message)
|
log2File(level, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(levelMsg)
|
if ln {
|
||||||
|
fmt.Println(levelMsg)
|
||||||
|
} else {
|
||||||
|
fmt.Print(levelMsg)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Warning(mess ...interface{}) {
|
func Warning(mess ...interface{}) {
|
||||||
msg("warning", false, mess...)
|
Msg("warning", false, true, mess...)
|
||||||
if LuetCfg.GetGeneral().FatalWarns {
|
if LuetCfg.GetGeneral().FatalWarns {
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
@ -235,23 +240,23 @@ func Debug(mess ...interface{}) {
|
|||||||
mess = append([]interface{}{fmt.Sprintf("DEBUG (%s:#%d:%v)",
|
mess = append([]interface{}{fmt.Sprintf("DEBUG (%s:#%d:%v)",
|
||||||
path.Base(file), line, runtime.FuncForPC(pc).Name())}, mess...)
|
path.Base(file), line, runtime.FuncForPC(pc).Name())}, mess...)
|
||||||
}
|
}
|
||||||
msg("debug", false, mess...)
|
Msg("debug", false, true, mess...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DebugC(mess ...interface{}) {
|
func DebugC(mess ...interface{}) {
|
||||||
msg("debug", true, mess...)
|
Msg("debug", true, true, mess...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Info(mess ...interface{}) {
|
func Info(mess ...interface{}) {
|
||||||
msg("info", false, mess...)
|
Msg("info", false, true, mess...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InfoC(mess ...interface{}) {
|
func InfoC(mess ...interface{}) {
|
||||||
msg("info", true, mess...)
|
Msg("info", true, true, mess...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Error(mess ...interface{}) {
|
func Error(mess ...interface{}) {
|
||||||
msg("error", false, mess...)
|
Msg("error", false, true, mess...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Fatal(mess ...interface{}) {
|
func Fatal(mess ...interface{}) {
|
||||||
|
Loading…
Reference in New Issue
Block a user