From ed2fc347c974c9b513f6794bd3939976398e5e2d Mon Sep 17 00:00:00 2001 From: Zeyu Li Date: Fri, 7 Jul 2023 09:05:31 +0000 Subject: [PATCH] refactor: Use juju errors Signed-off-by: Zeyu Li --- archive/archive.go | 22 ++--- archive/unarchive.go | 17 ++-- cmd/kraft/build/build.go | 23 +++--- cmd/kraft/events/events.go | 16 ++-- cmd/kraft/fetch/fetch.go | 4 +- cmd/kraft/login/login.go | 3 +- cmd/kraft/logs/logs.go | 9 ++- cmd/kraft/menu/menu.go | 4 +- cmd/kraft/net/create/create.go | 5 +- cmd/kraft/net/down/down.go | 3 +- cmd/kraft/net/inspect/inspect.go | 3 +- cmd/kraft/net/list/list.go | 5 +- cmd/kraft/net/net.go | 7 +- cmd/kraft/net/remove/remove.go | 3 +- cmd/kraft/net/up/up.go | 3 +- cmd/kraft/pkg/pkg.go | 4 +- cmd/kraft/pkg/pull/pull.go | 9 ++- cmd/kraft/prepare/prepare.go | 4 +- cmd/kraft/ps/ps.go | 7 +- cmd/kraft/rm/rm.go | 11 +-- cmd/kraft/run/run.go | 35 ++++---- cmd/kraft/run/runner_kernel.go | 6 +- cmd/kraft/run/runner_linuxu.go | 17 ++-- cmd/kraft/run/runner_package.go | 11 +-- cmd/kraft/run/runner_project.go | 14 ++-- cmd/kraft/run/utils.go | 4 +- cmd/kraft/set/set.go | 7 +- cmd/kraft/stop/stop.go | 13 +-- cmd/kraft/unset/unset.go | 5 +- cmdfactory/builder.go | 9 ++- cmdfactory/errors.go | 6 +- cmdfactory/flags_enum.go | 5 +- config/config_file.go | 6 +- config/defaults.go | 11 +-- config/feeder_yaml.go | 16 ++-- config/manager.go | 21 ++--- exec/executable.go | 10 ++- exec/options.go | 4 +- exec/process.go | 10 +-- go.mod | 1 + go.sum | 2 + initrd/initrd.go | 22 ++--- internal/cli/options.go | 8 +- internal/cli/target.go | 3 +- internal/ghrepo/repo.go | 13 +-- internal/run/stub.go | 6 +- internal/tableprinter/tableprinter_options.go | 6 +- internal/yamlmerger/yamlmerger.go | 9 +-- kconfig/config.go | 6 +- kconfig/kconfig.go | 7 +- kconfig/parser.go | 4 +- machine/firecracker/v1alpha1.go | 18 ++--- machine/name/id.go | 4 +- machine/network/bridge/utils.go | 8 +- machine/network/bridge/v1alpha1.go | 81 ++++++++++--------- machine/platform/detect.go | 4 +- machine/platform/filter.go | 4 +- machine/platform/iterator_v1alpha1.go | 20 ++--- machine/qemu/qemu_hostchardev.go | 28 ++++--- machine/qemu/qemu_version.go | 10 +-- machine/qemu/qmp/events.go | 5 +- .../qemu/qmp/v1alpha/service.pb.netconn.go | 5 +- machine/qemu/v1alpha1.go | 51 ++++++------ machine/store/embedded.go | 18 ++--- make/make.go | 8 +- make/options.go | 5 +- manifest/directory.go | 16 ++-- manifest/git.go | 4 +- manifest/github.go | 6 +- manifest/index.go | 18 ++--- manifest/manager.go | 14 ++-- manifest/manifest.go | 26 +++--- manifest/pack.go | 12 +-- manifest/pack_pull_archive.go | 26 +++--- manifest/pack_pull_git.go | 17 ++-- manifest/provider.go | 5 +- manifest/version.go | 4 +- oci/blob.go | 8 +- oci/handler/containerd.go | 9 ++- oci/handler/directory.go | 18 ++--- oci/image.go | 12 +-- oci/layer_options.go | 6 +- oci/manager.go | 15 ++-- oci/manager_options.go | 4 +- oci/pack.go | 27 ++++--- packmanager/umbrella.go | 12 +-- plugins/manager.go | 11 +-- test/e2e/framework/cmd/cmd.go | 5 +- test/e2e/framework/matchers/be_empty_dir.go | 7 +- test/e2e/framework/matchers/contain_dirs.go | 11 +-- test/e2e/framework/matchers/contain_files.go | 11 +-- tools/protoc-gen-go-netconn/apply.go | 5 +- tui/paraprogress/paraprogress.go | 6 +- tui/processtree/update.go | 5 +- unikraft/app/application.go | 15 ++-- unikraft/app/application_options.go | 4 +- unikraft/app/build_options.go | 4 +- unikraft/app/project.go | 8 +- unikraft/app/project_options.go | 4 +- unikraft/arch/architecture.go | 4 +- unikraft/arch/host.go | 5 +- unikraft/arch/transform.go | 4 +- unikraft/core/core.go | 4 +- unikraft/elfloader/elfloader_pack.go | 6 +- unikraft/export/v0/ukargparse/parse.go | 5 +- unikraft/lib/library.go | 10 +-- unikraft/lib/transform.go | 6 +- unikraft/plat/transform.go | 4 +- unikraft/target/target.go | 5 +- unikraft/target/transform.go | 4 +- unikraft/type.go | 7 +- unikraft/utils.go | 6 +- utils/terminal.go | 4 +- 113 files changed, 611 insertions(+), 546 deletions(-) diff --git a/archive/archive.go b/archive/archive.go index e48c7a9bc..3c3e1107d 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -8,7 +8,6 @@ import ( "archive/tar" "compress/gzip" "context" - "fmt" "io" "os" "path/filepath" @@ -16,6 +15,7 @@ import ( "sync" "time" + "github.com/juju/errors" "github.com/sirupsen/logrus" "kraftkit.sh/log" @@ -38,12 +38,12 @@ func TarFileWriter(ctx context.Context, src, dst string, tw *tar.Writer, opts .. dst = filepath.ToSlash(dst) if dst == "" { - return fmt.Errorf("cannot tar file with no specified destination") + return errors.New("cannot tar file with no specified destination") } else if dst[0] == '/' { dst = dst[1:] } if strings.HasSuffix(dst, "/") { - return fmt.Errorf("attempting to use TarFileWriter with directory") + return errors.New("attempting to use TarFileWriter with directory") } aopts := ArchiveOptions{} @@ -55,7 +55,7 @@ func TarFileWriter(ctx context.Context, src, dst string, tw *tar.Writer, opts .. fi, err := os.Stat(src) if err != nil { - return fmt.Errorf("fail to stat %s: %v", src, err) + return errors.Annotatef(err, "fail to stat %s", src) } var link string @@ -68,7 +68,7 @@ func TarFileWriter(ctx context.Context, src, dst string, tw *tar.Writer, opts .. header, err := tar.FileInfoHeader(fi, link) if err != nil { - return fmt.Errorf("%s: %w", src, err) + return errors.Annotatef(err, "%s", src) } header.Name = dst @@ -85,7 +85,7 @@ func TarFileWriter(ctx context.Context, src, dst string, tw *tar.Writer, opts .. } if err := tw.WriteHeader(header); err != nil { - return fmt.Errorf("tar: %w", err) + return errors.Annotate(err, "tar") } if mode.IsRegular() { @@ -96,14 +96,14 @@ func TarFileWriter(ctx context.Context, src, dst string, tw *tar.Writer, opts .. fp, err := os.Open(src) if err != nil { - return fmt.Errorf("fail to open file %s: %v", src, err) + return errors.Annotatef(err, "fail to open file %s", src) } buf := bufPool.Get().(*[]byte) defer bufPool.Put(buf) if _, err := io.CopyBuffer(tw, fp, *buf); err != nil { - return fmt.Errorf("failed to copy to %s: %w", src, err) + return errors.Annotatef(err, "failed to copy to %s", src) } if err := fp.Close(); err != nil { @@ -126,7 +126,7 @@ func TarFileTo(ctx context.Context, src, dst, out string, opts ...ArchiveOption) fp, err := os.OpenFile(out, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644) if err != nil { - return fmt.Errorf("could not create tarball file: %s: %v", out, err) + return errors.Annotatef(err, "could not create tarball file: %s", out) } var tw *tar.Writer @@ -164,7 +164,7 @@ func TarFileTo(ctx context.Context, src, dst, out string, opts ...ArchiveOption) func TarFile(ctx context.Context, src, prefix, out string, opts ...ArchiveOption) error { fp, err := os.OpenFile(out, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644) if err != nil { - return fmt.Errorf("could not create tarball file: %s: %v", out, err) + return errors.Annotatef(err, "could not create tarball file: %s", out) } tw := tar.NewWriter(fp) @@ -183,7 +183,7 @@ func TarFile(ctx context.Context, src, prefix, out string, opts ...ArchiveOption func TarDir(ctx context.Context, root, prefix, out string, opts ...ArchiveOption) error { fp, err := os.OpenFile(out, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644) if err != nil { - return fmt.Errorf("could not create tarball file: %s: %v", out, err) + return errors.Annotatef(err, "could not create tarball file: %s", out) } tw := tar.NewWriter(fp) diff --git a/archive/unarchive.go b/archive/unarchive.go index 38b599a13..a0f585356 100644 --- a/archive/unarchive.go +++ b/archive/unarchive.go @@ -7,11 +7,12 @@ package archive import ( "archive/tar" "compress/gzip" - "fmt" "io" "os" "path/filepath" "strings" + + "github.com/juju/errors" ) // Unarchive takes an input src file and determines (based on its extension) @@ -21,21 +22,21 @@ func Unarchive(src, dst string, opts ...UnarchiveOption) error { return UntarGz(src, dst, opts...) } - return fmt.Errorf("unrecognized extension: %s", filepath.Base(src)) + return errors.Errorf("unrecognized extension: %s", filepath.Base(src)) } // UntarGz unarchives a tarball which has been gzip compressed func UntarGz(src, dst string, opts ...UnarchiveOption) error { f, err := os.Open(src) if err != nil { - return fmt.Errorf("could not open file: %v", err) + return errors.Annotate(err, "could not open file") } defer f.Close() gzipReader, err := gzip.NewReader(f) if err != nil { - return fmt.Errorf("could not open gzip reader: %v", err) + return errors.Annotate(err, "could not open gzip reader") } return Untar(gzipReader, dst, opts...) @@ -78,23 +79,23 @@ func Untar(src io.Reader, dst string, opts ...UnarchiveOption) error { switch header.Typeflag { case tar.TypeDir: if err := os.MkdirAll(path, info.Mode()); err != nil { - return fmt.Errorf("could not create directory: %v", err) + return errors.Annotate(err, "could not create directory") } case tar.TypeReg: // Create parent path if it does not exist if err := os.MkdirAll(filepath.Dir(path), info.Mode()); err != nil { - return fmt.Errorf("could not create directory: %v", err) + return errors.Annotate(err, "could not create directory") } newFile, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()) if err != nil { - return fmt.Errorf("could not create file: %v", err) + return errors.Annotate(err, "could not create file") } if _, err := io.Copy(newFile, tr); err != nil { newFile.Close() - return fmt.Errorf("could not copy file: %v", err) + return errors.Annotate(err, "could not copy file") } newFile.Close() diff --git a/cmd/kraft/build/build.go b/cmd/kraft/build/build.go index 6d402cbcd..5ecb99b6a 100644 --- a/cmd/kraft/build/build.go +++ b/cmd/kraft/build/build.go @@ -11,6 +11,7 @@ import ( "os" "github.com/MakeNowJust/heredoc" + jujuerrors "github.com/juju/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -112,9 +113,9 @@ func (opts *Build) Pre(cmd *cobra.Command, args []string) error { // Initialize at least the configuration options for a project opts.project, err = app.NewProjectFromOptions(ctx, popts...) if err != nil && errors.Is(err, app.ErrNoKraftfile) { - return fmt.Errorf("cannot build project directory without a Kraftfile") + return jujuerrors.New("cannot build project directory without a Kraftfile") } else if err != nil { - return fmt.Errorf("could not initialize project directory: %w", err) + return jujuerrors.Annotate(err, "could not initialize project directory") } return nil @@ -146,11 +147,11 @@ func (opts *Build) pull(ctx context.Context, project app.Application, workdir st } if len(packages) == 0 { - return fmt.Errorf("could not find: %s", + return jujuerrors.Errorf("could not find: %s", unikraft.TypeNameVersion(opts.project.Template()), ) } else if len(packages) > 1 { - return fmt.Errorf("too many options for %s", + return jujuerrors.Errorf("too many options for %s", unikraft.TypeNameVersion(opts.project.Template()), ) } @@ -173,7 +174,7 @@ func (opts *Build) pull(ctx context.Context, project app.Application, workdir st } if err := treemodel.Start(); err != nil { - return fmt.Errorf("could not complete search: %v", err) + return jujuerrors.Annotate(err, "could not complete search") } proc := paraprogress.NewProcess( @@ -206,7 +207,7 @@ func (opts *Build) pull(ctx context.Context, project app.Application, workdir st } if err := paramodel.Start(); err != nil { - return fmt.Errorf("could not pull all components: %v", err) + return jujuerrors.Annotate(err, "could not pull all components") } } @@ -276,11 +277,11 @@ func (opts *Build) pull(ctx context.Context, project app.Application, workdir st } if len(p) == 0 { - return fmt.Errorf("could not find: %s", + return jujuerrors.Errorf("could not find: %s", unikraft.TypeNameVersion(component), ) } else if len(p) > 1 { - return fmt.Errorf("too many options for %s", + return jujuerrors.Errorf("too many options for %s", unikraft.TypeNameVersion(component), ) } @@ -306,7 +307,7 @@ func (opts *Build) pull(ctx context.Context, project app.Application, workdir st } if err := treemodel.Start(); err != nil { - return fmt.Errorf("could not complete search: %v", err) + return jujuerrors.Annotate(err, "could not complete search") } } @@ -344,7 +345,7 @@ func (opts *Build) pull(ctx context.Context, project app.Application, workdir st } if err := paramodel.Start(); err != nil { - return fmt.Errorf("could not pull all components: %v", err) + return jujuerrors.Annotate(err, "could not pull all components") } } @@ -374,7 +375,7 @@ func (opts *Build) Run(cmd *cobra.Command, args []string) error { } if len(selected) == 0 { - return fmt.Errorf("no targets selected to build") + return jujuerrors.New("no targets selected to build") } norender := log.LoggerTypeFromString(config.G[config.KraftKit](ctx).Log.Type) != log.FANCY diff --git a/cmd/kraft/events/events.go b/cmd/kraft/events/events.go index b7926deb5..2bfb13e7f 100644 --- a/cmd/kraft/events/events.go +++ b/cmd/kraft/events/events.go @@ -6,7 +6,6 @@ package events import ( "context" - "errors" "fmt" "os" "os/signal" @@ -15,6 +14,7 @@ import ( "time" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/spf13/cobra" machineapi "kraftkit.sh/api/machine/v1alpha1" @@ -78,7 +78,7 @@ func (opts *Events) Run(cmd *cobra.Command, args []string) error { platform, mode, err = mplatform.Detect(ctx) if mode == mplatform.SystemGuest { cancel() - return fmt.Errorf("nested virtualization not supported") + return errors.New("nested virtualization not supported") } else if err != nil { cancel() return err @@ -88,14 +88,14 @@ func (opts *Events) Run(cmd *cobra.Command, args []string) error { platform, ok = mplatform.PlatformsByName()[opts.platform] if !ok { cancel() - return fmt.Errorf("unknown platform driver: %s", opts.platform) + return errors.Errorf("unknown platform driver: %s", opts.platform) } } strategy, ok := mplatform.Strategies()[platform] if !ok { cancel() - return fmt.Errorf("unsupported platform driver: %s (contributions welcome!)", platform.String()) + return errors.Errorf("unsupported platform driver: %s (contributions welcome!)", platform.String()) } controller, err := strategy.NewMachineV1alpha1(ctx) @@ -116,7 +116,7 @@ func (opts *Events) Run(cmd *cobra.Command, args []string) error { pidfile, err = os.OpenFile(config.G[config.KraftKit](ctx).EventsPidFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o666) if err != nil { cancel() - return fmt.Errorf("could not create pidfile: %v", err) + return errors.Annotate(err, "could not create pidfile") } defer func() { @@ -130,12 +130,12 @@ func (opts *Events) Run(cmd *cobra.Command, args []string) error { if _, err := pidfile.Write([]byte(fmt.Sprintf("%d", os.Getpid()))); err != nil { cancel() - return fmt.Errorf("failed to write PID file: %w", err) + return errors.Annotate(err, "failed to write PID file") } if err := pidfile.Sync(); err != nil { cancel() - return fmt.Errorf("could not sync pid file: %v", err) + return errors.Annotate(err, "could not sync pid file") } } @@ -165,7 +165,7 @@ seek: machines, err := controller.List(ctx, &machineapi.MachineList{}) if err != nil { - return fmt.Errorf("could not list machines: %v", err) + return errors.Annotate(err, "could not list machines") } for _, machine := range machines.Items { diff --git a/cmd/kraft/fetch/fetch.go b/cmd/kraft/fetch/fetch.go index e062bc7df..c87f47e91 100644 --- a/cmd/kraft/fetch/fetch.go +++ b/cmd/kraft/fetch/fetch.go @@ -5,10 +5,10 @@ package fetch import ( - "fmt" "os" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/spf13/cobra" "kraftkit.sh/cmdfactory" @@ -109,7 +109,7 @@ func (opts *Fetch) Run(cmd *cobra.Command, args []string) error { t = targets[0] case config.G[config.KraftKit](ctx).NoPrompt: - return fmt.Errorf("could not determine which target to prepare") + return errors.New("could not determine which target to prepare") default: t, err = cli.SelectTarget(targets) diff --git a/cmd/kraft/login/login.go b/cmd/kraft/login/login.go index c8f92ff32..416df0879 100644 --- a/cmd/kraft/login/login.go +++ b/cmd/kraft/login/login.go @@ -14,6 +14,7 @@ import ( "kraftkit.sh/config" "kraftkit.sh/iostreams" + "github.com/juju/errors" "github.com/spf13/cobra" ) @@ -63,7 +64,7 @@ func (opts *Login) Run(cmd *cobra.Command, args []string) error { btoken, err := term.ReadPassword(int(iostreams.G(ctx).In.Fd())) if err != nil { - return fmt.Errorf("could not read password: %v", err) + return errors.Annotate(err, "could not read password") } fmt.Fprint(iostreams.G(ctx).Out, "\n") diff --git a/cmd/kraft/logs/logs.go b/cmd/kraft/logs/logs.go index a6defd49e..b57ac1ade 100644 --- a/cmd/kraft/logs/logs.go +++ b/cmd/kraft/logs/logs.go @@ -10,6 +10,7 @@ import ( "io" "os" + "github.com/juju/errors" "github.com/spf13/cobra" machineapi "kraftkit.sh/api/machine/v1alpha1" @@ -65,7 +66,7 @@ func (opts *Logs) Run(cmd *cobra.Command, args []string) error { var mode mplatform.SystemMode platform, mode, err = mplatform.Detect(ctx) if mode == mplatform.SystemGuest { - return fmt.Errorf("nested virtualization not supported") + return errors.New("nested virtualization not supported") } else if err != nil { return err } @@ -73,13 +74,13 @@ func (opts *Logs) Run(cmd *cobra.Command, args []string) error { var ok bool platform, ok = mplatform.PlatformsByName()[opts.platform] if !ok { - return fmt.Errorf("unknown platform driver: %s", opts.platform) + return errors.Errorf("unknown platform driver: %s", opts.platform) } } strategy, ok := mplatform.Strategies()[platform] if !ok { - return fmt.Errorf("unsupported platform driver: %s (contributions welcome!)", platform.String()) + return errors.Errorf("unsupported platform driver: %s (contributions welcome!)", platform.String()) } controller, err = strategy.NewMachineV1alpha1(ctx) @@ -106,7 +107,7 @@ func (opts *Logs) Run(cmd *cobra.Command, args []string) error { } if machine == nil { - return fmt.Errorf("could not find instance %s", args[0]) + return errors.Errorf("could not find instance %s", args[0]) } if opts.Follow && machine.Status.State == machineapi.MachineStateRunning { diff --git a/cmd/kraft/menu/menu.go b/cmd/kraft/menu/menu.go index aa2a176b1..682a0effd 100644 --- a/cmd/kraft/menu/menu.go +++ b/cmd/kraft/menu/menu.go @@ -5,10 +5,10 @@ package menu import ( - "fmt" "os" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/spf13/cobra" "kraftkit.sh/cmdfactory" @@ -112,7 +112,7 @@ func (opts *Menu) Run(cmd *cobra.Command, args []string) error { t = targets[0] case config.G[config.KraftKit](ctx).NoPrompt: - return fmt.Errorf("could not determine which target to prepare") + return errors.New("could not determine which target to prepare") default: t, err = cli.SelectTarget(targets) diff --git a/cmd/kraft/net/create/create.go b/cmd/kraft/net/create/create.go index 40bab8f75..975df06e9 100644 --- a/cmd/kraft/net/create/create.go +++ b/cmd/kraft/net/create/create.go @@ -8,6 +8,7 @@ import ( "fmt" "net" + "github.com/juju/errors" "github.com/spf13/cobra" "github.com/vishvananda/netlink" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -53,7 +54,7 @@ func (opts *Create) Pre(cmd *cobra.Command, _ []string) error { // return fmt.Errorf("cannot create network without subnet") // } if opts.Network == "" { - return fmt.Errorf("cannot create network without gateway and subnet in CIDR format") + return errors.New("cannot create network without gateway and subnet in CIDR format") } return nil @@ -66,7 +67,7 @@ func (opts *Create) Run(cmd *cobra.Command, args []string) error { strategy, ok := network.Strategies()[opts.driver] if !ok { - return fmt.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.driver) + return errors.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.driver) } controller, err := strategy.NewNetworkV1alpha1(ctx) diff --git a/cmd/kraft/net/down/down.go b/cmd/kraft/net/down/down.go index ec437628d..c56d831ac 100644 --- a/cmd/kraft/net/down/down.go +++ b/cmd/kraft/net/down/down.go @@ -7,6 +7,7 @@ package down import ( "fmt" + "github.com/juju/errors" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -46,7 +47,7 @@ func (opts *Down) Run(cmd *cobra.Command, args []string) error { ctx := cmd.Context() strategy, ok := network.Strategies()[opts.driver] if !ok { - return fmt.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.driver) + return errors.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.driver) } controller, err := strategy.NewNetworkV1alpha1(ctx) diff --git a/cmd/kraft/net/inspect/inspect.go b/cmd/kraft/net/inspect/inspect.go index b36ce4ea9..1303885af 100644 --- a/cmd/kraft/net/inspect/inspect.go +++ b/cmd/kraft/net/inspect/inspect.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" + "github.com/juju/errors" "github.com/spf13/cobra" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -50,7 +51,7 @@ func (opts *Inspect) Run(cmd *cobra.Command, args []string) error { strategy, ok := network.Strategies()[opts.Driver] if !ok { - return fmt.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.Driver) + return errors.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.Driver) } controller, err := strategy.NewNetworkV1alpha1(ctx) diff --git a/cmd/kraft/net/list/list.go b/cmd/kraft/net/list/list.go index 44f2b3cb0..983e4053c 100644 --- a/cmd/kraft/net/list/list.go +++ b/cmd/kraft/net/list/list.go @@ -5,11 +5,10 @@ package list import ( - "fmt" "net" + "github.com/juju/errors" "github.com/spf13/cobra" - networkapi "kraftkit.sh/api/network/v1alpha1" "kraftkit.sh/cmdfactory" "kraftkit.sh/internal/tableprinter" @@ -53,7 +52,7 @@ func (opts *List) Run(cmd *cobra.Command, args []string) error { strategy, ok := network.Strategies()[opts.driver] if !ok { - return fmt.Errorf("unsupported network driver strategy: %s", opts.driver) + return errors.Errorf("unsupported network driver strategy: %s", opts.driver) } controller, err := strategy.NewNetworkV1alpha1(ctx) diff --git a/cmd/kraft/net/net.go b/cmd/kraft/net/net.go index 43066e804..a5afdfdf0 100644 --- a/cmd/kraft/net/net.go +++ b/cmd/kraft/net/net.go @@ -5,8 +5,7 @@ package net import ( - "fmt" - + "github.com/juju/errors" "github.com/spf13/cobra" "kraftkit.sh/cmd/kraft/net/create" @@ -50,9 +49,9 @@ func New() *cobra.Command { func (opts *Net) Pre(cmd *cobra.Command, _ []string) error { if opts.Driver == "" { - return fmt.Errorf("network driver must be set") + return errors.New("network driver must be set") } else if !set.NewStringSet(network.DriverNames()...).Contains(opts.Driver) { - return fmt.Errorf("unsupported network driver strategy: %s", opts.Driver) + return errors.Errorf("unsupported network driver strategy: %s", opts.Driver) } return nil diff --git a/cmd/kraft/net/remove/remove.go b/cmd/kraft/net/remove/remove.go index 644e015eb..915cad5a3 100644 --- a/cmd/kraft/net/remove/remove.go +++ b/cmd/kraft/net/remove/remove.go @@ -7,6 +7,7 @@ package remove import ( "fmt" + "github.com/juju/errors" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -49,7 +50,7 @@ func (opts *Rm) Run(cmd *cobra.Command, args []string) error { strategy, ok := network.Strategies()[opts.driver] if !ok { - return fmt.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.driver) + return errors.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.driver) } controller, err := strategy.NewNetworkV1alpha1(ctx) diff --git a/cmd/kraft/net/up/up.go b/cmd/kraft/net/up/up.go index eaa82432e..2865eecd5 100644 --- a/cmd/kraft/net/up/up.go +++ b/cmd/kraft/net/up/up.go @@ -7,6 +7,7 @@ package up import ( "fmt" + "github.com/juju/errors" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -46,7 +47,7 @@ func (opts *Up) Run(cmd *cobra.Command, args []string) error { ctx := cmd.Context() strategy, ok := network.Strategies()[opts.driver] if !ok { - return fmt.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.driver) + return errors.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.driver) } controller, err := strategy.NewNetworkV1alpha1(ctx) diff --git a/cmd/kraft/pkg/pkg.go b/cmd/kraft/pkg/pkg.go index 9df0f5519..21a15663f 100644 --- a/cmd/kraft/pkg/pkg.go +++ b/cmd/kraft/pkg/pkg.go @@ -6,10 +6,10 @@ package pkg import ( "context" - "fmt" "os" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/mattn/go-shellwords" "github.com/spf13/cobra" @@ -86,7 +86,7 @@ func New() *cobra.Command { func (opts *Pkg) Pre(cmd *cobra.Command, _ []string) error { if (len(opts.Architecture) > 0 || len(opts.Platform) > 0) && len(opts.Target) > 0 { - return fmt.Errorf("the `--arch` and `--plat` options are not supported in addition to `--target`") + return errors.New("the `--arch` and `--plat` options are not supported in addition to `--target`") } ctx := cmd.Context() diff --git a/cmd/kraft/pkg/pull/pull.go b/cmd/kraft/pkg/pull/pull.go index 05fbf9e47..9ed497aa1 100644 --- a/cmd/kraft/pkg/pull/pull.go +++ b/cmd/kraft/pkg/pull/pull.go @@ -10,6 +10,7 @@ import ( "os" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/spf13/cobra" "kraftkit.sh/cmdfactory" @@ -160,9 +161,9 @@ func (opts *Pull) Run(cmd *cobra.Command, args []string) error { } if len(packages) == 0 { - return fmt.Errorf("could not find: %s", unikraft.TypeNameVersion(project.Template())) + return errors.Errorf("could not find: %s", unikraft.TypeNameVersion(project.Template())) } else if len(packages) > 1 { - return fmt.Errorf("too many options for %s", unikraft.TypeNameVersion(project.Template())) + return errors.Errorf("too many options for %s", unikraft.TypeNameVersion(project.Template())) } return nil }, @@ -182,7 +183,7 @@ func (opts *Pull) Run(cmd *cobra.Command, args []string) error { } if err := treemodel.Start(); err != nil { - return fmt.Errorf("could not complete search: %v", err) + return errors.Annotate(err, "could not complete search") } proc := paraprogress.NewProcess( @@ -214,7 +215,7 @@ func (opts *Pull) Run(cmd *cobra.Command, args []string) error { } if err := paramodel.Start(); err != nil { - return fmt.Errorf("could not pull all components: %v", err) + return errors.Annotate(err, "could not pull all components") } } diff --git a/cmd/kraft/prepare/prepare.go b/cmd/kraft/prepare/prepare.go index 9cedfc938..b2f6079d4 100644 --- a/cmd/kraft/prepare/prepare.go +++ b/cmd/kraft/prepare/prepare.go @@ -5,10 +5,10 @@ package prepare import ( - "fmt" "os" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/spf13/cobra" "kraftkit.sh/cmdfactory" @@ -109,7 +109,7 @@ func (opts *Prepare) Run(cmd *cobra.Command, args []string) error { t = targets[0] case config.G[config.KraftKit](ctx).NoPrompt: - return fmt.Errorf("could not determine which target to prepare") + return errors.New("could not determine which target to prepare") default: t, err = cli.SelectTarget(targets) diff --git a/cmd/kraft/ps/ps.go b/cmd/kraft/ps/ps.go index 11cdd4c8f..11badb3bf 100644 --- a/cmd/kraft/ps/ps.go +++ b/cmd/kraft/ps/ps.go @@ -17,6 +17,7 @@ import ( mplatform "kraftkit.sh/machine/platform" "github.com/dustin/go-humanize" + "github.com/juju/errors" "github.com/spf13/cobra" ) @@ -88,7 +89,7 @@ func (opts *Ps) Run(cmd *cobra.Command, args []string) error { var mode mplatform.SystemMode platform, mode, err = mplatform.Detect(ctx) if mode == mplatform.SystemGuest { - return fmt.Errorf("nested virtualization not supported") + return errors.New("nested virtualization not supported") } else if err != nil { return err } @@ -96,13 +97,13 @@ func (opts *Ps) Run(cmd *cobra.Command, args []string) error { var ok bool platform, ok = mplatform.PlatformsByName()[opts.platform] if !ok { - return fmt.Errorf("unknown platform driver: %s", opts.platform) + return errors.Errorf("unknown platform driver: %s", opts.platform) } } strategy, ok := mplatform.Strategies()[platform] if !ok { - return fmt.Errorf("unsupported platform driver: %s (contributions welcome!)", platform.String()) + return errors.Errorf("unsupported platform driver: %s (contributions welcome!)", platform.String()) } controller, err = strategy.NewMachineV1alpha1(ctx) diff --git a/cmd/kraft/rm/rm.go b/cmd/kraft/rm/rm.go index dc58d94cd..56ffaaf23 100644 --- a/cmd/kraft/rm/rm.go +++ b/cmd/kraft/rm/rm.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -71,7 +72,7 @@ func (opts *Rm) Run(cmd *cobra.Command, args []string) error { var mode mplatform.SystemMode platform, mode, err = mplatform.Detect(ctx) if mode == mplatform.SystemGuest { - return fmt.Errorf("nested virtualization not supported") + return errors.New("nested virtualization not supported") } else if err != nil { return err } @@ -79,13 +80,13 @@ func (opts *Rm) Run(cmd *cobra.Command, args []string) error { var ok bool platform, ok = mplatform.PlatformsByName()[opts.platform] if !ok { - return fmt.Errorf("unknown platform driver: %s", opts.platform) + return errors.Errorf("unknown platform driver: %s", opts.platform) } } strategy, ok := mplatform.Strategies()[platform] if !ok { - return fmt.Errorf("unsupported platform driver: %s (contributions welcome!)", platform.String()) + return errors.Errorf("unsupported platform driver: %s (contributions welcome!)", platform.String()) } controller, err = strategy.NewMachineV1alpha1(ctx) @@ -113,7 +114,7 @@ func (opts *Rm) Run(cmd *cobra.Command, args []string) error { } if len(remove) == 0 { - return fmt.Errorf("machine(s) not found") + return errors.New("machine(s) not found") } netcontrollers := make(map[string]networkapi.NetworkService, 0) @@ -127,7 +128,7 @@ func (opts *Rm) Run(cmd *cobra.Command, args []string) error { if !ok { strategy, ok := network.Strategies()[net.Driver] if !ok { - return fmt.Errorf("unknown machine network driver: %s", net.Driver) + return errors.Errorf("unknown machine network driver: %s", net.Driver) } netcontroller, err = strategy.NewNetworkV1alpha1(ctx) diff --git a/cmd/kraft/run/run.go b/cmd/kraft/run/run.go index ef79ce09d..f7e6e3db7 100644 --- a/cmd/kraft/run/run.go +++ b/cmd/kraft/run/run.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/rancher/wrangler/pkg/signals" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" @@ -125,9 +126,9 @@ func (opts *Run) Pre(cmd *cobra.Command, _ []string) error { // Discover the network controller strategy. if opts.Network == "" && opts.IP != "" { - return fmt.Errorf("cannot assign IP address without providing --network") + return errors.New("cannot assign IP address without providing --network") } else if opts.Network != "" && !strings.Contains(opts.Network, ":") { - return fmt.Errorf("specifying a network must be in the format : e.g. --network=bridge:kraft0") + return errors.New("specifying a network must be in the format : e.g. --network=bridge:kraft0") } if opts.Network != "" { @@ -138,7 +139,7 @@ func (opts *Run) Pre(cmd *cobra.Command, _ []string) error { networkStrategy, ok := network.Strategies()[opts.networkDriver] if !ok { - return fmt.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.networkDriver) + return errors.Errorf("unsupported network driver strategy: %v (contributions welcome!)", opts.networkDriver) } opts.networkController, err = networkStrategy.NewNetworkV1alpha1(ctx) @@ -155,7 +156,7 @@ func (opts *Run) Pre(cmd *cobra.Command, _ []string) error { var mode mplatform.SystemMode opts.platform, mode, err = mplatform.Detect(ctx) if mode == mplatform.SystemGuest { - return fmt.Errorf("nested virtualization not supported") + return errors.New("nested virtualization not supported") } else if err != nil { return err } @@ -163,13 +164,13 @@ func (opts *Run) Pre(cmd *cobra.Command, _ []string) error { var ok bool opts.platform, ok = mplatform.PlatformsByName()[plat] if !ok { - return fmt.Errorf("unknown platform driver: %s", opts.platform) + return errors.Errorf("unknown platform driver: %s", opts.platform) } } machineStrategy, ok := mplatform.Strategies()[opts.platform] if !ok { - return fmt.Errorf("unsupported platform driver: %s (contributions welcome!)", opts.platform.String()) + return errors.Errorf("unsupported platform driver: %s (contributions welcome!)", opts.platform.String()) } log.G(ctx).WithField("platform", opts.platform.String()).Debug("detected") @@ -200,7 +201,7 @@ func (opts *Run) Pre(cmd *cobra.Command, _ []string) error { i++ } - return fmt.Errorf("unknown runner: %s (choice of %v)", opts.RunAs, choices) + return errors.Errorf("unknown runner: %s (choice of %v)", opts.RunAs, choices) } } @@ -245,9 +246,9 @@ func (opts *Run) Run(cmd *cobra.Command, args []string) error { } } if run == nil && opts.RunAs != "" { - return fmt.Errorf("unknown runner: %s", opts.RunAs) + return errors.Errorf("unknown runner: %s", opts.RunAs) } else if run == nil { - return fmt.Errorf("could not determine how to run provided input") + return errors.New("could not determine how to run provided input") } log.G(ctx).WithField("runner", run.String()).Debug("using") @@ -296,13 +297,13 @@ func (opts *Run) Run(cmd *cobra.Command, args []string) error { } if err := os.MkdirAll(machine.Status.StateDir, 0o755); err != nil { - return fmt.Errorf("could not make machine state dir: %w", err) + return errors.Annotate(err, "could not make machine state dir") } var ramfs *initrd.InitrdConfig cwd, err := os.Getwd() if err != nil { - return fmt.Errorf("could not get current working directory: %w", err) + return errors.Annotate(err, "could not get current working directory") } if strings.Contains(opts.InitRd, initrd.InputDelimeter) { @@ -314,7 +315,7 @@ func (opts *Run) Run(cmd *cobra.Command, args []string) error { ramfs, err = initrd.NewFromMapping(cwd, output, opts.InitRd) if err != nil { - return fmt.Errorf("could not prepare initramfs: %w", err) + return errors.Annotate(err, "could not prepare initramfs") } } else if f, err := os.Stat(opts.InitRd); err == nil && f.IsDir() { output := filepath.Join(machine.Status.StateDir, "initramfs.cpio") @@ -325,12 +326,12 @@ func (opts *Run) Run(cmd *cobra.Command, args []string) error { ramfs, err = initrd.NewFromMapping(cwd, output, fmt.Sprintf("%s:/", opts.InitRd)) if err != nil { - return fmt.Errorf("could not prepare initramfs: %w", err) + return errors.Annotate(err, "could not prepare initramfs") } } else { ramfs, err = initrd.NewFromFile(cwd, opts.InitRd) if err != nil { - return fmt.Errorf("could not prepare initramfs: %w", err) + return errors.Annotate(err, "could not prepare initramfs") } } @@ -402,7 +403,7 @@ func (opts *Run) Run(cmd *cobra.Command, args []string) error { logs, errs, err := opts.machineController.Logs(ctx, machine) if err != nil { signals.RequestShutdown() - return fmt.Errorf("could not listen for machine logs: %v", err) + return errors.Annotate(err, "could not listen for machine logs") } loop: @@ -436,7 +437,7 @@ func (opts *Run) Run(cmd *cobra.Command, args []string) error { }, }) if err != nil { - return fmt.Errorf("could not get network information for %s: %v", opts.networkName, err) + return errors.Annotatef(err, "could not get network information for %s", opts.networkName) } // Remove the new network interface @@ -450,7 +451,7 @@ func (opts *Run) Run(cmd *cobra.Command, args []string) error { } if _, err = opts.networkController.Update(ctx, found); err != nil { - return fmt.Errorf("could not update network %s: %v", opts.networkName, err) + return errors.Annotatef(err, "could not update network %s", opts.networkName) } } diff --git a/cmd/kraft/run/runner_kernel.go b/cmd/kraft/run/runner_kernel.go index 9640af20d..c601d0e6f 100644 --- a/cmd/kraft/run/runner_kernel.go +++ b/cmd/kraft/run/runner_kernel.go @@ -7,9 +7,9 @@ package run import ( "context" "debug/elf" - "fmt" "path/filepath" + "github.com/juju/errors" machineapi "kraftkit.sh/api/machine/v1alpha1" "kraftkit.sh/unikraft" ) @@ -31,7 +31,7 @@ func (runner *runnerKernel) String() string { // Runnable implements Runner. func (runner *runnerKernel) Runnable(ctx context.Context, opts *Run, args ...string) (bool, error) { if len(args) == 0 { - return false, fmt.Errorf("no arguments supplied") + return false, errors.New("no arguments supplied") } var err error @@ -71,7 +71,7 @@ func (runner *runnerKernel) Prepare(ctx context.Context, opts *Run, machine *mac case elf.EM_AARCH64: machine.Spec.Architecture = "arm64" default: - return fmt.Errorf("unsupported kernel architecture: %v", fe.Machine.String()) + return errors.Errorf("unsupported kernel architecture: %v", fe.Machine.String()) } } else { machine.Spec.Architecture = opts.Architecture diff --git a/cmd/kraft/run/runner_linuxu.go b/cmd/kraft/run/runner_linuxu.go index 6edfccdb4..5959c9396 100644 --- a/cmd/kraft/run/runner_linuxu.go +++ b/cmd/kraft/run/runner_linuxu.go @@ -11,6 +11,7 @@ import ( "os" "path/filepath" + "github.com/juju/errors" machineapi "kraftkit.sh/api/machine/v1alpha1" "kraftkit.sh/config" "kraftkit.sh/log" @@ -42,7 +43,7 @@ func (runner *runnerLinuxu) String() string { // Runnable implements Runner. func (runner *runnerLinuxu) Runnable(ctx context.Context, opts *Run, args ...string) (bool, error) { if len(args) == 0 { - return false, fmt.Errorf("no arguments supplied") + return false, errors.New("no arguments supplied") } runner.exePath = args[0] @@ -52,24 +53,24 @@ func (runner *runnerLinuxu) Runnable(ctx context.Context, opts *Run, args ...str if err != nil { return false, err } else if fs.IsDir() { - return false, fmt.Errorf("first positional argument is a directory: %s", runner.exePath) + return false, errors.Errorf("first positional argument is a directory: %s", runner.exePath) } fi, err := os.Open(runner.exePath) if err != nil { - return false, fmt.Errorf("opening file %s: %w", runner.exePath, err) + return false, errors.Annotatef(err, "opening file %s", runner.exePath) } defer fi.Close() ef, err := elf.NewFile(fi) if err != nil { - return false, fmt.Errorf("reading ELF file %s: %w", runner.exePath, err) + return false, errors.Annotatef(err, "reading ELF file %s", runner.exePath) } // Both static and dynamic PIEs have this type. if ef.Type != elf.ET_DYN { - return false, fmt.Errorf("ELF file is shared object") + return false, errors.New("ELF file is shared object") } // Based on file(1) and elf.(*File).DynString. @@ -77,12 +78,12 @@ func (runner *runnerLinuxu) Runnable(ctx context.Context, opts *Run, args ...str // https://cs.opensource.google/go/go/+/refs/tags/go1.20.4:src/debug/elf/file.go;l=1602-1643 ds := ef.SectionByType(elf.SHT_DYNAMIC) if ds == nil { - return false, fmt.Errorf("ELF file has type %s but no dynamic section", ef.Type) + return false, errors.Errorf("ELF file has type %s but no dynamic section", ef.Type) } d, err := ds.Data() if err != nil { - return false, fmt.Errorf("reading ELF section %s of type %s", ds.Name, ds.Type) + return false, errors.Errorf("reading ELF section %s of type %s", ds.Name, ds.Type) } for len(d) > 0 { @@ -112,7 +113,7 @@ func (runner *runnerLinuxu) Runnable(ctx context.Context, opts *Run, args ...str } } - return false, fmt.Errorf("file is not ELF executable") + return false, errors.New("file is not ELF executable") } // Prepare implements Runner. diff --git a/cmd/kraft/run/runner_package.go b/cmd/kraft/run/runner_package.go index f60bc0344..cb3d7d8bb 100644 --- a/cmd/kraft/run/runner_package.go +++ b/cmd/kraft/run/runner_package.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" + "github.com/juju/errors" "k8s.io/apimachinery/pkg/util/uuid" machineapi "kraftkit.sh/api/machine/v1alpha1" "kraftkit.sh/config" @@ -46,7 +47,7 @@ func (runner *runnerPackage) String() string { // Runnable implements Runner. func (runner *runnerPackage) Runnable(ctx context.Context, opts *Run, args ...string) (bool, error) { if len(args) == 0 { - return false, fmt.Errorf("no arguments supplied") + return false, errors.New("no arguments supplied") } runner.packName = args[0] @@ -80,7 +81,7 @@ func (runner *runnerPackage) Prepare(ctx context.Context, opts *Run, machine *ma } if len(packs) > 1 { - return fmt.Errorf("could not determine what to run, too many options") + return errors.New("could not determine what to run, too many options") } else if len(packs) == 0 { // Second, try accessing the remote catalog packs, err = runner.pm.Catalog(ctx, @@ -93,9 +94,9 @@ func (runner *runnerPackage) Prepare(ctx context.Context, opts *Run, machine *ma } if len(packs) > 1 { - return fmt.Errorf("could not determine what to run, too many options") + return errors.New("could not determine what to run, too many options") } else if len(packs) == 0 { - return fmt.Errorf("not found: %s", runner.packName) + return errors.Errorf("not found: %s", runner.packName) } } @@ -146,7 +147,7 @@ func (runner *runnerPackage) Prepare(ctx context.Context, opts *Run, machine *ma // resolve application kernels. targ, ok := packs[0].(target.Target) if !ok { - return fmt.Errorf("package does not convert to target") + return errors.New("package does not convert to target") } machine.Spec.Architecture = targ.Architecture().Name() diff --git a/cmd/kraft/run/runner_project.go b/cmd/kraft/run/runner_project.go index 0b1ec4186..f8342fe5e 100644 --- a/cmd/kraft/run/runner_project.go +++ b/cmd/kraft/run/runner_project.go @@ -6,9 +6,9 @@ package run import ( "context" - "fmt" "os" + "github.com/juju/errors" machineapi "kraftkit.sh/api/machine/v1alpha1" "kraftkit.sh/config" "kraftkit.sh/internal/cli" @@ -40,7 +40,7 @@ func (runner *runnerProject) Runnable(ctx context.Context, opts *Run, args ...st cwd, err := os.Getwd() if err != nil { - return false, fmt.Errorf("getting current working directory: %w", err) + return false, errors.Annotate(err, "getting current working directory") } if len(args) == 0 { @@ -55,7 +55,7 @@ func (runner *runnerProject) Runnable(ctx context.Context, opts *Run, args ...st } if !app.IsWorkdirInitialized(runner.workdir) { - return false, fmt.Errorf("path is not project: %s", runner.workdir) + return false, errors.Errorf("path is not project: %s", runner.workdir) } return true, nil @@ -75,7 +75,7 @@ func (runner *runnerProject) Prepare(ctx context.Context, opts *Run, machine *ma project, err := app.NewProjectFromOptions(ctx, popts...) if err != nil { - return fmt.Errorf("could not instantiate project directory %s: %v", runner.workdir, err) + return errors.Errorf("could not instantiate project directory %s: %v", runner.workdir, err) } // Filter project targets by any provided CLI options @@ -90,18 +90,18 @@ func (runner *runnerProject) Prepare(ctx context.Context, opts *Run, machine *ma switch { case len(targets) == 0: - return fmt.Errorf("could not detect any project targets based on plat=\"%s\" arch=\"%s\"", opts.platform.String(), opts.Architecture) + return errors.Errorf("could not detect any project targets based on plat=\"%s\" arch=\"%s\"", opts.platform.String(), opts.Architecture) case len(targets) == 1: t = targets[0] case config.G[config.KraftKit](ctx).NoPrompt && len(targets) > 1: - return fmt.Errorf("could not determine what to run based on provided CLI arguments") + return errors.New("could not determine what to run based on provided CLI arguments") default: t, err = cli.SelectTarget(targets) if err != nil { - return fmt.Errorf("could not select target: %v", err) + return errors.Errorf("could not select target: %v", err) } } diff --git a/cmd/kraft/run/utils.go b/cmd/kraft/run/utils.go index e1f83b8bc..5141d90d9 100644 --- a/cmd/kraft/run/utils.go +++ b/cmd/kraft/run/utils.go @@ -2,9 +2,9 @@ package run import ( "context" - "fmt" "github.com/containerd/nerdctl/pkg/strutil" + "github.com/juju/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/uuid" machineapi "kraftkit.sh/api/machine/v1alpha1" @@ -104,7 +104,7 @@ func (opts *Run) assignName(ctx context.Context, machine *machineapi.Machine) er for _, found := range machines.Items { if opts.Name == found.Name { - return fmt.Errorf("machine instance name already in use: %s", opts.Name) + return errors.Errorf("machine instance name already in use: %s", opts.Name) } } diff --git a/cmd/kraft/set/set.go b/cmd/kraft/set/set.go index 27f01220e..42c47224f 100644 --- a/cmd/kraft/set/set.go +++ b/cmd/kraft/set/set.go @@ -37,6 +37,7 @@ import ( "strings" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/spf13/cobra" "kraftkit.sh/cmdfactory" @@ -96,7 +97,7 @@ func (opts *Set) Run(cmd *cobra.Command, args []string) error { // Skip if nothing can be set if len(args) == 0 { - return fmt.Errorf("no options to set") + return errors.New("no options to set") } // Set the working directory (remove the argument if it exists) @@ -112,7 +113,7 @@ func (opts *Set) Run(cmd *cobra.Command, args []string) error { // Set the configuration options, skip the first one if needed for _, arg := range args { if !strings.ContainsRune(arg, '=') || strings.HasSuffix(arg, "=") { - return fmt.Errorf("invalid or malformed argument: %s", arg) + return errors.Errorf("invalid or malformed argument: %s", arg) } confOpts = append(confOpts, arg) @@ -124,7 +125,7 @@ func (opts *Set) Run(cmd *cobra.Command, args []string) error { // Check if the file exists // TODO: offer option to start in interactive mode if _, err := os.Stat(dotconfig); os.IsNotExist(err) { - return fmt.Errorf("dotconfig file does not exist: %s", dotconfig) + return errors.Errorf("dotconfig file does not exist: %s", dotconfig) } popts := []app.ProjectOption{ diff --git a/cmd/kraft/stop/stop.go b/cmd/kraft/stop/stop.go index e9fc0a748..ac74f2c00 100644 --- a/cmd/kraft/stop/stop.go +++ b/cmd/kraft/stop/stop.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/spf13/cobra" machineapi "kraftkit.sh/api/machine/v1alpha1" @@ -49,7 +50,7 @@ func New() *cobra.Command { func (opts *Stop) Pre(cmd *cobra.Command, args []string) error { if len(args) == 0 && !opts.All { - return fmt.Errorf("please supply a machine ID or name or use the --all flag") + return errors.New("please supply a machine ID or name or use the --all flag") } opts.platform = cmd.Flag("plat").Value.String() @@ -58,7 +59,7 @@ func (opts *Stop) Pre(cmd *cobra.Command, args []string) error { func (opts *Stop) Run(cmd *cobra.Command, args []string) error { if len(args) == 0 && !opts.All { - return fmt.Errorf("please supply a machine ID or name or use the --all flag") + return errors.New("please supply a machine ID or name or use the --all flag") } var err error @@ -74,7 +75,7 @@ func (opts *Stop) Run(cmd *cobra.Command, args []string) error { var mode mplatform.SystemMode platform, mode, err = mplatform.Detect(ctx) if mode == mplatform.SystemGuest { - return fmt.Errorf("nested virtualization not supported") + return errors.New("nested virtualization not supported") } else if err != nil { return err } @@ -82,13 +83,13 @@ func (opts *Stop) Run(cmd *cobra.Command, args []string) error { var ok bool platform, ok = mplatform.PlatformsByName()[opts.platform] if !ok { - return fmt.Errorf("unknown platform driver: %s", opts.platform) + return errors.Errorf("unknown platform driver: %s", opts.platform) } } strategy, ok := mplatform.Strategies()[platform] if !ok { - return fmt.Errorf("unsupported platform driver: %s (contributions welcome!)", platform.String()) + return errors.Errorf("unsupported platform driver: %s (contributions welcome!)", platform.String()) } controller, err = strategy.NewMachineV1alpha1(ctx) @@ -116,7 +117,7 @@ func (opts *Stop) Run(cmd *cobra.Command, args []string) error { } if len(stop) == 0 { - return fmt.Errorf("machine(s) not found") + return errors.New("machine(s) not found") } for _, machine := range stop { diff --git a/cmd/kraft/unset/unset.go b/cmd/kraft/unset/unset.go index e1ba03091..baab205b6 100644 --- a/cmd/kraft/unset/unset.go +++ b/cmd/kraft/unset/unset.go @@ -36,6 +36,7 @@ import ( "os" "github.com/MakeNowJust/heredoc" + "github.com/juju/errors" "github.com/spf13/cobra" "kraftkit.sh/cmdfactory" @@ -94,7 +95,7 @@ func (opts *Unset) Run(cmd *cobra.Command, args []string) error { // Skip if nothing can be unset if len(args) == 0 { - return fmt.Errorf("no options to unset") + return errors.New("no options to unset") } // Set the working directory @@ -117,7 +118,7 @@ func (opts *Unset) Run(cmd *cobra.Command, args []string) error { // Check if the file exists // TODO: offer option to start in interactive mode if _, err := os.Stat(dotconfig); os.IsNotExist(err) { - return fmt.Errorf("dotconfig file does not exist: %s", dotconfig) + return errors.Errorf("dotconfig file does not exist: %s", dotconfig) } // Initialize at least the configuration options for a project diff --git a/cmdfactory/builder.go b/cmdfactory/builder.go index 3ed9bc7be..52f7c2a93 100644 --- a/cmdfactory/builder.go +++ b/cmdfactory/builder.go @@ -17,10 +17,13 @@ import ( "time" "unsafe" + jujuerrors "github.com/juju/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" "kraftkit.sh/internal/set" + "kraftkit.sh/iostreams" + "kraftkit.sh/log" ) var ( @@ -178,7 +181,11 @@ func Main(ctx context.Context, cmd *cobra.Command) { expandRegisteredFlags(cmd) if err := cmd.ExecuteContext(ctx); err != nil { - fmt.Println(err) + if set.NewStringSet("trace", "debug").Contains(log.G(ctx).Level.String()) { + fmt.Fprintln(iostreams.G(ctx).Out, jujuerrors.ErrorStack(err)) + } else { + fmt.Println(err) + } os.Exit(1) } } diff --git a/cmdfactory/errors.go b/cmdfactory/errors.go index 0f23f8923..137675c8a 100644 --- a/cmdfactory/errors.go +++ b/cmdfactory/errors.go @@ -4,16 +4,14 @@ package cmdfactory import ( - "errors" - "fmt" - "github.com/AlecAivazis/survey/v2/terminal" + "github.com/juju/errors" ) // FlagErrorf returns a new FlagError that wraps an error produced by // fmt.Errorf(format, args...). func FlagErrorf(format string, args ...interface{}) error { - return FlagErrorWrap(fmt.Errorf(format, args...)) + return FlagErrorWrap(errors.Errorf(format, args...)) } // FlagError returns a new FlagError that wraps the specified error. diff --git a/cmdfactory/flags_enum.go b/cmdfactory/flags_enum.go index 40638da87..e00d84797 100644 --- a/cmdfactory/flags_enum.go +++ b/cmdfactory/flags_enum.go @@ -5,8 +5,9 @@ package cmdfactory import ( - "fmt" "strings" + + "github.com/juju/errors" ) type EnumFlag struct { @@ -39,7 +40,7 @@ func (a *EnumFlag) Set(p string) error { } if !isIncluded(a.Allowed, p) { - return fmt.Errorf("%s is not included in: %s", p, strings.Join(a.Allowed, ", ")) + return errors.Errorf("%s is not included in: %s", p, strings.Join(a.Allowed, ", ")) } a.Value = p diff --git a/config/config_file.go b/config/config_file.go index 8bcb37927..a3bcda5ff 100644 --- a/config/config_file.go +++ b/config/config_file.go @@ -24,13 +24,13 @@ package config import ( - "errors" - "fmt" "io" "os" "path/filepath" "runtime" "syscall" + + "github.com/juju/errors" ) const ( @@ -229,7 +229,7 @@ func pathError(err error) error { var pathError *os.PathError if errors.As(err, &pathError) && errors.Is(pathError.Err, syscall.ENOTDIR) { if p := findRegularFile(pathError.Path); p != "" { - return fmt.Errorf("remove or rename regular file `%s` (must be a directory)", p) + return errors.Errorf("remove or rename regular file `%s` (must be a directory)", p) } } return err diff --git a/config/defaults.go b/config/defaults.go index 89128594c..475a56fcb 100644 --- a/config/defaults.go +++ b/config/defaults.go @@ -5,10 +5,11 @@ package config import ( - "fmt" "path/filepath" "reflect" "strconv" + + "github.com/juju/errors" ) const ( @@ -21,7 +22,7 @@ func NewDefaultKraftKitConfig() (*KraftKit, error) { c := &KraftKit{} if err := setDefaults(c); err != nil { - return nil, fmt.Errorf("could not set defaults for config: %s", err) + return nil, errors.Errorf("could not set defaults for config: %s", err) } // Add default path for plugins.. @@ -57,7 +58,7 @@ func setDefaults(s interface{}) error { func setDefaultValue(v reflect.Value, def string) error { if v.Kind() != reflect.Ptr { - return fmt.Errorf("not a pointer value") + return errors.New("not a pointer value") } v = reflect.Indirect(v) @@ -67,7 +68,7 @@ func setDefaultValue(v reflect.Value, def string) error { if len(def) > 0 { i, err := strconv.ParseInt(def, 10, 64) if err != nil { - return fmt.Errorf("could not parse default integer value: %s", err) + return errors.Errorf("could not parse default integer value: %s", err) } v.SetInt(i) } @@ -81,7 +82,7 @@ func setDefaultValue(v reflect.Value, def string) error { if len(def) > 0 { b, err := strconv.ParseBool(def) if err != nil { - return fmt.Errorf("could not parse default boolean value: %s", err) + return errors.Errorf("could not parse default boolean value: %s", err) } v.SetBool(b) } else { diff --git a/config/feeder_yaml.go b/config/feeder_yaml.go index c84f0481a..870e150b7 100644 --- a/config/feeder_yaml.go +++ b/config/feeder_yaml.go @@ -32,11 +32,11 @@ package config import ( - "fmt" "io" "os" "path/filepath" + "github.com/juju/errors" "gopkg.in/yaml.v3" "kraftkit.sh/internal/yamlmerger" @@ -50,7 +50,7 @@ type YamlFeeder struct { func (f YamlFeeder) Feed(structure interface{}) error { file, err := os.Open(filepath.Clean(f.File)) if err != nil { - return fmt.Errorf("cannot open yaml file: %v", err) + return errors.Annotate(err, "cannot open yaml file") } defer file.Close() @@ -66,7 +66,7 @@ func (f YamlFeeder) Feed(structure interface{}) error { } if err = yaml.NewDecoder(file).Decode(structure); err != nil { - return fmt.Errorf("cannot feed config file: %v", err) + return errors.Annotate(err, "cannot feed config file") } return nil @@ -74,7 +74,7 @@ func (f YamlFeeder) Feed(structure interface{}) error { func (yf YamlFeeder) Write(structure interface{}, merge bool) error { if len(yf.File) == 0 { - return fmt.Errorf("filename for YAML cannot be empty") + return errors.New("filename for YAML cannot be empty") } // Create parent directories if not present @@ -86,19 +86,19 @@ func (yf YamlFeeder) Write(structure interface{}, merge bool) error { // Open the file (create if not present) f, err := os.OpenFile(yf.File, os.O_RDWR|os.O_CREATE, 0o600) if err != nil { - return fmt.Errorf("could not open file: %v", err) + return errors.Annotate(err, "could not open file") } defer f.Close() data, err := io.ReadAll(f) if err != nil { - return fmt.Errorf("could not read file: %v", err) + return errors.Annotate(err, "could not read file") } from := yaml.Node{} if err := yaml.Unmarshal(data, &from); err != nil { - return fmt.Errorf("could not unmarshal YAML: %s", err) + return errors.Errorf("could not unmarshal YAML: %s", err) } yml, err := yaml.Marshal(structure) @@ -114,7 +114,7 @@ func (yf YamlFeeder) Write(structure interface{}, merge bool) error { // When kind is 0, it is an uninitialized YAML structure (aka empty file) if from.Kind != 0 && merge { if err := yamlmerger.RecursiveMerge(&from, &into); err != nil { - return fmt.Errorf("could not update config: %v", err) + return errors.Annotate(err, "could not update config") } } diff --git a/config/manager.go b/config/manager.go index 0f7e7dcfd..5e5bf1c45 100644 --- a/config/manager.go +++ b/config/manager.go @@ -5,12 +5,13 @@ package config import ( - "fmt" "os" "os/signal" "reflect" "strings" "syscall" + + "github.com/juju/errors" ) // ConfigManager uses the package facilities, there should be at least one @@ -34,7 +35,7 @@ func WithFile[C any](file string, forceCreate bool) ConfigManagerOption[C] { return func(cm *ConfigManager[C]) error { ext := strings.Split(file, ".") if len(ext) == 1 { - return fmt.Errorf("unknown file extension for config file: %s", file) + return errors.Errorf("unknown file extension for config file: %s", file) } _, err := os.Stat(file) @@ -47,12 +48,12 @@ func WithFile[C any](file string, forceCreate bool) ConfigManagerOption[C] { if os.IsNotExist(err) { err := yml.Write(cm.Config, forceCreate) if err != nil { - return fmt.Errorf("could not write initial config: %v", err) + return errors.Annotate(err, "could not write initial config") } } return WithFeeder[C](yml)(cm) default: - return fmt.Errorf("unsupported file extension: %s", file) + return errors.Errorf("unsupported file extension: %s", file) } } } @@ -65,7 +66,7 @@ func WithDefaultConfigFile[C any]() ConfigManagerOption[C] { func NewConfigManager[C any](c *C, opts ...ConfigManagerOption[C]) (*ConfigManager[C], error) { if c == nil { - return nil, fmt.Errorf("cannot instantiate ConfigManager without Config") + return nil, errors.New("cannot instantiate ConfigManager without Config") } cm := &ConfigManager[C]{ @@ -74,14 +75,14 @@ func NewConfigManager[C any](c *C, opts ...ConfigManagerOption[C]) (*ConfigManag for _, o := range opts { if err := o(cm); err != nil { - return nil, fmt.Errorf("could not apply config manager option: %v", err) + return nil, errors.Annotate(err, "could not apply config manager option") } } // Feed the config, pass the manager anyway if this fails, we still have // defaults if err := cm.Feed(); err != nil { - return cm, fmt.Errorf("could not feed config: %v", err) + return cm, errors.Annotate(err, "could not feed config") } return cm, nil @@ -141,7 +142,7 @@ func (cm *ConfigManager[C]) SetupListener(fallback func(err error)) *ConfigManag // feedStruct feeds a struct using given feeder. func (cm *ConfigManager[C]) feedStruct(f Feeder, s interface{}) error { if err := f.Feed(s); err != nil { - return fmt.Errorf("failed to feed config: %v", err) + return errors.Annotate(err, "failed to feed config") } return nil @@ -168,7 +169,7 @@ func Default[C any](key string) string { func findConfigDefault[C any](needle, offset, def string, v reflect.Value) (string, string, string, reflect.Value, error) { if v.Kind() != reflect.Ptr { - return needle, offset, def, v, fmt.Errorf("not a pointer value") + return needle, offset, def, v, errors.New("not a pointer value") } if needle == offset { @@ -202,5 +203,5 @@ func findConfigDefault[C any](needle, offset, def string, v reflect.Value) (stri } } - return needle, offset, def, v, fmt.Errorf("could not find default for: %s", needle) + return needle, offset, def, v, errors.Errorf("could not find default for: %s", needle) } diff --git a/exec/executable.go b/exec/executable.go index 9ac8da8a4..d0b9f739d 100644 --- a/exec/executable.go +++ b/exec/executable.go @@ -9,6 +9,8 @@ import ( "fmt" "reflect" "strings" + + "github.com/juju/errors" ) type Executable struct { @@ -24,7 +26,7 @@ type Executable struct { // what is passed to the flag. func NewExecutable(bin string, face interface{}, args ...string) (*Executable, error) { if len(bin) == 0 { - return nil, fmt.Errorf("binary argument cannot be empty") + return nil, errors.New("binary argument cannot be empty") } e := &Executable{} @@ -62,7 +64,7 @@ type flag struct { func parseFlag(tag reflect.StructTag) (*flag, error) { parts := strings.Split(tag.Get("flag"), ",") if len(parts) == 0 { - return nil, fmt.Errorf("could not parse flag without tag") + return nil, errors.New("could not parse flag without tag") } f := &flag{ @@ -74,7 +76,7 @@ func parseFlag(tag reflect.StructTag) (*flag, error) { case strings.HasPrefix(part, "omitvalueif"): omit := strings.Split(part, "=") if len(omit) == 1 { - return nil, fmt.Errorf("omitvalueif requires value") + return nil, errors.New("omitvalueif requires value") } f.omitvalueif = omit[1] @@ -90,7 +92,7 @@ func parseFlag(tag reflect.StructTag) (*flag, error) { // with tag annotations `flag` func ParseInterfaceArgs(face interface{}, args ...string) ([]string, error) { if face != nil && reflect.ValueOf(face).Kind() == reflect.Ptr { - return nil, fmt.Errorf("cannot derive interface arguments from pointer: passed by reference") + return nil, errors.New("cannot derive interface arguments from pointer: passed by reference") } t := reflect.TypeOf(face) diff --git a/exec/options.go b/exec/options.go index 52b190027..79a843231 100644 --- a/exec/options.go +++ b/exec/options.go @@ -7,6 +7,8 @@ package exec import ( "fmt" "io" + + "github.com/juju/errors" ) type ExecOptions struct { @@ -29,7 +31,7 @@ func NewExecOptions(eopts ...ExecOption) (*ExecOptions, error) { for _, o := range eopts { if err := o(eo); err != nil { - return nil, fmt.Errorf("could not apply option: %v", err) + return nil, errors.Annotate(err, "could not apply option") } } diff --git a/exec/process.go b/exec/process.go index d64d74210..525d8ebb9 100644 --- a/exec/process.go +++ b/exec/process.go @@ -6,13 +6,13 @@ package exec import ( "context" - "fmt" "io" "os" "os/exec" "strings" "syscall" + "github.com/juju/errors" "kraftkit.sh/log" ) @@ -39,7 +39,7 @@ func NewProcess(bin string, args []string, eopts ...ExecOption) (*Process, error // *Executable object and optional execution options func NewProcessFromExecutable(executable *Executable, eopts ...ExecOption) (*Process, error) { if executable == nil { - return nil, fmt.Errorf("cannot prepare process without executable") + return nil, errors.New("cannot prepare process without executable") } opts, err := NewExecOptions(eopts...) @@ -119,7 +119,7 @@ func (e *Process) Start(ctx context.Context) error { } if err := e.cmd.Start(); err != nil { - return fmt.Errorf("could not start process: %v", err) + return errors.Annotate(err, "could not start process") } return nil @@ -128,7 +128,7 @@ func (e *Process) Start(ctx context.Context) error { // Wait for the process to complete func (e *Process) Wait() error { if e.cmd == nil { - return fmt.Errorf("process has not yet started cannot wait") + return errors.New("process has not yet started cannot wait") } err := e.cmd.Wait() @@ -171,7 +171,7 @@ func (e *Process) Kill() error { // Pid returns the process ID func (e *Process) Pid() (int, error) { if e.cmd == nil || e.cmd.Process == nil || e.cmd.Process.Pid == -1 { - return -1, fmt.Errorf("could not locate pid") + return -1, errors.New("could not locate pid") } return e.cmd.Process.Pid, nil diff --git a/go.mod b/go.mod index 4653f7787..5a00ba54a 100644 --- a/go.mod +++ b/go.mod @@ -143,6 +143,7 @@ require ( github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/juju/errors v1.0.0 github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.16.5 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect diff --git a/go.sum b/go.sum index 168e674ee..a5946d34c 100644 --- a/go.sum +++ b/go.sum @@ -650,6 +650,8 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/juju/errors v1.0.0 h1:yiq7kjCLll1BiaRuNY53MGI0+EQ3rF6GB+wvboZDefM= +github.com/juju/errors v1.0.0/go.mod h1:B5x9thDqx0wIMH3+aLIMP9HjItInYWObRovoCFM5Qe8= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= diff --git a/initrd/initrd.go b/initrd/initrd.go index 866beab5a..a1cb38069 100644 --- a/initrd/initrd.go +++ b/initrd/initrd.go @@ -6,7 +6,6 @@ package initrd import ( "errors" - "fmt" "io" "io/fs" "os" @@ -16,6 +15,7 @@ import ( "kraftkit.sh/utils" "github.com/cavaliergopher/cpio" + jujuerrors "github.com/juju/errors" ) const InputDelimeter = ":" @@ -86,26 +86,26 @@ func NewFromFile(workdir, path string) (*InitrdConfig, error) { func (i *InitrdConfig) NewWriter(w io.Writer) (*cpio.Writer, error) { switch i.Format { case ODC: - return nil, fmt.Errorf("unsupported CPIO format: odc") + return nil, errors.New("unsupported CPIO format: odc") case NEWC: return cpio.NewWriter(w), nil case USTAR: - return nil, fmt.Errorf("unsupported CPIO format: ustar") + return nil, errors.New("unsupported CPIO format: ustar") default: - return nil, fmt.Errorf("unknown CPIO format") + return nil, errors.New("unknown CPIO format") } } func (i *InitrdConfig) NewReader(w io.Reader) (*cpio.Reader, error) { switch i.Format { case ODC: - return nil, fmt.Errorf("unsupported CPIO format: odc") + return nil, errors.New("unsupported CPIO format: odc") case NEWC: return cpio.NewReader(w), nil case USTAR: - return nil, fmt.Errorf("unsupported CPIO format: ustar") + return nil, errors.New("unsupported CPIO format: ustar") default: - return nil, fmt.Errorf("unknown CPIO format") + return nil, errors.New("unknown CPIO format") } } @@ -122,7 +122,7 @@ func NewFromPath(base string, prefix string, files ...string) (*InitrdConfig, er prefix = "/" } if !strings.HasPrefix(prefix, "/") { - return nil, fmt.Errorf("must use absolute path in prefix: %s", prefix) + return nil, jujuerrors.Errorf("must use absolute path in prefix: %s", prefix) } for _, file := range files { @@ -147,7 +147,7 @@ func NewFromMapping(workdir, output string, maps ...string) (*InitrdConfig, erro f, err := os.OpenFile(output, os.O_RDWR|os.O_CREATE, 0o644) if err != nil { - return nil, fmt.Errorf("could not open initramfs file: %w", err) + return nil, jujuerrors.Annotate(err, "could not open initramfs file") } writer := cpio.NewWriter(f) @@ -156,7 +156,7 @@ func NewFromMapping(workdir, output string, maps ...string) (*InitrdConfig, erro for _, mapping := range maps { split := strings.Split(mapping, InputDelimeter) if len(split) != 2 { - return nil, fmt.Errorf("could not parse mapping '%s': must be in format :", mapping) + return nil, jujuerrors.Errorf("could not parse mapping '%s': must be in format :", mapping) } hostPath := utils.RelativePath(workdir, split[0]) @@ -164,7 +164,7 @@ func NewFromMapping(workdir, output string, maps ...string) (*InitrdConfig, erro f, err := os.Stat(hostPath) if err != nil && errors.Is(err, os.ErrNotExist) { - return nil, fmt.Errorf("path does not exist: %s", hostPath) + return nil, jujuerrors.Errorf("path does not exist: %s", hostPath) } else if err == nil && f.IsDir() { // The provided mapping is a directory, lets iterate over each path if err := filepath.WalkDir(hostPath, func(path string, d fs.DirEntry, err error) error { diff --git a/internal/cli/options.go b/internal/cli/options.go index 215053d5a..ba2659289 100644 --- a/internal/cli/options.go +++ b/internal/cli/options.go @@ -5,11 +5,11 @@ package cli import ( - "fmt" "net/http" "os" "path/filepath" + "github.com/juju/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -206,11 +206,11 @@ func WithDefaultHTTPClient() CliOption { } if copts.ConfigManager == nil { - return fmt.Errorf("cannot access config manager") + return errors.New("cannot access config manager") } if copts.IOStreams == nil { - return fmt.Errorf("cannot access IO streams") + return errors.New("cannot access IO streams") } httpClient, err := httpclient.NewHTTPClient( @@ -236,7 +236,7 @@ func WithDefaultPluginManager() CliOption { } if copts.ConfigManager == nil { - return fmt.Errorf("cannot access config manager") + return errors.New("cannot access config manager") } copts.PluginManager = plugins.NewPluginManager(copts.ConfigManager.Config.Paths.Plugins, nil) diff --git a/internal/cli/target.go b/internal/cli/target.go index 7574842e1..8a9321456 100644 --- a/internal/cli/target.go +++ b/internal/cli/target.go @@ -10,6 +10,7 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/erikgeiser/promptkit/selection" + "github.com/juju/errors" "kraftkit.sh/unikraft/target" ) @@ -50,7 +51,7 @@ func SelectTarget(targets []target.Target) (target.Target, error) { } } - return nil, fmt.Errorf("could not select target") + return nil, errors.New("could not select target") } // FilterTargets returns a subset of `targets` based in input strings `arch`, diff --git a/internal/ghrepo/repo.go b/internal/ghrepo/repo.go index 00906c9e3..82fc000f0 100644 --- a/internal/ghrepo/repo.go +++ b/internal/ghrepo/repo.go @@ -33,6 +33,7 @@ import ( "strings" "github.com/cli/cli/v2/git" + "github.com/juju/errors" ) // Interface describes an object that represents a GitHub repository @@ -51,12 +52,12 @@ func New(owner, repo string) Interface { func NewFromURL(path string) (Interface, error) { u, err := url.Parse(path) if err != nil { - return nil, fmt.Errorf("could not parse url: %s", err) + return nil, errors.Errorf("could not parse url: %s", err) } parts := strings.Split(u.Path, "/") if len(parts) != 3 { - return nil, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, path) + return nil, errors.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, path) } owner := parts[1] @@ -115,7 +116,7 @@ func FromFullNameWithHost(nwo, fallbackHost string) (Interface, error) { parts := strings.SplitN(nwo, "/", 4) for _, p := range parts { if len(p) == 0 { - return nil, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, nwo) + return nil, errors.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, nwo) } } switch len(parts) { @@ -124,19 +125,19 @@ func FromFullNameWithHost(nwo, fallbackHost string) (Interface, error) { case 2: return NewWithHost(parts[0], parts[1], fallbackHost), nil default: - return nil, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, nwo) + return nil, errors.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, nwo) } } // FromURL extracts the GitHub repository information from a git remote URL func FromURL(u *url.URL) (Interface, error) { if u.Hostname() == "" { - return nil, fmt.Errorf("no hostname detected") + return nil, errors.New("no hostname detected") } parts := strings.SplitN(strings.Trim(u.Path, "/"), "/", 3) if len(parts) != 2 { - return nil, fmt.Errorf("invalid path: %s", u.Path) + return nil, errors.Errorf("invalid path: %s", u.Path) } return NewWithHost(parts[0], strings.TrimSuffix(parts[1], ".git"), u.Hostname()), nil diff --git a/internal/run/stub.go b/internal/run/stub.go index bfbf5951b..215b1bbf5 100644 --- a/internal/run/stub.go +++ b/internal/run/stub.go @@ -29,6 +29,8 @@ import ( "path/filepath" "regexp" "strings" + + "github.com/juju/errors" ) type T interface { @@ -127,7 +129,7 @@ type commandStub struct { // Run satisfies Runnable func (s *commandStub) Run() error { if s.exitStatus != 0 { - return fmt.Errorf("%s exited with status %d", s.pattern, s.exitStatus) + return errors.Errorf("%s exited with status %d", s.pattern, s.exitStatus) } return nil } @@ -135,7 +137,7 @@ func (s *commandStub) Run() error { // Output satisfies Runnable func (s *commandStub) Output() ([]byte, error) { if s.exitStatus != 0 { - return []byte(nil), fmt.Errorf("%s exited with status %d", s.pattern, s.exitStatus) + return []byte(nil), errors.Errorf("%s exited with status %d", s.pattern, s.exitStatus) } return []byte(s.stdout), nil } diff --git a/internal/tableprinter/tableprinter_options.go b/internal/tableprinter/tableprinter_options.go index 9e1bbdbbe..3d2b0c135 100644 --- a/internal/tableprinter/tableprinter_options.go +++ b/internal/tableprinter/tableprinter_options.go @@ -1,6 +1,8 @@ package tableprinter -import "fmt" +import ( + "github.com/juju/errors" +) // TablePrinterOption is a type of func(*TablePrinter). type TablePrinterOption func(*TablePrinter) error @@ -19,7 +21,7 @@ func WithOutputFormat(format TableOutputFormat) TablePrinterOption { func WithOutputFormatFromString(format string) TablePrinterOption { return func(opts *TablePrinter) error { if format == "" { - return fmt.Errorf("unsupported table printer format: %s", format) + return errors.Errorf("unsupported table printer format: %s", format) } opts.format = TableOutputFormat(format) return nil diff --git a/internal/yamlmerger/yamlmerger.go b/internal/yamlmerger/yamlmerger.go index a9ea4962d..e4c6aa304 100644 --- a/internal/yamlmerger/yamlmerger.go +++ b/internal/yamlmerger/yamlmerger.go @@ -24,15 +24,14 @@ package yamlmerger import ( - "fmt" - + "github.com/juju/errors" "gopkg.in/yaml.v3" ) // https://stackoverflow.com/a/65784135 func RecursiveMerge(from, into *yaml.Node) error { if from.Kind != into.Kind { - return fmt.Errorf("cannot merge nodes of different kinds") + return errors.New("cannot merge nodes of different kinds") } switch from.Kind { @@ -43,7 +42,7 @@ func RecursiveMerge(from, into *yaml.Node) error { if nodesEqual(from.Content[i], into.Content[j]) { found = true if err := RecursiveMerge(from.Content[i+1], into.Content[j+1]); err != nil { - return fmt.Errorf("at key " + from.Content[i].Value + ": " + err.Error()) + return errors.Errorf("at key " + from.Content[i].Value + ": " + err.Error()) } break } @@ -74,7 +73,7 @@ func RecursiveMerge(from, into *yaml.Node) error { return err } default: - return fmt.Errorf("can only merge mapping, sequence and scalar nodes") + return errors.New("can only merge mapping, sequence and scalar nodes") } return nil diff --git a/kconfig/config.go b/kconfig/config.go index a866096ce..ece4217b1 100644 --- a/kconfig/config.go +++ b/kconfig/config.go @@ -12,6 +12,8 @@ import ( "os" "regexp" "strings" + + "github.com/juju/errors" ) const DotConfigFileName = ".config" @@ -86,7 +88,7 @@ func (kvm KeyValueMap) OverrideBy(other KeyValueMap) KeyValueMap { func NewKeyValueMapFromFile(file string) (KeyValueMap, error) { f, err := os.Open(file) if err != nil { - return nil, fmt.Errorf("could not open file: %v", err) + return nil, errors.Annotate(err, "could not open file") } defer f.Close() @@ -353,7 +355,7 @@ func (cf *DotConfigFile) Serialize() []byte { func ParseConfig(file string) (*DotConfigFile, error) { data, err := os.ReadFile(file) if err != nil { - return nil, fmt.Errorf("failed to open .config file %v: %v", file, err) + return nil, errors.Annotatef(err, "failed to open .config file %v", file) } return ParseConfigData(data) diff --git a/kconfig/kconfig.go b/kconfig/kconfig.go index 67e132833..7e3576685 100644 --- a/kconfig/kconfig.go +++ b/kconfig/kconfig.go @@ -10,11 +10,12 @@ package kconfig import ( - "fmt" "os" "path/filepath" "strings" "sync" + + "github.com/juju/errors" ) // KConfigFile represents a parsed Kconfig file (including includes). @@ -128,7 +129,7 @@ type kconfigParser struct { func Parse(file string, env ...*KeyValue) (*KConfigFile, error) { data, err := os.ReadFile(file) if err != nil { - return nil, fmt.Errorf("failed to open Kconfig file %v: %v", file, err) + return nil, errors.Annotatef(err, "failed to open Kconfig file %v", file) } return ParseData(data, file, env...) } @@ -149,7 +150,7 @@ func ParseData(data []byte, file string, extra ...*KeyValue) (*KConfigFile, erro } if len(kp.stack) == 0 { - return nil, fmt.Errorf("no mainmenu in config") + return nil, errors.New("no mainmenu in config") } root := kp.stack[0] diff --git a/kconfig/parser.go b/kconfig/parser.go index c55d3238c..aeb163dba 100644 --- a/kconfig/parser.go +++ b/kconfig/parser.go @@ -12,6 +12,8 @@ import ( "fmt" "os/exec" "strings" + + "github.com/juju/errors" ) // parser is a helper for parsing simple text protocols tailored for kconfig syntax. @@ -87,7 +89,7 @@ func (p *parser) identLevel() int { func (p *parser) failf(msg string, args ...interface{}) { if p.err == nil { - p.err = fmt.Errorf("%v:%v:%v: %v\n%v", p.file, p.line, p.col, fmt.Sprintf(msg, args...), p.current) + p.err = errors.Errorf("%v:%v:%v: %v\n%v", p.file, p.line, p.col, fmt.Sprintf(msg, args...), p.current) } } diff --git a/machine/firecracker/v1alpha1.go b/machine/firecracker/v1alpha1.go index 81a5b33a5..326dcfbbf 100644 --- a/machine/firecracker/v1alpha1.go +++ b/machine/firecracker/v1alpha1.go @@ -6,7 +6,6 @@ package firecracker import ( "context" - "fmt" "os" "path/filepath" "strings" @@ -17,6 +16,7 @@ import ( firecracker "github.com/firecracker-microvm/firecracker-go-sdk" "github.com/firecracker-microvm/firecracker-go-sdk/client/models" "github.com/fsnotify/fsnotify" + "github.com/juju/errors" goprocess "github.com/shirou/gopsutil/v3/process" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" @@ -71,11 +71,11 @@ func NewMachineV1alpha1Service(ctx context.Context, opts ...any) (machinev1alpha func (service *machineV1alpha1Service) Create(ctx context.Context, machine *machinev1alpha1.Machine) (*machinev1alpha1.Machine, error) { // Start with fail-safe checks for unsupported specification declarations. if len(machine.Spec.Ports) > 0 { - return machine, fmt.Errorf("kraftkit does not yet support port forwarding to firecracker (contributions welcome): please use a network instead") + return machine, errors.New("kraftkit does not yet support port forwarding to firecracker (contributions welcome): please use a network instead") } if machine.Status.KernelPath == "" { - return machine, fmt.Errorf("cannot create firecracker instance without kernel") + return machine, errors.New("cannot create firecracker instance without kernel") } if machine.ObjectMeta.UID == "" { @@ -153,7 +153,7 @@ func (service *machineV1alpha1Service) Create(ctx context.Context, machine *mach ApiSock: fccfg.SocketPath, }) if err != nil { - return machine, fmt.Errorf("could not prepare firecracker executable: %v", err) + return machine, errors.Annotate(err, "could not prepare firecracker executable") } process, err := exec.NewProcessFromExecutable(e, @@ -161,7 +161,7 @@ func (service *machineV1alpha1Service) Create(ctx context.Context, machine *mach exec.WithDetach(true), ) if err != nil { - return machine, fmt.Errorf("could not prepare firecracker process: %v", err) + return machine, errors.Annotate(err, "could not prepare firecracker process") } machine.CreationTimestamp = metav1.NewTime(time.Now()) @@ -182,7 +182,7 @@ func (service *machineV1alpha1Service) Create(ctx context.Context, machine *mach // Start and also wait for the process to be released, this ensures the // program is actively being executed. if err := process.Start(ctx); err != nil { - return machine, fmt.Errorf("could not start and wait for firecracker process: %v", err) + return machine, errors.Annotate(err, "could not start and wait for firecracker process") } // Wait for the socket file to be created @@ -204,7 +204,7 @@ watch: pid, err := process.Pid() if err != nil { - return machine, fmt.Errorf("could not get firecracker pid: %v", err) + return machine, errors.Annotate(err, "could not get firecracker pid") } client := firecracker.NewClient(fccfg.SocketPath, logrus.NewEntry(log.G(ctx)), false) @@ -316,7 +316,7 @@ func getFirecrackerConfigFromPlatformConfig(platformConfig interface{}) (*Firecr return &fccfg, nil } - return nil, fmt.Errorf("could not cast firecracker platform config from store") + return nil, errors.New("could not cast firecracker platform config from store") } // Update implements kraftkit.sh/api/machine/v1alpha1.MachineService @@ -461,7 +461,7 @@ func (service *machineV1alpha1Service) Get(ctx context.Context, machine *machine // We cannot amend the status at this point, even if the process is // alive, since it is not an indicator of the state of the VM, only of the // VMM. So we return what we already know via LookupMachineConfig. - return machine, fmt.Errorf("could not query machine status via API socket: %v", err) + return machine, errors.Annotate(err, "could not query machine status via API socket") } cancel() diff --git a/machine/name/id.go b/machine/name/id.go index 0d2648a32..6b54b2b95 100644 --- a/machine/name/id.go +++ b/machine/name/id.go @@ -11,6 +11,8 @@ import ( "regexp" "strconv" "strings" + + "github.com/juju/errors" ) // MachineID is a 16 byte universally unique identifier. @@ -93,7 +95,7 @@ func NewRandomMachineID() (MachineID, error) { // MachineID. func ValidateMachineID(id string) error { if ok := validHex.MatchString(id); !ok { - return fmt.Errorf("image ID %q is invalid", id) + return errors.Errorf("image ID %q is invalid", id) } return nil diff --git a/machine/network/bridge/utils.go b/machine/network/bridge/utils.go index 477c4f4e9..570af8a81 100644 --- a/machine/network/bridge/utils.go +++ b/machine/network/bridge/utils.go @@ -3,12 +3,12 @@ package bridge import ( "context" "encoding/binary" - "fmt" "math/big" "net" "time" "github.com/erikh/ping" + "github.com/juju/errors" "github.com/vishvananda/netlink" "kraftkit.sh/internal/set" ) @@ -59,7 +59,7 @@ func BridgeIPs(bridge *netlink.Bridge) ([]string, error) { list, err = netlink.NeighList(bridge.Index, netlink.FAMILY_V4) if err != nil { - return nil, fmt.Errorf("cannot retrieve IPv4 neighbor information for interface %s: %v", bridge.Name, err) + return nil, errors.Annotatef(err, "cannot retrieve IPv4 neighbor information for interface %s", bridge.Name) } ips := make([]string, len(list)) @@ -92,7 +92,7 @@ search: select { case <-ctx.Done(): - return nil, fmt.Errorf("context cancelled") + return nil, errors.New("context cancelled") default: } @@ -100,7 +100,7 @@ search: // If the IP is not within the provided network, it is not possible to // increment the IP so return with an error. case !ipnet.Contains(ip): - return nil, fmt.Errorf("could not allocate IP address in %v", ipnet.String()) + return nil, errors.Errorf("could not allocate IP address in %v", ipnet.String()) // Skip the Bridge IP. case func() bool { diff --git a/machine/network/bridge/v1alpha1.go b/machine/network/bridge/v1alpha1.go index ec30ddf6c..54ca92d0e 100644 --- a/machine/network/bridge/v1alpha1.go +++ b/machine/network/bridge/v1alpha1.go @@ -14,6 +14,7 @@ import ( "unicode" "github.com/erikh/ping" + "github.com/juju/errors" "github.com/vishvananda/netlink" "github.com/vishvananda/netlink/nl" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -32,7 +33,7 @@ func NewNetworkServiceV1alpha1(ctx context.Context, opts ...any) (networkv1alpha // Create implements kraftkit.sh/api/network/v1alpha1.Create func (service *v1alpha1Network) Create(ctx context.Context, network *networkv1alpha1.Network) (*networkv1alpha1.Network, error) { if network.Name == "" { - return nil, fmt.Errorf("cannot create network without name") + return nil, errors.New("cannot create network without name") } if network.ObjectMeta.UID == "" { @@ -48,10 +49,10 @@ func (service *v1alpha1Network) Create(ctx context.Context, network *networkv1al // Validate the options. if len(network.Spec.Gateway) == 0 { - return network, fmt.Errorf("gateway cannot be empty") + return network, errors.New("gateway cannot be empty") } if len(network.Spec.Netmask) == 0 { - return network, fmt.Errorf("netmask cannot be empty") + return network, errors.New("netmask cannot be empty") } bridge := &netlink.Bridge{ @@ -63,9 +64,9 @@ func (service *v1alpha1Network) Create(ctx context.Context, network *networkv1al _, err := net.InterfaceByName(network.Name) if err == nil { // Bridge already exists, return early. - return network, fmt.Errorf("network already exists: %s", network.Name) + return network, errors.Errorf("network already exists: %s", network.Name) } else if !strings.Contains(err.Error(), "no such network interface") { - return network, fmt.Errorf("getting interface %s failed: %v", network.Name, err) + return network, errors.Annotatef(err, "getting interface %s failed", network.Name) } // Create the bridge. @@ -74,7 +75,7 @@ func (service *v1alpha1Network) Create(ctx context.Context, network *networkv1al la.MTU = bridge.MTU br := &netlink.Bridge{LinkAttrs: la} if err := netlink.LinkAdd(br); err != nil { - return network, fmt.Errorf("bridge creation for %s failed: %v", network.Name, err) + return network, errors.Annotatef(err, "bridge creation for %s failed", network.Name) } // br.Promisc = 1 // TODO(nderjung): Should the bridge be promiscuous? @@ -87,19 +88,19 @@ func (service *v1alpha1Network) Create(ctx context.Context, network *networkv1al }, } if err := netlink.AddrAdd(br, addr); err != nil { - return network, fmt.Errorf("adding address %s to bridge %s failed: %v", addr.String(), network.Name, err) + return network, errors.Annotatef(err, "adding address %s to bridge %s failed", addr.String(), network.Name) } // Bring the bridge up. if err := netlink.LinkSetUp(br); err != nil { - return network, fmt.Errorf("bringing bridge %s up failed: %v", network.Name, err) + return network, errors.Annotatef(err, "bringing bridge %s up failed", network.Name) } network.CreationTimestamp = metav1.Now() link, err := netlink.LinkByName(network.Name) if err != nil { - return network, fmt.Errorf("could not get bridge %s details: %v", network.Name, err) + return network, errors.Annotatef(err, "could not get bridge %s details", network.Name) } // Use the internal network bridge networking system to determine @@ -159,23 +160,23 @@ func (service *v1alpha1Network) Start(ctx context.Context, network *networkv1alp for _, iface := range network.Spec.Interfaces { link, err := netlink.LinkByName(iface.Spec.IfName) if err != nil { - return network, fmt.Errorf("getting link %s failed: %v", network.Name, err) + return network, errors.Annotatef(err, "getting link %s failed", network.Name) } if err := netlink.LinkSetUp(link); err != nil { - return network, fmt.Errorf("could not bring %s link down: %v", network.Name, err) + return network, errors.Annotatef(err, "could not bring %s link down", network.Name) } } // Get the bridge link. link, err := netlink.LinkByName(network.Name) if err != nil { - return network, fmt.Errorf("getting bridge %s failed: %v", network.Name, err) + return network, errors.Annotatef(err, "getting bridge %s failed", network.Name) } // Bring up the bridge link if err := netlink.LinkSetUp(link); err != nil { - return network, fmt.Errorf("could not bring %s link up: %v", network.Name, err) + return network, errors.Annotatef(err, "could not bring %s link up", network.Name) } network.Status.State = networkv1alpha1.NetworkStateUp @@ -189,27 +190,27 @@ func (service *v1alpha1Network) Stop(ctx context.Context, network *networkv1alph for _, iface := range network.Spec.Interfaces { link, err := netlink.LinkByName(iface.Spec.IfName) if err != nil { - return network, fmt.Errorf("getting link %s failed: %v", iface.Spec.IfName, err) + return network, errors.Annotatef(err, "getting link %s failed", iface.Spec.IfName) } if ping.Ping(&net.IPAddr{IP: net.ParseIP(iface.Spec.IP), Zone: ""}, 150*time.Millisecond) { - return network, fmt.Errorf("interface still in use: %s (%s, %s)", iface.Spec.IfName, iface.Spec.MacAddress, iface.Spec.IP) + return network, errors.Errorf("interface still in use: %s (%s, %s)", iface.Spec.IfName, iface.Spec.MacAddress, iface.Spec.IP) } if err := netlink.LinkSetDown(link); err != nil { - return network, fmt.Errorf("could not bring %s link down: %v", iface.Spec.IfName, err) + return network, errors.Annotatef(err, "could not bring %s link down", iface.Spec.IfName) } } // Get the bridge link. link, err := netlink.LinkByName(network.Name) if err != nil { - return network, fmt.Errorf("getting bridge %s failed: %v", network.Name, err) + return network, errors.Annotatef(err, "getting bridge %s failed", network.Name) } // Bring down the bridge link if err := netlink.LinkSetDown(link); err != nil { - return network, fmt.Errorf("could not bring %s bridge down: %v", network.Name, err) + return network, errors.Annotatef(err, "could not bring %s bridge down", network.Name) } network.Status.State = networkv1alpha1.NetworkStateDown @@ -222,17 +223,17 @@ func (service *v1alpha1Network) Stop(ctx context.Context, network *networkv1alph func (service *v1alpha1Network) Update(ctx context.Context, network *networkv1alpha1.Network) (*networkv1alpha1.Network, error) { link, err := netlink.LinkByName(network.Name) if err != nil { - return network, fmt.Errorf("could not get bridge link: %v", err) + return network, errors.Annotate(err, "could not get bridge link") } bridge, ok := link.(*netlink.Bridge) if !ok { - return network, fmt.Errorf("network link is not bridge") + return network, errors.New("network link is not bridge") } bridgeface, err := net.InterfaceByName(bridge.Name) if err != nil { - return nil, fmt.Errorf("could not get bridge interface: %v", err) + return nil, errors.Annotate(err, "could not get bridge interface") } ipnet := &net.IPNet{ @@ -243,7 +244,7 @@ func (service *v1alpha1Network) Update(ctx context.Context, network *networkv1al // Start MAC addresses iteratively. startMac, err := macaddr.GenerateMacAddress(true) if err != nil { - return network, fmt.Errorf("could not prepare MAC address generator: %v", err) + return network, errors.Annotate(err, "could not prepare MAC address generator") } // Populate a hashmap of link aliases that allow us to quickly reference later @@ -282,7 +283,7 @@ func (service *v1alpha1Network) Update(ctx context.Context, network *networkv1al if iface.Spec.IP == "" { ip, err := AllocateIP(ctx, ipnet, bridgeface, bridge) if err != nil { - return network, fmt.Errorf("could not allocate interface IP for %s: %v", iface.Spec.IfName, err) + return network, errors.Annotatef(err, "could not allocate interface IP for %s", iface.Spec.IfName) } iface.Spec.IP = ip.String() @@ -299,15 +300,15 @@ func (service *v1alpha1Network) Update(ctx context.Context, network *networkv1al if existing, err := netlink.LinkByName(tap.Name); err == nil { if existing.Attrs().Flags&net.FlagRunning != 0 { if err = netlink.LinkSetDown(tap); err != nil { - return network, fmt.Errorf("could not bring %s link down: %v", iface.Spec.IfName, err) + return network, errors.Annotatef(err, "could not bring %s link down", iface.Spec.IfName) } if err := netlink.LinkModify(tap); err != nil { - return network, fmt.Errorf("could not update %s link: %v", iface.Spec.IfName, err) + return network, errors.Annotatef(err, "could not update %s link", iface.Spec.IfName) } } } else { if err := netlink.LinkAdd(tap); err != nil { - return network, fmt.Errorf("could not create %s link: %v", iface.Spec.IfName, err) + return network, errors.Annotatef(err, "could not create %s link", iface.Spec.IfName) } } @@ -315,11 +316,11 @@ func (service *v1alpha1Network) Update(ctx context.Context, network *networkv1al // combination of the network and this interface. alias := fmt.Sprintf("%s:%s", network.ObjectMeta.UID, iface.ObjectMeta.UID) if err := netlink.LinkSetAlias(tap, alias); err != nil { - return network, fmt.Errorf("could not set link alias: %v", err) + return network, errors.Annotatef(err, "could not set link alias") } if err = netlink.LinkSetUp(tap); err != nil { - return network, fmt.Errorf("could not bring %s link up: %v", iface.Spec.IfName, err) + return network, errors.Annotatef(err, "could not bring %s link up", iface.Spec.IfName) } inuse[alias] = true @@ -329,7 +330,7 @@ func (service *v1alpha1Network) Update(ctx context.Context, network *networkv1al // Clean up any removed interfaces. Re-check the link list. links, err := netlink.LinkList() if err != nil { - return network, fmt.Errorf("could not gather list of existing links: %v", err) + return network, errors.Annotate(err, "could not gather list of existing links") } for _, link := range links { @@ -343,11 +344,11 @@ func (service *v1alpha1Network) Update(ctx context.Context, network *networkv1al } if err = netlink.LinkSetDown(tap); err != nil { - return network, fmt.Errorf("could not bring %s link down: %v", tap.Name, err) + return network, errors.Annotatef(err, "could not bring %s link down", tap.Name) } if err = netlink.LinkDel(tap); err != nil { - return network, fmt.Errorf("could not remove %s: %v", tap.Name, err) + return network, errors.Annotatef(err, "could not remove %s", tap.Name) } } @@ -361,38 +362,38 @@ func (service *v1alpha1Network) Delete(ctx context.Context, network *networkv1al // Get the link. link, err := netlink.LinkByName(iface.Spec.IfName) if err != nil { - return network, fmt.Errorf("could not get %s link: %v", iface.Spec.IfName, err) + return network, errors.Annotatef(err, "could not get %s link", iface.Spec.IfName) } if ping.Ping(&net.IPAddr{IP: net.ParseIP(iface.Spec.IP), Zone: ""}, 150*time.Millisecond) { - return network, fmt.Errorf("interface still in use: %s (%s, %s)", iface.Spec.IfName, iface.Spec.MacAddress, iface.Spec.IP) + return network, errors.Errorf("interface still in use: %s (%s, %s)", iface.Spec.IfName, iface.Spec.MacAddress, iface.Spec.IP) } // Bring down the bridge link if err := netlink.LinkSetDown(link); err != nil { - return network, fmt.Errorf("could not bring %s link down: %v", iface.Spec.IfName, err) + return network, errors.Annotatef(err, "could not bring %s link down", iface.Spec.IfName) } // Delete the bridge link. if err := netlink.LinkDel(link); err != nil { - return network, fmt.Errorf("could not delete %s link: %v", iface.Spec.IfName, err) + return network, errors.Annotatef(err, "could not delete %s link", iface.Spec.IfName) } } // Get the bridge link. link, err := netlink.LinkByName(network.Name) if err != nil { - return network, fmt.Errorf("getting bridge %s failed: %v", network.Name, err) + return network, errors.Annotatef(err, "getting bridge %s failed", network.Name) } // Bring down the bridge link if err := netlink.LinkSetDown(link); err != nil { - return network, fmt.Errorf("could not bring %s link down: %v", network.Name, err) + return network, errors.Annotatef(err, "could not bring %s link down", network.Name) } // Delete the bridge link. if err := netlink.LinkDel(link); err != nil { - return network, fmt.Errorf("could not delete %s link: %v", network.Name, err) + return network, errors.Annotatef(err, "could not delete %s link", network.Name) } return nil, nil @@ -429,7 +430,7 @@ func mapBridgeStatistics(network *networkv1alpha1.Network, bridge *netlink.Bridg func (service *v1alpha1Network) Get(ctx context.Context, network *networkv1alpha1.Network) (*networkv1alpha1.Network, error) { link, err := netlink.LinkByName(network.Name) if err != nil { - return network, fmt.Errorf("could not get link %s: %v", network.Name, err) + return network, errors.Annotatef(err, "could not get link %s", network.Name) } if network.ObjectMeta.CreationTimestamp == *new(metav1.Time) { @@ -438,7 +439,7 @@ func (service *v1alpha1Network) Get(ctx context.Context, network *networkv1alpha bridge, ok := link.(*netlink.Bridge) if !ok { - return network, fmt.Errorf("network link is not bridge") + return network, errors.New("network link is not bridge") } addrs, err := netlink.AddrList(bridge, nl.FAMILY_V4) diff --git a/machine/platform/detect.go b/machine/platform/detect.go index c557254fd..534a38071 100644 --- a/machine/platform/detect.go +++ b/machine/platform/detect.go @@ -7,12 +7,12 @@ package platform import ( "bufio" "context" - "fmt" "io" "os" "path/filepath" "strings" + "github.com/juju/errors" "kraftkit.sh/internal/set" ) @@ -149,5 +149,5 @@ func Detect(ctx context.Context) (Platform, SystemMode, error) { } } - return PlatformUnknown, SystemUnknown, fmt.Errorf("could not determine hypervisor and system mode") + return PlatformUnknown, SystemUnknown, errors.Errorf("could not determine hypervisor and system mode") } diff --git a/machine/platform/filter.go b/machine/platform/filter.go index 01e66c2d6..d330f7b71 100644 --- a/machine/platform/filter.go +++ b/machine/platform/filter.go @@ -6,9 +6,9 @@ package platform import ( "context" - "fmt" zip "api.zip" + "github.com/juju/errors" machinev1alpha1 "kraftkit.sh/api/machine/v1alpha1" ) @@ -38,7 +38,7 @@ func storePlatformFilter(platform Platform) zip.OnBefore { obj := req.(*zip.Object[machinev1alpha1.MachineSpec, machinev1alpha1.MachineStatus]) if obj.Spec.Platform != platform.String() { - return nil, fmt.Errorf("machine is not %s instance: %s", platform.String(), obj.Name) + return nil, errors.Errorf("machine is not %s instance: %s", platform.String(), obj.Name) } return obj, nil diff --git a/machine/platform/iterator_v1alpha1.go b/machine/platform/iterator_v1alpha1.go index 8c65621da..6b1da0b51 100644 --- a/machine/platform/iterator_v1alpha1.go +++ b/machine/platform/iterator_v1alpha1.go @@ -6,10 +6,10 @@ package platform import ( "context" - "fmt" zip "api.zip" "github.com/acorn-io/baaah/pkg/merr" + "github.com/juju/errors" machinev1alpha1 "kraftkit.sh/api/machine/v1alpha1" ) @@ -53,7 +53,7 @@ func (iterator *machineV1alpha1ServiceIterator) Create(ctx context.Context, mach return ret, nil } - return machine, fmt.Errorf("all iterated platforms failed: %w", merr.NewErrors(errs...)) + return machine, errors.Annotate(merr.NewErrors(errs...), "all iterated platforms failed") } // Start implements kraftkit.sh/api/machine/v1alpha1.MachineService @@ -70,7 +70,7 @@ func (iterator *machineV1alpha1ServiceIterator) Start(ctx context.Context, machi return ret, nil } - return machine, fmt.Errorf("all iterated platforms failed: %w", merr.NewErrors(errs...)) + return machine, errors.Annotate(merr.NewErrors(errs...), "all iterated platforms failed") } // Pause implements kraftkit.sh/api/machine/v1alpha1.MachineService @@ -87,7 +87,7 @@ func (iterator *machineV1alpha1ServiceIterator) Pause(ctx context.Context, machi return ret, nil } - return machine, fmt.Errorf("all iterated platforms failed: %w", merr.NewErrors(errs...)) + return machine, errors.Annotate(merr.NewErrors(errs...), "all iterated platforms failed: %w") } // Stop implements kraftkit.sh/api/machine/v1alpha1.MachineService @@ -104,7 +104,7 @@ func (iterator *machineV1alpha1ServiceIterator) Stop(ctx context.Context, machin return ret, nil } - return machine, fmt.Errorf("all iterated platforms failed: %w", merr.NewErrors(errs...)) + return machine, errors.Annotate(merr.NewErrors(errs...), "all iterated platforms failed") } // Update implements kraftkit.sh/api/machine/v1alpha1.MachineService @@ -121,7 +121,7 @@ func (iterator *machineV1alpha1ServiceIterator) Update(ctx context.Context, mach return ret, nil } - return machine, fmt.Errorf("all iterated platforms failed: %w", merr.NewErrors(errs...)) + return machine, errors.Annotate(merr.NewErrors(errs...), "all iterated platforms failed") } // Delete implements kraftkit.sh/api/machine/v1alpha1.MachineService @@ -138,7 +138,7 @@ func (iterator *machineV1alpha1ServiceIterator) Delete(ctx context.Context, mach return ret, nil } - return machine, fmt.Errorf("all iterated platforms failed: %w", merr.NewErrors(errs...)) + return machine, errors.Annotate(merr.NewErrors(errs...), "all iterated platforms failed") } // Get implements kraftkit.sh/api/machine/v1alpha1.MachineService @@ -155,7 +155,7 @@ func (iterator *machineV1alpha1ServiceIterator) Get(ctx context.Context, machine return ret, nil } - return machine, fmt.Errorf("all iterated platforms failed: %w", merr.NewErrors(errs...)) + return machine, errors.Annotate(merr.NewErrors(errs...), "all iterated platforms failed") } // List implements kraftkit.sh/api/machine/v1alpha1.MachineService @@ -190,7 +190,7 @@ func (iterator *machineV1alpha1ServiceIterator) Watch(ctx context.Context, machi return eventChan, errChan, nil } - return nil, nil, fmt.Errorf("all iterated platforms failed: %w", merr.NewErrors(errs...)) + return nil, nil, errors.Annotate(merr.NewErrors(errs...), "all iterated platforms failed") } // Logs implements kraftkit.sh/api/machine/v1alpha1.MachineService @@ -207,5 +207,5 @@ func (iterator *machineV1alpha1ServiceIterator) Logs(ctx context.Context, machin return logChan, errChan, nil } - return nil, nil, fmt.Errorf("all iterated platforms failed: %w", merr.NewErrors(errs...)) + return nil, nil, errors.Annotate(merr.NewErrors(errs...), "all iterated platforms failed") } diff --git a/machine/qemu/qemu_hostchardev.go b/machine/qemu/qemu_hostchardev.go index d0a626b43..bae4c1210 100644 --- a/machine/qemu/qemu_hostchardev.go +++ b/machine/qemu/qemu_hostchardev.go @@ -10,6 +10,8 @@ import ( "path/filepath" "strconv" "strings" + + "github.com/juju/errors" ) type QemuHostCharDev interface { @@ -51,7 +53,7 @@ func (cd QemuHostCharDevVirtualConsole) Resource() string { } func (cd QemuHostCharDevVirtualConsole) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevVirtualConsole.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevVirtualConsole.Connection") } type QemuHostCharDevPty struct{} @@ -65,7 +67,7 @@ func (cd QemuHostCharDevPty) Resource() string { } func (cd QemuHostCharDevPty) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevPty.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevPty.Connection") } type QemuHostCharDevNone struct{} @@ -79,7 +81,7 @@ func (cd QemuHostCharDevNone) Resource() string { } func (cd QemuHostCharDevNone) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevNone.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevNone.Connection") } type QemuHostCharDevNull struct{} @@ -94,7 +96,7 @@ func (cd QemuHostCharDevNull) Resource() string { } func (cd QemuHostCharDevNull) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevNull.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevNull.Connection") } type QemuHostCharDevNamed struct { @@ -125,7 +127,7 @@ func (cd QemuHostCharDevNamed) Resource() string { } func (cd QemuHostCharDevNamed) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevNamed.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevNamed.Connection") } type QemuHostCharDevTty struct { @@ -158,7 +160,7 @@ func (cd QemuHostCharDevTty) Resource() string { } func (cd QemuHostCharDevTty) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevTty.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevTty.Connection") } type QemuHostCharDevFile struct { @@ -189,7 +191,7 @@ func (cd QemuHostCharDevFile) Resource() string { } func (cd QemuHostCharDevFile) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevFile.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevFile.Connection") } type QemuHostCharDevStdio struct { @@ -213,7 +215,7 @@ func (cd QemuHostCharDevStdio) Resource() string { } func (cd QemuHostCharDevStdio) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevStdio.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevStdio.Connection") } type QemuHostCharDevPipe struct { @@ -244,7 +246,7 @@ func (cd QemuHostCharDevPipe) Resource() string { } func (cd QemuHostCharDevPipe) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevPipe.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevPipe.Connection") } type QemuHostCharDevUDP struct { @@ -296,7 +298,7 @@ func (cd QemuHostCharDevUDP) Resource() string { } func (cd QemuHostCharDevUDP) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevUDP.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevUDP.Connection") } const ( @@ -359,7 +361,7 @@ func (cd QemuHostCharDevTCP) Resource() string { } func (cd QemuHostCharDevTCP) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevTCP.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevTCP.Connection") } type QemuHostCharDevTelnet struct { @@ -412,7 +414,7 @@ func (cd QemuHostCharDevTelnet) Resource() string { } func (cd QemuHostCharDevTelnet) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevTelnet.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevTelnet.Connection") } type QemuHostCharDevWebsocket struct { @@ -464,7 +466,7 @@ func (cd QemuHostCharDevWebsocket) Resource() string { } func (cd QemuHostCharDevWebsocket) Connection() (net.Conn, error) { - return nil, fmt.Errorf("not implemented: machine.qemu.QemuHostCharDevWebsocket.Connection") + return nil, errors.New("not implemented: machine.qemu.QemuHostCharDevWebsocket.Connection") } type QemuHostCharDevUnix struct { diff --git a/machine/qemu/qemu_version.go b/machine/qemu/qemu_version.go index 6a2dd2da6..18461a772 100644 --- a/machine/qemu/qemu_version.go +++ b/machine/qemu/qemu_version.go @@ -8,10 +8,10 @@ import ( "bufio" "bytes" "context" - "fmt" "strings" "github.com/Masterminds/semver/v3" + "github.com/juju/errors" "kraftkit.sh/exec" ) @@ -32,7 +32,7 @@ func GetQemuVersionFromBin(ctx context.Context, bin string) (*semver.Version, er Version: true, }) if err != nil { - return nil, fmt.Errorf("could not prepare QEMU executable: %v", err) + return nil, errors.Annotate(err, "could not prepare QEMU executable") } var buf bytes.Buffer @@ -41,13 +41,13 @@ func GetQemuVersionFromBin(ctx context.Context, bin string) (*semver.Version, er exec.WithStdout(bufio.NewWriter(&buf)), ) if err != nil { - return nil, fmt.Errorf("could not prepare QEMU process: %v", err) + return nil, errors.Annotate(err, "could not prepare QEMU process") } // Start and also wait for the process to be released, this ensures the // program is actively being executed. if err := process.StartAndWait(ctx); err != nil { - return nil, fmt.Errorf("could not start and wait for QEMU process: %v", err) + return nil, errors.Annotate(err, "could not start and wait for QEMU process") } // Get the first line of the returned value @@ -55,7 +55,7 @@ func GetQemuVersionFromBin(ctx context.Context, bin string) (*semver.Version, er // Check if the returned value has the magic words if !strings.HasPrefix(ret, "QEMU emulator version ") { - return nil, fmt.Errorf("malformed return value cannot parse QEMU version") + return nil, errors.New("malformed return value cannot parse QEMU version") } ret = strings.TrimPrefix(ret, "QEMU emulator version ") diff --git a/machine/qemu/qmp/events.go b/machine/qemu/qmp/events.go index 4be338a30..6abb6cef0 100644 --- a/machine/qemu/qmp/events.go +++ b/machine/qemu/qmp/events.go @@ -34,12 +34,11 @@ package qmp import ( "bufio" "encoding/json" - "errors" - "fmt" "io" "reflect" "time" + "github.com/juju/errors" "kraftkit.sh/utils" ) @@ -101,7 +100,7 @@ func (em *QMPEventMonitor[T]) Accept() (*QMPEvent[T], error) { } if !found { - return nil, fmt.Errorf("unknown QMP event type: %s", typ) + return nil, errors.Errorf("unknown QMP event type: %s", typ) } return &QMPEvent[T]{ diff --git a/machine/qemu/qmp/v1alpha/service.pb.netconn.go b/machine/qemu/qmp/v1alpha/service.pb.netconn.go index b4539f384..9f708b97e 100644 --- a/machine/qemu/qmp/v1alpha/service.pb.netconn.go +++ b/machine/qemu/qmp/v1alpha/service.pb.netconn.go @@ -6,10 +6,11 @@ package qmpv1alpha import ( "bufio" "encoding/json" - "fmt" "io" "reflect" "sync" + + jujuerrors "github.com/juju/errors" ) type QEMUMachineProtocolClient struct { @@ -58,7 +59,7 @@ func (c *QEMUMachineProtocolClient) setRpcRequestSetDefaults(face any) error { case reflect.String: f.SetString(def) default: - return fmt.Errorf("unsupported default kind: %s", f.Kind().String()) + return jujuerrors.Errorf("unsupported default kind: %s", f.Kind().String()) } } diff --git a/machine/qemu/v1alpha1.go b/machine/qemu/v1alpha1.go index 0acacf06b..5c69ae505 100644 --- a/machine/qemu/v1alpha1.go +++ b/machine/qemu/v1alpha1.go @@ -18,6 +18,7 @@ import ( zip "api.zip" "github.com/acorn-io/baaah/pkg/merr" + jujuerrors "github.com/juju/errors" "github.com/mitchellh/mapstructure" goprocess "github.com/shirou/gopsutil/v3/process" corev1 "k8s.io/api/core/v1" @@ -69,11 +70,11 @@ func NewMachineV1alpha1Service(ctx context.Context, opts ...any) (machinev1alpha // Create implements kraftkit.sh/api/machine/v1alpha1.MachineService.Create func (service *machineV1alpha1Service) Create(ctx context.Context, machine *machinev1alpha1.Machine) (*machinev1alpha1.Machine, error) { if machine.Status.KernelPath == "" { - return machine, fmt.Errorf("empty kernel path") + return machine, jujuerrors.New("empty kernel path") } if _, err := os.Stat(machine.Status.KernelPath); err != nil && os.IsNotExist(err) { - return machine, fmt.Errorf("supplied kernel path does not exist: %s", machine.Status.KernelPath) + return machine, jujuerrors.Errorf("supplied kernel path does not exist: %s", machine.Status.KernelPath) } var bin string @@ -84,7 +85,7 @@ func (service *machineV1alpha1Service) Create(ctx context.Context, machine *mach case "arm": bin = QemuSystemArm default: - return nil, fmt.Errorf("unsupported architecture: %s", machine.Spec.Architecture) + return nil, jujuerrors.Errorf("unsupported architecture: %s", machine.Spec.Architecture) } // Determine the version of QEMU so as to both determine whether it is a @@ -95,7 +96,7 @@ func (service *machineV1alpha1Service) Create(ctx context.Context, machine *mach } if qemuVersion.LessThan(QemuVersion4_2_0) { - return machine, fmt.Errorf("unsupported QEMU version: %s: please upgrade to a newer version", qemuVersion.String()) + return machine, jujuerrors.Errorf("unsupported QEMU version: %s: please upgrade to a newer version", qemuVersion.String()) } if machine.ObjectMeta.UID == "" { @@ -341,7 +342,7 @@ func (service *machineV1alpha1Service) Create(ctx context.Context, machine *mach ) default: - return nil, fmt.Errorf("unsupported architecture: %s", machine.Spec.Architecture) + return nil, jujuerrors.Errorf("unsupported architecture: %s", machine.Spec.Architecture) } // Create a log file just for the QEMU process which can be used to debug @@ -361,7 +362,7 @@ func (service *machineV1alpha1Service) Create(ctx context.Context, machine *mach qcfg, err := NewQemuConfig(qopts...) if err != nil { machine.Status.State = machinev1alpha1.MachineStateFailed - return machine, fmt.Errorf("could not generate QEMU config: %v", err) + return machine, jujuerrors.Annotate(err, "could not generate QEMU config") } machine.Status.PlatformConfig = *qcfg @@ -369,13 +370,13 @@ func (service *machineV1alpha1Service) Create(ctx context.Context, machine *mach e, err := exec.NewExecutable(bin, *qcfg) if err != nil { machine.Status.State = machinev1alpha1.MachineStateFailed - return machine, fmt.Errorf("could not prepare QEMU executable: %v", err) + return machine, jujuerrors.Annotate(err, "could not prepare QEMU executable") } process, err := exec.NewProcessFromExecutable(e, service.eopts...) if err != nil { machine.Status.State = machinev1alpha1.MachineStateFailed - return machine, fmt.Errorf("could not prepare QEMU process: %v", err) + return machine, jujuerrors.Annotate(err, "could not prepare QEMU process") } machine.CreationTimestamp = metav1.Now() @@ -387,10 +388,10 @@ func (service *machineV1alpha1Service) Create(ctx context.Context, machine *mach // Propagate the contents of the QEMU log file as an error if errLog, err2 := os.ReadFile(qemuLogFile); err2 == nil { - err = errors.Join(fmt.Errorf(strings.TrimSpace(string(errLog))), err) + err = errors.Join(jujuerrors.Errorf(strings.TrimSpace(string(errLog))), err) } - return machine, fmt.Errorf("could not start and wait for QEMU process: %v", err) + return machine, jujuerrors.Annotate(err, "could not start and wait for QEMU process") } machine.Status.State = machinev1alpha1.MachineStateCreated @@ -483,17 +484,17 @@ func (service *machineV1alpha1Service) QMPClient(ctx context.Context, machine *m func processFromPidFile(pidFile string) (*goprocess.Process, error) { pidData, err := os.ReadFile(pidFile) if err != nil { - return nil, fmt.Errorf("could not read pid file: %v", err) + return nil, jujuerrors.Annotate(err, "could not read pid file") } pid, err := strconv.ParseUint(strings.TrimSpace(string(pidData)), 10, 64) if err != nil { - return nil, fmt.Errorf("could not convert pid string \"%s\" to uint64: %v", pidData, err) + return nil, jujuerrors.Annotatef(err, "could not convert pid string \"%s\" to uint64", pidData) } process, err := goprocess.NewProcess(int32(pid)) if err != nil { - return nil, fmt.Errorf("could not look up process %d: %v", pid, err) + return nil, jujuerrors.Annotatef(err, "could not look up process %d", pid) } return process, nil @@ -506,7 +507,7 @@ func (service *machineV1alpha1Service) Watch(ctx context.Context, machine *machi qcfg, ok := machine.Status.PlatformConfig.(QemuConfig) if !ok { - return nil, nil, fmt.Errorf("cannot cast QEMU platform configuration from machine status") + return nil, nil, jujuerrors.New("cannot cast QEMU platform configuration from machine status") } // Always use index 1 for monitoring events @@ -585,7 +586,7 @@ func (service *machineV1alpha1Service) Watch(ctx context.Context, machine *machi break accept } default: - errs <- fmt.Errorf("unsupported event: %s", event.Event) + errs <- jujuerrors.Errorf("unsupported event: %s", event.Event) } } }() @@ -597,7 +598,7 @@ func (service *machineV1alpha1Service) Watch(ctx context.Context, machine *machi func (service *machineV1alpha1Service) Start(ctx context.Context, machine *machinev1alpha1.Machine) (*machinev1alpha1.Machine, error) { qmpClient, err := service.QMPClient(ctx, machine) if err != nil { - return machine, fmt.Errorf("could not start qemu instance: %v", err) + return machine, jujuerrors.Annotate(err, "could not start qemu instance") } defer qmpClient.Close() @@ -608,7 +609,7 @@ func (service *machineV1alpha1Service) Start(ctx context.Context, machine *machi qcfg, ok := machine.Status.PlatformConfig.(QemuConfig) if !ok { - return machine, fmt.Errorf("cannot cast QEMU platform configuration from machine status") + return machine, jujuerrors.New("cannot cast QEMU platform configuration from machine status") } process, err := processFromPidFile(qcfg.PidFile) @@ -627,7 +628,7 @@ func (service *machineV1alpha1Service) Start(ctx context.Context, machine *machi func (service *machineV1alpha1Service) Pause(ctx context.Context, machine *machinev1alpha1.Machine) (*machinev1alpha1.Machine, error) { qmpClient, err := service.QMPClient(ctx, machine) if err != nil { - return machine, fmt.Errorf("could not start qemu instance: %v", err) + return machine, jujuerrors.Annotate(err, "could not start qemu instance") } defer qmpClient.Close() @@ -654,7 +655,7 @@ func (service *machineV1alpha1Service) Get(ctx context.Context, machine *machine qcfg, ok := machine.Status.PlatformConfig.(QemuConfig) if !ok { - return machine, fmt.Errorf("cannot read QEMU platform configuration from machine status") + return machine, errors.New("cannot read QEMU platform configuration from machine status") } // Check if the process is alive, which ultimately indicates to us whether we @@ -708,7 +709,7 @@ func (service *machineV1alpha1Service) Get(ctx context.Context, machine *machine exitCode = 1 return machine, nil } else if err != nil { - return machine, fmt.Errorf("could not attach to QMP client: %v", err) + return machine, jujuerrors.Annotate(err, "could not attach to QMP client") } defer qmpClient.Close() @@ -719,7 +720,7 @@ func (service *machineV1alpha1Service) Get(ctx context.Context, machine *machine // We cannot amend the status at this point, even if the process is // alive, since it is not an indicator of the state of the VM, only of the // VMM. So we return what we already know via LookupMachineConfig. - return machine, fmt.Errorf("could not query machine status via QMP: %v", err) + return machine, jujuerrors.Annotate(err, "could not query machine status via QMP") } // Map the QMP status to supported machine states @@ -779,7 +780,7 @@ func (service *machineV1alpha1Service) List(ctx context.Context, machines *machi func (service *machineV1alpha1Service) Stop(ctx context.Context, machine *machinev1alpha1.Machine) (*machinev1alpha1.Machine, error) { qmpClient, err := service.QMPClient(ctx, machine) if err != nil { - return machine, fmt.Errorf("could not stop qemu instance: %v", err) + return machine, jujuerrors.Annotate(err, "could not stop qemu instance") } defer qmpClient.Close() @@ -790,14 +791,14 @@ func (service *machineV1alpha1Service) Stop(ctx context.Context, machine *machin qcfg, ok := machine.Status.PlatformConfig.(QemuConfig) if !ok { - return machine, fmt.Errorf("cannot read QEMU platform configuration from machine status") + return machine, errors.New("cannot read QEMU platform configuration from machine status") } machine.Status.State = machinev1alpha1.MachineStateExited if err := retrytimeout.RetryTimeout(5*time.Second, func() error { if _, err := os.ReadFile(qcfg.PidFile); !os.IsNotExist(err) { - return fmt.Errorf("process still active") + return errors.New("process still active") } return nil @@ -812,7 +813,7 @@ func (service *machineV1alpha1Service) Stop(ctx context.Context, machine *machin func (service *machineV1alpha1Service) Delete(ctx context.Context, machine *machinev1alpha1.Machine) (*machinev1alpha1.Machine, error) { qcfg, ok := machine.Status.PlatformConfig.(QemuConfig) if !ok { - return machine, fmt.Errorf("cannot read QEMU platform configuration from machine status") + return machine, errors.New("cannot read QEMU platform configuration from machine status") } var errs merr.Errors diff --git a/machine/store/embedded.go b/machine/store/embedded.go index d1908ec12..dd865c1a5 100644 --- a/machine/store/embedded.go +++ b/machine/store/embedded.go @@ -8,12 +8,12 @@ import ( "bytes" "context" "encoding/gob" - "fmt" "os" "time" zip "api.zip" "github.com/dgraph-io/badger/v3" + "github.com/juju/errors" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/storage" @@ -98,12 +98,12 @@ func (store *embedded[_, _]) open() error { var err error db, err = badger.Open(store.bopts) if err != nil { - return fmt.Errorf("could not open machine store: %v", err) + return errors.Annotate(err, "could not open machine store") } return nil }); err != nil { - return fmt.Errorf("could not open machine store: %v", err) + return errors.Annotate(err, "could not open machine store") } store.db = db @@ -131,12 +131,12 @@ func (store *embedded[_, _]) Create(ctx context.Context, key string, _, out runt b := bytes.Buffer{} if err := gob.NewEncoder(&b).Encode(out); err != nil { - return fmt.Errorf("could not encode driver config for %s: %v", key, err) + return errors.Annotatef(err, "could not encode driver config for %s", key) } txn := store.db.NewTransaction(true) if err := txn.SetEntry(badger.NewEntry([]byte(key), b.Bytes())); err != nil { - return fmt.Errorf("could not save machine driver to store for %s: %v", key, err) + return errors.Annotatef(err, "could not save machine driver to store for %s", key) } return txn.Commit() @@ -177,12 +177,12 @@ func (store *embedded[_, _]) Get(ctx context.Context, key string, opts storage.G if err := store.db.View(func(txn *badger.Txn) error { item, err := txn.Get([]byte(key)) if err != nil { - return fmt.Errorf("could not access store for %s: %v", key, err) + return errors.Annotatef(err, "could not access store for %s", key) } val, err := item.ValueCopy(nil) if err != nil { - return fmt.Errorf("could not copy from store for %s: %v", key, err) + return errors.Annotatef(err, "could not copy from store for %s", key) } b := bytes.Buffer{} @@ -190,7 +190,7 @@ func (store *embedded[_, _]) Get(ctx context.Context, key string, opts storage.G return gob.NewDecoder(&b).Decode(objPtr) }); err != nil { - return fmt.Errorf("could not read from store for %s: %v", key, err) + return errors.Annotatef(err, "could not read from store for %s", key) } return nil @@ -238,7 +238,7 @@ func (store *embedded[Spec, Status]) GetList(ctx context.Context, key string, op return nil }); err != nil { - return fmt.Errorf("could not list from store at %s: %v", key, err) + return errors.Annotatef(err, "could not list from store at %s", key) } return nil diff --git a/make/make.go b/make/make.go index 5bd5e8b71..c0056b57f 100644 --- a/make/make.go +++ b/make/make.go @@ -6,10 +6,10 @@ package make import ( "context" - "fmt" "reflect" "strings" + "github.com/juju/errors" "kraftkit.sh/exec" ) @@ -24,7 +24,7 @@ type export struct { func parseExport(tag reflect.StructTag) (*export, error) { parts := strings.Split(tag.Get("export"), ",") if len(parts) == 0 { - return nil, fmt.Errorf("could not identify export tag") + return nil, errors.New("could not identify export tag") } e := &export{ @@ -59,13 +59,13 @@ func NewFromInterface(args interface{}, mopts ...MakeOption) (*Make, error) { v := reflect.ValueOf(args) if v.Kind() == reflect.Ptr { - return nil, fmt.Errorf("cannot derive interface arguments from pointer: passed by reference") + return nil, errors.New("cannot derive interface arguments from pointer: passed by reference") } for i := 0; i < t.NumField(); i++ { e, err := parseExport(t.Field(i).Tag) if err != nil { - return nil, fmt.Errorf("could not parse export tag: %s", err) + return nil, errors.Errorf("could not parse export tag: %s", err) } if len(e.export) > 0 { diff --git a/make/options.go b/make/options.go index dea0592f0..13de8ab37 100644 --- a/make/options.go +++ b/make/options.go @@ -5,8 +5,7 @@ package make import ( - "fmt" - + "github.com/juju/errors" "kraftkit.sh/exec" ) @@ -55,7 +54,7 @@ func NewMakeOptions(mopts ...MakeOption) (*MakeOptions, error) { for _, o := range mopts { if err := o(mo); err != nil { - return nil, fmt.Errorf("could not apply option: %v", err) + return nil, errors.Annotatef(err, "could not apply option") } } diff --git a/manifest/directory.go b/manifest/directory.go index 45f29a34d..a8c65e925 100644 --- a/manifest/directory.go +++ b/manifest/directory.go @@ -6,10 +6,10 @@ package manifest import ( "context" - "fmt" "os" "path/filepath" + "github.com/juju/errors" "kraftkit.sh/log" "kraftkit.sh/pack" "kraftkit.sh/unikraft" @@ -28,7 +28,7 @@ type DirectoryProvider struct { // "microlibirary" directory func NewDirectoryProvider(ctx context.Context, path string, opts ...ManifestOption) (Provider, error) { if f, err := os.Stat(path); err != nil || (err == nil && !f.IsDir()) { - return nil, fmt.Errorf("could not access directory '%s': %v", path, err) + return nil, errors.Annotatef(err, "could not access directory '%s'", path) } // Determine the type preemptively @@ -54,7 +54,7 @@ func NewDirectoryProvider(ctx context.Context, path string, opts ...ManifestOpti } if t == unikraft.ComponentTypeUnknown { - return nil, fmt.Errorf("unknown type for directory: %s", path) + return nil, errors.Errorf("unknown type for directory: %s", path) } provider := DirectoryProvider{ @@ -93,12 +93,12 @@ func (dp DirectoryProvider) PullManifest(ctx context.Context, manifest *Manifest } if len(popts.Workdir()) == 0 { - return fmt.Errorf("cannot pull without without working directory") + return errors.New("cannot pull without without working directory") } // The directory provider only has one channel, exploit this knowledge if len(manifest.Channels) != 1 { - return fmt.Errorf("cannot determine channel for directory provider") + return errors.New("cannot determine channel for directory provider") } local, err := unikraft.PlaceComponent( @@ -107,7 +107,7 @@ func (dp DirectoryProvider) PullManifest(ctx context.Context, manifest *Manifest manifest.Name, ) if err != nil { - return fmt.Errorf("could not place component package: %s", err) + return errors.Errorf("could not place component package: %s", err) } f, err := os.Lstat(local) @@ -120,13 +120,13 @@ func (dp DirectoryProvider) PullManifest(ctx context.Context, manifest *Manifest return nil } else if err == nil && f.Mode()&os.ModeSymlink == os.ModeSymlink { if err := os.Remove(local); err != nil { - return fmt.Errorf("could not remove symlink: %v", err) + return errors.Annotate(err, "could not remove symlink") } } // Simply generate a symbolic link to the directory resource if err := os.Symlink(manifest.Channels[0].Resource, local); err != nil { - return fmt.Errorf("could not copy directory: %v", err) + return errors.Annotate(err, "could not copy directory") } return nil diff --git a/manifest/git.go b/manifest/git.go index c66e17570..2e71ec7a2 100644 --- a/manifest/git.go +++ b/manifest/git.go @@ -6,7 +6,6 @@ package manifest import ( "context" - "fmt" "path/filepath" "strings" @@ -15,6 +14,7 @@ import ( gitplumbing "github.com/go-git/go-git/v5/plumbing" githttp "github.com/go-git/go-git/v5/plumbing/transport/http" gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh" + "github.com/juju/errors" giturl "github.com/kubescape/go-git-url" "kraftkit.sh/log" @@ -93,7 +93,7 @@ func NewGitProvider(ctx context.Context, path string, opts ...ManifestOption) (P // what we can read from the remote provider.refs, err = remote.ListContext(ctx, lopts) if err != nil { - return nil, fmt.Errorf("could not list remote git repository: %v", err) + return nil, errors.Annotate(err, "could not list remote git repository") } return provider, nil diff --git a/manifest/github.go b/manifest/github.go index 290f7bb6c..117d4e912 100644 --- a/manifest/github.go +++ b/manifest/github.go @@ -8,7 +8,6 @@ import ( "context" "crypto/tls" "errors" - "fmt" "net/http" "net/url" "strings" @@ -16,6 +15,7 @@ import ( "github.com/gobwas/glob" "github.com/google/go-github/v32/github" + jujuerrors "github.com/juju/errors" "github.com/sirupsen/logrus" "golang.org/x/oauth2" @@ -84,7 +84,7 @@ func NewGitHubProvider(ctx context.Context, path string, opts ...ManifestOption) if repo.RepoHost() != "github.com" { endpoint, err := url.Parse(repo.RepoHost()) if err != nil { - return nil, fmt.Errorf("failed to parse v3 endpoint: %s", err) + return nil, jujuerrors.Errorf("failed to parse v3 endpoint: %s", err) } provider.client, err = github.NewEnterpriseClient( @@ -148,7 +148,7 @@ func (ghp GitHubProvider) String() string { // parse a GitHub source with a wildcard repository name, e.g. lib-* func (ghp GitHubProvider) manifestsFromWildcard() ([]*Manifest, error) { if !strings.HasSuffix(ghp.repo.RepoName(), "*") { - return nil, fmt.Errorf("not a wildcard") + return nil, jujuerrors.New("not a wildcard") } var repos []*github.Repository diff --git a/manifest/index.go b/manifest/index.go index 0515cdfa7..effcf05ea 100644 --- a/manifest/index.go +++ b/manifest/index.go @@ -6,7 +6,6 @@ package manifest import ( "context" - "fmt" "io" "net/http" "net/url" @@ -14,6 +13,7 @@ import ( "path/filepath" "time" + "github.com/juju/errors" "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" @@ -68,7 +68,7 @@ func NewManifestIndexProvider(ctx context.Context, path string, mopts ...Manifes }, nil } - return nil, fmt.Errorf("provided path is not a manifest index: %s", path) + return nil, errors.Errorf("provided path is not a manifest index: %s", path) } func (mip ManifestIndexProvider) Manifests() ([]*Manifest, error) { @@ -76,7 +76,7 @@ func (mip ManifestIndexProvider) Manifests() ([]*Manifest, error) { } func (mip ManifestIndexProvider) PullManifest(ctx context.Context, manifest *Manifest, opts ...pack.PullOption) error { - return fmt.Errorf("not implemented: manifest.ManifestIndexProvider.PullManifest") + return errors.New("not implemented: manifest.ManifestIndexProvider.PullManifest") } func (mip ManifestIndexProvider) String() string { @@ -93,7 +93,7 @@ func NewManifestIndexFromBytes(raw []byte, opts ...ManifestOption) (*ManifestInd } if index.Manifests == nil { - return nil, fmt.Errorf("nothing found in manifest index") + return nil, errors.New("nothing found in manifest index") } for i, manifest := range index.Manifests { @@ -109,7 +109,7 @@ func NewManifestIndexFromFile(path string, mopts ...ManifestOption) (*ManifestIn if err != nil { return nil, err } else if f.Size() == 0 { - return nil, fmt.Errorf("manifest index is empty: %s", path) + return nil, errors.Errorf("manifest index is empty: %s", path) } contents, err := os.ReadFile(path) @@ -155,7 +155,7 @@ func NewManifestIndexFromURL(ctx context.Context, path string, mopts ...Manifest } resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("manifest index not found: %s", path) + return nil, errors.Errorf("manifest index not found: %s", path) } get, err := http.NewRequest("GET", path, nil) @@ -177,13 +177,13 @@ func NewManifestIndexFromURL(ctx context.Context, path string, mopts ...Manifest defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("received %d error when retreiving: %s", resp.StatusCode, path) + return nil, errors.Errorf("received %d error when retreiving: %s", resp.StatusCode, path) } // Check if we're directly pointing to a compatible manifest file ext := filepath.Ext(path) if ext != ".yml" && ext != ".yaml" { - return nil, fmt.Errorf("unsupported manifest index extension for path: %s", path) + return nil, errors.Errorf("unsupported manifest index extension for path: %s", path) } contents, err := io.ReadAll(resp.Body) @@ -205,7 +205,7 @@ func (mi *ManifestIndex) WriteToFile(path string) error { // Open the file (create if not present) f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0o600) if err != nil { - return fmt.Errorf("could not open file: %v", err) + return errors.Annotate(err, "could not open file") } defer f.Close() diff --git a/manifest/manager.go b/manifest/manager.go index 980f896f6..0312fd9ea 100644 --- a/manifest/manager.go +++ b/manifest/manager.go @@ -6,7 +6,6 @@ package manifest import ( "context" - "fmt" "os" "path/filepath" "sort" @@ -14,6 +13,7 @@ import ( "unicode" "github.com/gobwas/glob" + "github.com/juju/errors" "github.com/sirupsen/logrus" "kraftkit.sh/config" @@ -36,7 +36,7 @@ func NewManifestManager(ctx context.Context, opts ...any) (packmanager.PackageMa for _, mopt := range opts { opt, ok := mopt.(ManifestManagerOption) if !ok { - return nil, fmt.Errorf("cannot cast ManifestManager option") + return nil, errors.New("cannot cast ManifestManager option") } if err := opt(ctx, &manager); err != nil { @@ -57,7 +57,7 @@ func NewManifestManager(ctx context.Context, opts ...any) (packmanager.PackageMa // update retrieves and returns a cache of the upstream manifest registry func (m *manifestManager) update(ctx context.Context) (*ManifestIndex, error) { if len(m.manifests) == 0 { - return nil, fmt.Errorf("no manifests specified in config") + return nil, errors.New("no manifests specified in config") } localIndex := &ManifestIndex{ @@ -169,15 +169,15 @@ func (m *manifestManager) RemoveSource(ctx context.Context, source string) error } func (m *manifestManager) Pack(ctx context.Context, c component.Component, opts ...packmanager.PackOption) ([]pack.Package, error) { - return nil, fmt.Errorf("not implemented manifest.manager.Pack") + return nil, errors.New("not implemented manifest.manager.Pack") } func (m *manifestManager) Unpack(ctx context.Context, p pack.Package, opts ...packmanager.UnpackOption) ([]component.Component, error) { - return nil, fmt.Errorf("not implemented manifest.manager.Unpack") + return nil, errors.New("not implemented manifest.manager.Unpack") } func (m *manifestManager) From(sub pack.PackageFormat) (packmanager.PackageManager, error) { - return nil, fmt.Errorf("method not applicable to manifest manager") + return nil, errors.New("method not applicable to manifest manager") } func (m *manifestManager) Catalog(ctx context.Context, qopts ...packmanager.QueryOption) ([]pack.Package, error) { @@ -374,7 +374,7 @@ func (m *manifestManager) IsCompatible(ctx context.Context, source string, qopts } if _, err := NewProvider(ctx, source); err != nil { - return nil, false, fmt.Errorf("incompatible source") + return nil, false, errors.New("incompatible source") } return m, true, nil diff --git a/manifest/manifest.go b/manifest/manifest.go index aba06ee3c..a1d862497 100644 --- a/manifest/manifest.go +++ b/manifest/manifest.go @@ -6,7 +6,6 @@ package manifest import ( "context" - "fmt" "io" "net/http" "net/url" @@ -14,6 +13,7 @@ import ( "path/filepath" "sync" + "github.com/juju/errors" "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" @@ -90,7 +90,7 @@ func NewManifestProvider(ctx context.Context, path string, mopts ...ManifestOpti }, nil } - return nil, fmt.Errorf("provided path is not a manifest: %s", path) + return nil, errors.Errorf("provided path is not a manifest: %s", path) } func (mp ManifestProvider) Manifests() ([]*Manifest, error) { @@ -146,9 +146,9 @@ func NewManifestFromBytes(ctx context.Context, raw []byte, opts ...ManifestOptio } if len(manifest.Name) == 0 { - return nil, fmt.Errorf("unset name in manifest") + return nil, errors.New("unset name in manifest") } else if len(manifest.Type) == 0 { - return nil, fmt.Errorf("unset type in manifest") + return nil, errors.New("unset type in manifest") } if providerName != "" { @@ -167,13 +167,13 @@ func NewManifestFromFile(ctx context.Context, path string, mopts ...ManifestOpti if err != nil { return nil, err } else if f.Size() == 0 { - return nil, fmt.Errorf("manifest path is empty: %s", path) + return nil, errors.Errorf("manifest path is empty: %s", path) } // Check if we're directly pointing to a compatible manifest file ext := filepath.Ext(path) if ext != ".yml" && ext != ".yaml" { - return nil, fmt.Errorf("unsupported manifest extension for path: %s", path) + return nil, errors.Errorf("unsupported manifest extension for path: %s", path) } contents, err := os.ReadFile(path) @@ -196,7 +196,7 @@ func NewManifestFromFile(ctx context.Context, path string, mopts ...ManifestOpti func NewManifestFromURL(ctx context.Context, path string, mopts ...ManifestOption) (*Manifest, error) { u, err := url.Parse(path) if err != nil || u.Scheme == "" || u.Host == "" { - return nil, fmt.Errorf("provided path was not a valid URL") + return nil, errors.New("provided path was not a valid URL") } var contents []byte @@ -220,7 +220,7 @@ func NewManifestFromURL(ctx context.Context, path string, mopts ...ManifestOptio } resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("manifest index not found: %s", path) + return nil, errors.Errorf("manifest index not found: %s", path) } get, err := http.NewRequestWithContext(ctx, "GET", path, nil) @@ -242,13 +242,13 @@ func NewManifestFromURL(ctx context.Context, path string, mopts ...ManifestOptio defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("received %d error when retrieving: %s", resp.StatusCode, path) + return nil, errors.Errorf("received %d error when retrieving: %s", resp.StatusCode, path) } // Check if we're directly pointing to a compatible manifest file ext := filepath.Ext(path) if ext != ".yml" && ext != ".yaml" { - return nil, fmt.Errorf("unsupported manifest extension for path: %s", path) + return nil, errors.Errorf("unsupported manifest extension for path: %s", path) } contents, err = io.ReadAll(resp.Body) @@ -356,7 +356,7 @@ func (m Manifest) WriteToFile(path string) error { // Open the file (create if not present) f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0o600) if err != nil { - return fmt.Errorf("could not open file: %v", err) + return errors.Annotate(err, "could not open file") } defer f.Close() @@ -405,7 +405,7 @@ func (m Manifest) WriteToFile(path string) error { // DefaultChannel returns the default channel of the Manifest func (m Manifest) DefaultChannel() (*ManifestChannel, error) { if len(m.Channels) == 0 { - return nil, fmt.Errorf("manifest does not have any channels") + return nil, errors.New("manifest does not have any channels") } // Use the channel by default to determine the latest version. In the @@ -417,5 +417,5 @@ func (m Manifest) DefaultChannel() (*ManifestChannel, error) { } } - return nil, fmt.Errorf("manifest does not have a default channel: %s", m.Origin) + return nil, errors.Errorf("manifest does not have a default channel: %s", m.Origin) } diff --git a/manifest/pack.go b/manifest/pack.go index 772e2eb54..b601e0266 100644 --- a/manifest/pack.go +++ b/manifest/pack.go @@ -6,9 +6,9 @@ package manifest import ( "context" - "fmt" "path/filepath" + "github.com/juju/errors" "kraftkit.sh/log" "kraftkit.sh/pack" "kraftkit.sh/unikraft" @@ -47,7 +47,7 @@ func NewPackageFromManifestWithVersion(manifest *Manifest, version string, opts manifest.Versions = versions if len(channels) == 0 && len(versions) == 0 { - return nil, fmt.Errorf("unknown version: %s", version) + return nil, errors.Errorf("unknown version: %s", version) } return &mpack{manifest, version}, nil @@ -81,14 +81,14 @@ func (mp mpack) Metadata() any { } func (mp mpack) Push(ctx context.Context, opts ...pack.PushOption) error { - return fmt.Errorf("not implemented: manifest.ManifestPackage.Push") + return errors.New("not implemented: manifest.ManifestPackage.Push") } func (mp mpack) Pull(ctx context.Context, opts ...pack.PullOption) error { log.G(ctx).Debugf("pulling manifest package %s", mp.Name()) if mp.manifest.Provider == nil { - return fmt.Errorf("uninitialized manifest provider") + return errors.New("uninitialized manifest provider") } opts = append(opts, pack.WithPullVersion(mp.version)) @@ -107,7 +107,7 @@ func resourceCacheChecksum(manifest *Manifest) (string, string, string, error) { var cache string if manifest.mopts.cacheDir == "" { - err = fmt.Errorf("cannot determine cache dir") + err = errors.Errorf("cannot determine cache dir") } else if len(manifest.Channels) == 1 { ext := filepath.Ext(manifest.Channels[0].Resource) if ext == ".gz" { @@ -132,7 +132,7 @@ func resourceCacheChecksum(manifest *Manifest) (string, string, string, error) { manifest.mopts.cacheDir, manifest.Name+"-"+manifest.Versions[0].Version+ext, ) } else { - err = fmt.Errorf("too many options") + err = errors.New("too many options") } return resource, cache, checksum, err diff --git a/manifest/pack_pull_archive.go b/manifest/pack_pull_archive.go index 821860338..0e07efb76 100644 --- a/manifest/pack_pull_archive.go +++ b/manifest/pack_pull_archive.go @@ -8,13 +8,13 @@ import ( "context" "crypto/sha256" "encoding/base64" - "fmt" "io" "net/http" "net/url" "os" "path/filepath" + "github.com/juju/errors" "github.com/sirupsen/logrus" "kraftkit.sh/archive" @@ -101,9 +101,9 @@ func pullArchive(ctx context.Context, manifest *Manifest, opts ...pack.PullOptio // archives as Content-Length is, for some reason, always set to 0. res, err := client.Do(head) if err != nil { - return fmt.Errorf("could not perform HEAD request on resource: %v", err) + return errors.Annotate(err, "could not perform HEAD request on resource") } else if res.StatusCode != http.StatusOK { - return fmt.Errorf("received HTTP error code %d on resource", res.StatusCode) + return errors.Errorf("received HTTP error code %d on resource", res.StatusCode) } else if res.ContentLength <= 0 { log.G(ctx).Warnf("could not determine package size before pulling") pp.total = 0 @@ -114,12 +114,12 @@ func pullArchive(ctx context.Context, manifest *Manifest, opts ...pack.PullOptio // Create a temporary partial of the destination path of the resource tmpCache := cache + ".part" if err := os.MkdirAll(filepath.Dir(tmpCache), 0o755); err != nil { - return fmt.Errorf("could not create parent directorires: %v", err) + return errors.Annotate(err, "could not create parent directorires") } f, err := os.OpenFile(tmpCache, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o755) if err != nil { - return fmt.Errorf("could not create cache file: %v", err) + return errors.Annotate(err, "could not create cache file") } defer f.Close() @@ -143,9 +143,9 @@ func pullArchive(ctx context.Context, manifest *Manifest, opts ...pack.PullOptio // Perform the request to actually retrieve the file res, err = client.Do(get) if err != nil { - return fmt.Errorf("could not initialize GET request to download package: %v", err) + return errors.Annotate(err, "could not initialize GET request to download package") } else if res.StatusCode != http.StatusOK { - return fmt.Errorf("received non-200 HTTP status code when attempting to download package: %v", err) + return errors.Annotate(err, "received non-200 HTTP status code when attempting to download package") } defer res.Body.Close() @@ -166,17 +166,17 @@ func pullArchive(ctx context.Context, manifest *Manifest, opts ...pack.PullOptio f, err := os.Open(tmpCache) if err != nil { - return fmt.Errorf("could not perform checksum: %v", err) + return errors.Annotate(err, "could not perform checksum") } defer f.Close() h := sha256.New() if _, err := io.Copy(h, f); err != nil { - return fmt.Errorf("could not perform checksum: %v", err) + return errors.Annotate(err, "could not perform checksum") } if checksum != string(h.Sum(nil)) { - return fmt.Errorf("checksum of package does not match") + return errors.New("checksum of package does not match") } log.G(ctx).WithFields(logrus.Fields{ @@ -188,7 +188,7 @@ func pullArchive(ctx context.Context, manifest *Manifest, opts ...pack.PullOptio // Copy the completed download to the local cache path if err := os.Rename(tmpCache, cache); err != nil { - return fmt.Errorf("could not move downloaded package '%s' to destination '%s': %v", tmpCache, cache, err) + return errors.Annotatef(err, "could not move downloaded package '%s' to destination '%s'", tmpCache, cache) } } else { log.G(ctx).WithFields(logrus.Fields{ @@ -205,7 +205,7 @@ func pullArchive(ctx context.Context, manifest *Manifest, opts ...pack.PullOptio manifest.Name, ) if err != nil { - return fmt.Errorf("could not place component package: %s", err) + return errors.Errorf("could not place component package: %s", err) } } @@ -219,7 +219,7 @@ func pullArchive(ctx context.Context, manifest *Manifest, opts ...pack.PullOptio if err := archive.Unarchive(cache, local, archive.StripComponents(1), ); err != nil { - return fmt.Errorf("could not unarchive: %v", err) + return errors.Annotate(err, "could not unarchive") } } diff --git a/manifest/pack_pull_git.go b/manifest/pack_pull_git.go index 355019db4..5f3570388 100644 --- a/manifest/pack_pull_git.go +++ b/manifest/pack_pull_git.go @@ -19,6 +19,7 @@ import ( gitplumbing "github.com/go-git/go-git/v5/plumbing" githttp "github.com/go-git/go-git/v5/plumbing/transport/http" gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh" + jujuerrors "github.com/juju/errors" "kraftkit.sh/log" "kraftkit.sh/pack" @@ -107,13 +108,13 @@ func pullGit(ctx context.Context, manifest *Manifest, opts ...pack.PullOption) e } if len(popts.Workdir()) == 0 { - return fmt.Errorf("cannot Git clone manifest package without working directory") + return jujuerrors.New("cannot Git clone manifest package without working directory") } log.G(ctx).Debugf("using git to pull manifest package %s", manifest.Name) if len(manifest.Origin) == 0 { - return fmt.Errorf("requesting Git with empty repository in manifest") + return jujuerrors.New("requesting Git with empty repository in manifest") } completeWorker := make(chan struct{}) @@ -141,7 +142,7 @@ func pullGit(ctx context.Context, manifest *Manifest, opts ...pack.PullOption) e } copts.Auth, err = gitssh.NewSSHAgentAuth("git") if err != nil { - return fmt.Errorf("could not create SSH agent auth: %w", err) + return jujuerrors.Annotate(err, "could not create SSH agent auth") } } else { if !strings.HasPrefix(path, "https://") { @@ -149,7 +150,7 @@ func pullGit(ctx context.Context, manifest *Manifest, opts ...pack.PullOption) e } u, err := url.Parse(path) if err != nil { - return fmt.Errorf("could not parse URL: %w", err) + return jujuerrors.Annotate(err, "could not parse URL") } endpoint := u.Host @@ -178,7 +179,7 @@ func pullGit(ctx context.Context, manifest *Manifest, opts ...pack.PullOption) e manifest.Name, ) if err != nil { - return fmt.Errorf("could not place component package: %w", err) + return jujuerrors.Annotate(err, "could not place component package") } log.G(ctx). @@ -192,7 +193,7 @@ func pullGit(ctx context.Context, manifest *Manifest, opts ...pack.PullOption) e case errors.Is(err, git.ErrRepositoryAlreadyExists): reps, err := git.PlainOpen(local) if err != nil { - return fmt.Errorf("could not open repository: %w", err) + return jujuerrors.Annotate(err, "could not open repository") } err = reps.FetchContext(ctx, &git.FetchOptions{ RemoteURL: copts.URL, @@ -206,10 +207,10 @@ func pullGit(ctx context.Context, manifest *Manifest, opts ...pack.PullOption) e log.G(ctx).Infof("successfully updated %s in %s", path, local) return nil default: - return fmt.Errorf("could not clone repository: %w", err) + return jujuerrors.Annotate(err, "could not clone repository") } case err != nil: - return fmt.Errorf("could not clone repository: %w", err) + return jujuerrors.Annotate(err, "could not clone repository") } // Wait for the go routine to finish diff --git a/manifest/provider.go b/manifest/provider.go index 5df2652a4..699bf3f9f 100644 --- a/manifest/provider.go +++ b/manifest/provider.go @@ -8,6 +8,7 @@ import ( "context" "fmt" + "github.com/juju/errors" "github.com/sirupsen/logrus" "kraftkit.sh/log" @@ -87,7 +88,7 @@ func NewProvider(ctx context.Context, path string, mopts ...ManifestOption) (Pro return provider, nil } - return nil, fmt.Errorf("could not determine provider for: %s", path) + return nil, errors.Errorf("could not determine provider for: %s", path) } // NewProviderFromString returns a provider based on a giving string which @@ -114,5 +115,5 @@ func NewProviderFromString(ctx context.Context, provider, path string, entity an return NewDirectoryProvider(ctx, path, mopts...) } - return nil, fmt.Errorf("could not determine provider for: %s", path) + return nil, errors.Errorf("could not determine provider for: %s", path) } diff --git a/manifest/version.go b/manifest/version.go index 0bf323cbb..a026d4ddf 100644 --- a/manifest/version.go +++ b/manifest/version.go @@ -32,7 +32,7 @@ package manifest import ( - "fmt" + "github.com/juju/errors" ) type ManifestVersionType string @@ -52,7 +52,7 @@ type ManifestVersion struct { func (mv *ManifestVersion) ShortGitSha() (string, error) { if mv.Type != ManifestVersionGitSha { - return "", fmt.Errorf("manifest version is not derived from Git") + return "", errors.New("manifest version is not derived from Git") } return mv.Version[:7], nil diff --git a/oci/blob.go b/oci/blob.go index b0799780a..4bb109c9e 100644 --- a/oci/blob.go +++ b/oci/blob.go @@ -6,9 +6,9 @@ package oci import ( "context" - "fmt" "os" + "github.com/juju/errors" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -24,7 +24,7 @@ type Blob struct { // type. func NewBlob(_ context.Context, mediaType string, data []byte, opts ...BlobOption) (*Blob, error) { if mediaType == "" { - return nil, fmt.Errorf("unknown blob type") + return nil, errors.New("unknown blob type") } fi, err := os.CreateTemp("", "kraftkit_oci-*") @@ -62,12 +62,12 @@ func NewBlob(_ context.Context, mediaType string, data []byte, opts ...BlobOptio func NewBlobFromFile(_ context.Context, mediaType string, filePath string, opts ...BlobOption) (*Blob, error) { fi, err := os.Stat(filePath) if err != nil { - return nil, fmt.Errorf("failed to stat %s: %v", filePath, err) + return nil, errors.Annotatef(err, "failed to stat %s", filePath) } fp, err := os.Open(filePath) if err != nil { - return nil, fmt.Errorf("failed to read %s: %v", filePath, err) + return nil, errors.Annotatef(err, "failed to read %s", filePath) } defer func() { diff --git a/oci/handler/containerd.go b/oci/handler/containerd.go index 79445584e..264c1d6cc 100644 --- a/oci/handler/containerd.go +++ b/oci/handler/containerd.go @@ -21,6 +21,7 @@ import ( "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/remotes" "github.com/containerd/nerdctl/pkg/imgutil/dockerconfigresolver" + "github.com/juju/errors" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" @@ -64,7 +65,7 @@ func NewContainerdHandler(ctx context.Context, address, namespace string, opts . // existing containerd client connection. func NewContainerdWithClient(ctx context.Context, client *containerd.Client) (context.Context, *ContainerdHandler, error) { if client == nil { - return nil, nil, fmt.Errorf("no containerd client provided") + return nil, nil, errors.New("no containerd client provided") } return ctx, &ContainerdHandler{client: client}, nil @@ -538,7 +539,7 @@ func (handle *ContainerdHandler) UnpackImage(ctx context.Context, ref string, de } if !isUnpacked { - return fmt.Errorf("empty image") + return errors.New("empty image") } // TODO(nderjung): This is where we could used media-types to extract the @@ -569,7 +570,7 @@ func (handle *ContainerdHandler) UnpackImage(ctx context.Context, ref string, de // FinalizeImage implements ImageFinalizer. func (handle *ContainerdHandler) FinalizeImage(ctx context.Context, image ocispec.Image) error { - return fmt.Errorf("not implemented: oci.handler.ContainerdHandler.FinalizeImage") + return errors.New("not implemented: oci.handler.ContainerdHandler.FinalizeImage") } // combineErrors is a helper for handling multiple potential errors, combining @@ -579,7 +580,7 @@ func combineErrors(original, additional error) error { case additional == nil: return original case original != nil: - return fmt.Errorf("%w. Additionally: %w", original, additional) + return errors.Errorf("%v. Additionally: %v", original, additional) default: return additional } diff --git a/oci/handler/directory.go b/oci/handler/directory.go index 3ebac54a6..c7e18031b 100644 --- a/oci/handler/directory.go +++ b/oci/handler/directory.go @@ -8,7 +8,6 @@ import ( "archive/tar" "context" "encoding/json" - "fmt" "io" "io/fs" "os" @@ -19,6 +18,7 @@ import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/juju/errors" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -35,7 +35,7 @@ type DirectoryHandler struct { func NewDirectoryHandler(path string) (*DirectoryHandler, error) { if err := os.MkdirAll(path, 0o755); err != nil { - return nil, fmt.Errorf("could not create local oci cache directory: %w", err) + return nil, errors.Annotate(err, "could not create local oci cache directory") } return &DirectoryHandler{path: path}, nil @@ -65,7 +65,7 @@ func (handle *DirectoryHandler) ListManifests(ctx context.Context) (manifests [] // there's nothing to return. if _, err := os.Stat(manifestsDir); err != nil && os.IsNotExist(err) { if err := os.MkdirAll(manifestsDir, 0o755); err != nil { - return nil, fmt.Errorf("could not create local oci cache directory: %w", err) + return nil, errors.Annotate(err, "could not create local oci cache directory") } return nil, nil @@ -158,12 +158,12 @@ func (handle *DirectoryHandler) PushDigest(ctx context.Context, ref string, desc // Create the parent directory if it does not exist if err := os.MkdirAll(filepath.Dir(blobPath), 0o644); err != nil { - return fmt.Errorf("could not make parent directory: %w", err) + return errors.Annotate(err, "could not make parent directory") } blob, err := os.OpenFile(blobPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644) if err != nil { - return fmt.Errorf("could not create blob: %w", err) + return errors.Annotate(err, "could not create blob") } var progresReader io.Reader @@ -206,7 +206,7 @@ func (handle *DirectoryHandler) ResolveImage(ctx context.Context, fullref string // Check whether the manifest exists if _, err := os.Stat(manifestPath); err != nil { - return ocispec.Image{}, fmt.Errorf("manifest for %s does not exist: %s", ref.Name(), manifestPath) + return ocispec.Image{}, errors.Errorf("manifest for %s does not exist: %s", ref.Name(), manifestPath) } // Read the manifest @@ -242,7 +242,7 @@ func (handle *DirectoryHandler) ResolveImage(ctx context.Context, fullref string // Check whether the config exists if _, err := os.Stat(configDir); err != nil { - return ocispec.Image{}, fmt.Errorf("could not access config file for %s: %w", ref.Name(), err) + return ocispec.Image{}, errors.Annotatef(err, "could not access config file for %s", ref.Name()) } // Read the config @@ -398,7 +398,7 @@ func (handle *DirectoryHandler) FetchImage(ctx context.Context, fullref, platfor // PushImage implements ImagePusher. func (handle *DirectoryHandler) PushImage(ctx context.Context, ref string, target *ocispec.Descriptor) error { - return fmt.Errorf("not implemented") + return errors.New("not implemented") } // UnpackImage implements ImageUnpacker. @@ -477,5 +477,5 @@ func (handle *DirectoryHandler) UnpackImage(ctx context.Context, ref string, des // FinalizeImage implements ImageFinalizer. func (handle *DirectoryHandler) FinalizeImage(ctx context.Context, image ocispec.Image) error { - return fmt.Errorf("not implemented: oci.handler.DirectoryHandler.FinalizeImage") + return errors.New("not implemented: oci.handler.DirectoryHandler.FinalizeImage") } diff --git a/oci/image.go b/oci/image.go index 8e9452704..36b0666e8 100644 --- a/oci/image.go +++ b/oci/image.go @@ -9,7 +9,6 @@ import ( "context" "encoding/json" "errors" - "fmt" "os" "sync" "time" @@ -17,6 +16,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/google/go-containerregistry/pkg/name" + jujuerrors "github.com/juju/errors" "github.com/opencontainers/go-digest" specs "github.com/opencontainers/image-spec/specs-go" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -47,7 +47,7 @@ type Image struct { // options. func NewImage(_ context.Context, handle handler.Handler, opts ...ImageOption) (*Image, error) { if handle == nil { - return nil, fmt.Errorf("cannot use `NewImage` without handler") + return nil, jujuerrors.New("cannot use `NewImage` without handler") } image := Image{ @@ -95,7 +95,7 @@ func (image *Image) Layers() []*Layer { // descriptor. func (image *Image) AddLayer(ctx context.Context, layer *Layer) (ocispec.Descriptor, error) { if layer == nil { - return ocispec.Descriptor{}, fmt.Errorf("cannot add empty layer") + return ocispec.Descriptor{}, jujuerrors.New("cannot add empty layer") } log.G(ctx).WithFields(logrus.Fields{ @@ -235,7 +235,7 @@ func (image *Image) Save(ctx context.Context, source string, onProgress func(flo } if _, err := image.AddBlob(egCtx, image.layers[i].blob); err != nil { - return fmt.Errorf("failed to push layer: %d: %v", i, err) + return jujuerrors.Annotatef(err, "failed to push layer: %d", i) } return nil @@ -323,7 +323,7 @@ func (image *Image) Save(ctx context.Context, source string, onProgress func(flo manifestJson, err := json.Marshal(image.manifest) if err != nil { - return ocispec.Descriptor{}, fmt.Errorf("failed to marshal manifest: %w", err) + return ocispec.Descriptor{}, jujuerrors.Annotatef(err, "failed to marshal manifest") } image.manifestDesc = content.NewDescriptorFromBytes( @@ -341,7 +341,7 @@ func (image *Image) Save(ctx context.Context, source string, onProgress func(flo bytes.NewReader(manifestJson), onProgress, ); err != nil && !errors.Is(err, errdefs.ErrAlreadyExists) { - return ocispec.Descriptor{}, fmt.Errorf("failed to push manifest: %w", err) + return ocispec.Descriptor{}, jujuerrors.Annotate(err, "failed to push manifest") } return image.manifestDesc, nil diff --git a/oci/layer_options.go b/oci/layer_options.go index adc528672..8d439f49b 100644 --- a/oci/layer_options.go +++ b/oci/layer_options.go @@ -4,7 +4,9 @@ // You may not use this file except in compliance with the License. package oci -import "fmt" +import ( + "github.com/juju/errors" +) type LayerOption func(*Layer) error @@ -12,7 +14,7 @@ type LayerOption func(*Layer) error func WithLayerAnnotation(key, val string) LayerOption { return func(layer *Layer) error { if layer.blob == nil { - return fmt.Errorf("cannot apply layer annotation without creating blob") + return errors.New("cannot apply layer annotation without creating blob") } if layer.blob.desc.Annotations == nil { diff --git a/oci/manager.go b/oci/manager.go index 73f5b5a7e..b14338a82 100644 --- a/oci/manager.go +++ b/oci/manager.go @@ -17,6 +17,7 @@ import ( "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" + "github.com/juju/errors" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "kraftkit.sh/config" @@ -44,7 +45,7 @@ func NewOCIManager(ctx context.Context, opts ...any) (packmanager.PackageManager for _, mopt := range opts { opt, ok := mopt.(OCIManagerOption) if !ok { - return nil, fmt.Errorf("cannot cast OCI Manager option") + return nil, errors.New("cannot cast OCI Manager option") } if err := opt(ctx, &manager); err != nil { @@ -53,7 +54,7 @@ func NewOCIManager(ctx context.Context, opts ...any) (packmanager.PackageManager } if manager.handle == nil { - return nil, fmt.Errorf("cannot instantiate OCI Manager without handler") + return nil, errors.New("cannot instantiate OCI Manager without handler") } return &manager, nil @@ -68,7 +69,7 @@ func (manager *ociManager) Update(ctx context.Context) error { func (manager *ociManager) Pack(ctx context.Context, entity component.Component, opts ...packmanager.PackOption) ([]pack.Package, error) { targ, ok := entity.(target.Target) if !ok { - return nil, fmt.Errorf("entity is not Unikraft target") + return nil, errors.New("entity is not Unikraft target") } pkg, err := NewPackageFromTarget(ctx, targ, opts...) @@ -81,7 +82,7 @@ func (manager *ociManager) Pack(ctx context.Context, entity component.Component, // Unpack implements packmanager.PackageManager func (manager *ociManager) Unpack(ctx context.Context, entity pack.Package, opts ...packmanager.UnpackOption) ([]component.Component, error) { - return nil, fmt.Errorf("not implemented: oci.manager.Unpack") + return nil, errors.New("not implemented: oci.manager.Unpack") } // registry is a wrapper method for authenticating and listing OCI repositories @@ -111,7 +112,7 @@ func (manager *ociManager) registry(ctx context.Context, domain string) (*regtoo }, }) if err != nil { - return nil, fmt.Errorf("could not initialize registry: %v", err) + return nil, errors.Annotate(err, "could not initialize registry") } return reg, nil @@ -131,7 +132,7 @@ func (manager *ociManager) Catalog(ctx context.Context, qopts ...packmanager.Que ) if refErr == nil { if ref.Identifier() != "latest" && qversion != "" && ref.Identifier() != qversion { - return nil, fmt.Errorf("cannot determine which version as name contains version and version query paremeter set") + return nil, errors.New("cannot determine which version as name contains version and version query paremeter set") } else if qversion == "" { qname = ref.Context().String() qversion = ref.Identifier() @@ -433,7 +434,7 @@ func (manager *ociManager) IsCompatible(ctx context.Context, source string, qopt // From implements packmanager.PackageManager func (manager *ociManager) From(pack.PackageFormat) (packmanager.PackageManager, error) { - return nil, fmt.Errorf("not possible: oci.manager.From") + return nil, errors.New("not possible: oci.manager.From") } // Format implements packmanager.PackageManager diff --git a/oci/manager_options.go b/oci/manager_options.go index ba7f7685c..de232117d 100644 --- a/oci/manager_options.go +++ b/oci/manager_options.go @@ -2,12 +2,12 @@ package oci import ( "context" - "fmt" "os" "path/filepath" regtypes "github.com/docker/docker/api/types/registry" "github.com/genuinetools/reg/repoutils" + "github.com/juju/errors" "github.com/sirupsen/logrus" "kraftkit.sh/config" "kraftkit.sh/log" @@ -139,7 +139,7 @@ func WithRegistries(registries ...string) OCIManagerOption { func WithDockerConfig(auth regtypes.AuthConfig) OCIManagerOption { return func(ctx context.Context, manager *ociManager) error { if auth.ServerAddress == "" { - return fmt.Errorf("cannot use auth config without server address") + return errors.New("cannot use auth config without server address") } if manager.auths == nil { diff --git a/oci/pack.go b/oci/pack.go index 2cf523734..39997ecff 100644 --- a/oci/pack.go +++ b/oci/pack.go @@ -14,6 +14,7 @@ import ( "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" + "github.com/juju/errors" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" "oras.land/oras-go/v2/content" @@ -257,7 +258,7 @@ func NewPackageFromOCIManifestSpec(ctx context.Context, handle handler.Handler, // Check if the OCI image has a known annotation which identifies if a // unikernel is contained within if _, ok := manifest.Annotations[AnnotationKernelVersion]; !ok { - return nil, fmt.Errorf("OCI image does not contain a Unikraft unikernel") + return nil, errors.New("OCI image does not contain a Unikraft unikernel") } var err error @@ -308,57 +309,57 @@ func NewPackageFromRemoteOCIRef(ctx context.Context, handle handler.Handler, ref name.WithDefaultRegistry(DefaultRegistry), ) if err != nil { - return nil, fmt.Errorf("cannot parse OCI image name reference: %v", err) + return nil, errors.Annotate(err, "cannot parse OCI image name reference") } raw, err := crane.Manifest(ref) if err != nil { - return nil, fmt.Errorf("could not get manifest: %v", err) + return nil, errors.Annotate(err, "could not get manifest") } var manifest ocispec.Manifest if err := json.Unmarshal(raw, &manifest); err != nil { - return nil, fmt.Errorf("could not unmarshal manifest: %v", err) + return nil, errors.Annotate(err, "could not unmarshal manifest") } // Check if the OCI image has a known annotation which identifies if a // unikernel is contained within if _, ok := manifest.Annotations[AnnotationKernelVersion]; !ok { - return nil, fmt.Errorf("OCI image does not contain a Unikraft unikernel") + return nil, errors.New("OCI image does not contain a Unikraft unikernel") } ocipack.image, err = NewImageFromManifestSpec(ctx, handle, manifest) if err != nil { - return nil, fmt.Errorf("could not generate image from manifest: %v", err) + return nil, errors.Annotate(err, "could not generate image from manifest") } if manifest.Config.Platform == nil { - return nil, fmt.Errorf("remote image platform is unknown") + return nil, errors.New("remote image platform is unknown") } // TODO(nderjung): Setting the architecture and platform are a bit of a hack // at the moment. A nicer mechanism should be used. architecture, err := arch.TransformFromSchema(ctx, manifest.Config.Platform.Architecture) if err != nil { - return nil, fmt.Errorf("could not convert architecture string") + return nil, errors.New("could not convert architecture string") } var ok bool ocipack.arch, ok = architecture.(arch.Architecture) if !ok { - return nil, fmt.Errorf("could not convert architecture string") + return nil, errors.New("could not convert architecture string") } platform, err := plat.TransformFromSchema(ctx, manifest.Config.Platform.OS) if err != nil { - return nil, fmt.Errorf("could not convert platform string") + return nil, errors.New("could not convert platform string") } ocipack.plat, ok = platform.(plat.Platform) if !ok { - return nil, fmt.Errorf("could not convert platform string") + return nil, errors.New("could not convert platform string") } return &ocipack, nil @@ -396,7 +397,7 @@ func (ocipack *ociPackage) Metadata() any { func (ocipack *ociPackage) Push(ctx context.Context, opts ...pack.PushOption) error { manifestJson, err := json.Marshal(ocipack.image.manifest) if err != nil { - return fmt.Errorf("failed to marshal manifest: %w", err) + return errors.Annotate(err, "failed to marshal manifest") } ocipack.image.manifestDesc = content.NewDescriptorFromBytes( @@ -485,7 +486,7 @@ func (ocipack *ociPackage) Path() string { // KConfigTree implements unikraft.component.Component func (ocipack *ociPackage) KConfigTree(context.Context, ...*kconfig.KeyValue) (*kconfig.KConfigFile, error) { - return nil, fmt.Errorf("not implemented: oci.ociPackage.KConfigTree") + return nil, errors.New("not implemented: oci.ociPackage.KConfigTree") } // KConfig implements unikraft.component.Component diff --git a/packmanager/umbrella.go b/packmanager/umbrella.go index bfc979663..f35f88c44 100644 --- a/packmanager/umbrella.go +++ b/packmanager/umbrella.go @@ -6,8 +6,8 @@ package packmanager import ( "context" - "fmt" + "github.com/juju/errors" "github.com/sirupsen/logrus" "kraftkit.sh/log" @@ -29,7 +29,7 @@ func PackageManagers() map[pack.PackageFormat]PackageManager { func RegisterPackageManager(ctxk pack.PackageFormat, constructor NewManagerConstructor, opts ...any) error { if _, ok := packageManagerConstructors[ctxk]; ok { - return fmt.Errorf("package manager already registered: %s", ctxk) + return errors.Errorf("package manager already registered: %s", ctxk) } packageManagerConstructors[ctxk] = constructor @@ -64,7 +64,7 @@ func NewUmbrellaManager(ctx context.Context) (PackageManager, error) { } if format, ok := packageManagers[manager.Format()]; ok { - return nil, fmt.Errorf("package manager already registered: %s", format) + return nil, errors.Errorf("package manager already registered: %s", format) } packageManagers[manager.Format()] = manager @@ -80,7 +80,7 @@ func (u umbrella) From(sub pack.PackageFormat) (PackageManager, error) { } } - return nil, fmt.Errorf("unknown package manager: %s", sub) + return nil, errors.Errorf("unknown package manager: %s", sub) } func (u umbrella) Update(ctx context.Context) error { @@ -195,7 +195,7 @@ func (u umbrella) Catalog(ctx context.Context, qopts ...QueryOption) ([]pack.Pac func (u umbrella) IsCompatible(ctx context.Context, source string, qopts ...QueryOption) (PackageManager, bool, error) { if source == "" { - return nil, false, fmt.Errorf("cannot determine compatibility of empty source") + return nil, false, errors.Errorf("cannot determine compatibility of empty source") } for _, manager := range packageManagers { @@ -214,7 +214,7 @@ func (u umbrella) IsCompatible(ctx context.Context, source string, qopts ...Quer } } - return nil, false, fmt.Errorf("cannot find compatible package manager for source: %s", source) + return nil, false, errors.Errorf("cannot find compatible package manager for source: %s", source) } func (u umbrella) Format() pack.PackageFormat { diff --git a/plugins/manager.go b/plugins/manager.go index 8c05fdc17..6e4ad069e 100644 --- a/plugins/manager.go +++ b/plugins/manager.go @@ -44,6 +44,7 @@ import ( "strings" "github.com/cli/safeexec" + "github.com/juju/errors" "gopkg.in/yaml.v3" "kraftkit.sh/internal/findsh" @@ -109,13 +110,13 @@ func (pm *PluginManager) parseBinaryPluginDir(fi fs.FileInfo) (Plugin, error) { manifestPath := filepath.Join(pm.dataDir, fi.Name(), PluginManifestFile) manifest, err := os.ReadFile(manifestPath) if err != nil { - return ext, fmt.Errorf("could not open %s for reading: %w", manifestPath, err) + return ext, errors.Annotatef(err, "could not open %s for reading", manifestPath) } var man PluginManifest err = yaml.Unmarshal(manifest, &man) if err != nil { - return ext, fmt.Errorf("could not parse %s: %w", manifestPath, err) + return ext, errors.Annotatef(err, "could not parse %s", manifestPath) } // repo := ghrepo.NewWithHost(bm.Owner, bm.Name, bm.Host) @@ -187,7 +188,7 @@ func (pm *PluginManager) List() ([]Plugin, error) { if f, err := os.Stat(pm.dataDir); err != nil || !f.IsDir() { if err := os.MkdirAll(pm.dataDir, 0o755); err != nil { - return results, fmt.Errorf("%v: %s", err, pm.dataDir) + return results, errors.Errorf("%v: %s", err, pm.dataDir) } } @@ -228,11 +229,11 @@ func (pm *PluginManager) List() ([]Plugin, error) { } func (pm *PluginManager) Install(repo string) error { - return fmt.Errorf("not implemented") + return errors.New("not implemented") } func (pm *PluginManager) InstallLocal(repo string) error { - return fmt.Errorf("not implemented") + return errors.New("not implemented") } func (pm *PluginManager) Dispatch() error { diff --git a/test/e2e/framework/cmd/cmd.go b/test/e2e/framework/cmd/cmd.go index cdd508324..67af57e6c 100644 --- a/test/e2e/framework/cmd/cmd.go +++ b/test/e2e/framework/cmd/cmd.go @@ -13,6 +13,7 @@ import ( "os/exec" "path/filepath" + jujuerrors "github.com/juju/errors" gomegafmt "github.com/onsi/gomega/format" ) @@ -47,7 +48,9 @@ func (c *Cmd) Run() error { if r, ok := c.Cmd.Stderr.(io.Reader); ok { b, re := io.ReadAll(r) if re != nil { - return fmt.Errorf("%w. Additionally, while reading stderr: %w", err, re) + re = jujuerrors.Annotate(re, "Additionally, while reading stderr") + err = jujuerrors.Wrap(err, re) + return err } ee.Stderr = b return &ExitError{ExitError: ee} diff --git a/test/e2e/framework/matchers/be_empty_dir.go b/test/e2e/framework/matchers/be_empty_dir.go index 55f532a4b..95305055f 100644 --- a/test/e2e/framework/matchers/be_empty_dir.go +++ b/test/e2e/framework/matchers/be_empty_dir.go @@ -9,6 +9,7 @@ import ( "fmt" "os" + "github.com/juju/errors" "github.com/onsi/gomega/format" "github.com/onsi/gomega/types" ) @@ -23,12 +24,12 @@ var _ types.GomegaMatcher = (*beAnEmptyDirectoryMatcher)(nil) func (matcher *beAnEmptyDirectoryMatcher) Match(actual any) (success bool, err error) { actualDirName, ok := actual.(string) if !ok { - return false, fmt.Errorf("BeAnEmptyDirectory matcher expects a directory path") + return false, errors.New("BeAnEmptyDirectory matcher expects a directory path") } dirEntries, err := os.ReadDir(actualDirName) if err != nil { - matcher.err = fmt.Errorf("reading directory entries: %w", err) + matcher.err = errors.Annotate(err, "reading directory entries") return false, nil } @@ -36,7 +37,7 @@ func (matcher *beAnEmptyDirectoryMatcher) Match(actual any) (success bool, err e hasEntries := n > 0 if hasEntries { - matcher.err = fmt.Errorf("directory contains %d entries", n) + matcher.err = errors.Errorf("directory contains %d entries", n) } return !hasEntries, nil diff --git a/test/e2e/framework/matchers/contain_dirs.go b/test/e2e/framework/matchers/contain_dirs.go index b41b7082d..d5e48f5d5 100644 --- a/test/e2e/framework/matchers/contain_dirs.go +++ b/test/e2e/framework/matchers/contain_dirs.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" + "github.com/juju/errors" "github.com/onsi/gomega/format" "github.com/onsi/gomega/types" ) @@ -26,29 +27,29 @@ var _ types.GomegaMatcher = (*containDirectoriesMatcher)(nil) func (matcher *containDirectoriesMatcher) Match(actual any) (success bool, err error) { actualDirName, ok := actual.(string) if !ok { - return false, fmt.Errorf("ContainFiles matcher expects a directory path") + return false, errors.New("ContainFiles matcher expects a directory path") } dirEntries, err := os.ReadDir(actualDirName) if err != nil { - matcher.err = fmt.Errorf("reading directory entries: %w", err) + matcher.err = errors.Annotate(err, "reading directory entries") return false, nil } if n, nExpect := len(dirEntries), len(matcher.dirNames); n < nExpect { - matcher.err = fmt.Errorf("directory contains less entries (%d) than provided sub-directories names (%d)", n, nExpect) + matcher.err = errors.Errorf("directory contains less entries (%d) than provided sub-directories names (%d)", n, nExpect) return false, nil } for _, fn := range matcher.dirNames { fi, err := os.Stat(filepath.Join(actualDirName, fn)) if err != nil { - matcher.err = fmt.Errorf("reading file info: %w", err) + matcher.err = errors.Annotate(err, "reading file info") return false, nil } if !fi.IsDir() { - matcher.err = fmt.Errorf("file %q is not a directory (type: %s)", fi.Name(), fi.Mode().Type()) + matcher.err = errors.Errorf("file %q is not a directory (type: %s)", fi.Name(), fi.Mode().Type()) return false, nil } } diff --git a/test/e2e/framework/matchers/contain_files.go b/test/e2e/framework/matchers/contain_files.go index 090e92fe4..1c8727365 100644 --- a/test/e2e/framework/matchers/contain_files.go +++ b/test/e2e/framework/matchers/contain_files.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" + "github.com/juju/errors" "github.com/onsi/gomega/format" "github.com/onsi/gomega/types" ) @@ -26,29 +27,29 @@ var _ types.GomegaMatcher = (*containFilesMatcher)(nil) func (matcher *containFilesMatcher) Match(actual any) (success bool, err error) { actualDirName, ok := actual.(string) if !ok { - return false, fmt.Errorf("ContainFiles matcher expects a directory path") + return false, errors.New("ContainFiles matcher expects a directory path") } dirEntries, err := os.ReadDir(actualDirName) if err != nil { - matcher.err = fmt.Errorf("reading directory entries: %w", err) + matcher.err = errors.Annotate(err, "reading directory entries") return false, nil } if n, nExpect := len(dirEntries), len(matcher.fileNames); n < nExpect { - matcher.err = fmt.Errorf("directory contains less entries (%d) than provided files names (%d)", n, nExpect) + matcher.err = errors.Errorf("directory contains less entries (%d) than provided files names (%d)", n, nExpect) return false, nil } for _, fn := range matcher.fileNames { fi, err := os.Stat(filepath.Join(actualDirName, fn)) if err != nil { - matcher.err = fmt.Errorf("reading file info: %w", err) + matcher.err = errors.Annotate(err, "reading file info") return false, nil } if !fi.Mode().IsRegular() { - matcher.err = fmt.Errorf("file %q is not regular (type: %s)", fi.Name(), fi.Mode().Type()) + matcher.err = errors.Errorf("file %q is not regular (type: %s)", fi.Name(), fi.Mode().Type()) return false, nil } } diff --git a/tools/protoc-gen-go-netconn/apply.go b/tools/protoc-gen-go-netconn/apply.go index 7e8186ee5..346699cab 100644 --- a/tools/protoc-gen-go-netconn/apply.go +++ b/tools/protoc-gen-go-netconn/apply.go @@ -180,12 +180,13 @@ import ( {{ if .HasService }} "bufio" "encoding/json" - "fmt" "io" {{- end }} "reflect" {{ if .HasService -}} "sync" + + jujuerrors "github.com/juju/errors" {{ end }} ) {{ end }} @@ -239,7 +240,7 @@ func (c *{{ .GoName }}Client) setRpcRequestSetDefaults(face any) error { case reflect.String: f.SetString(def) default: - return fmt.Errorf("unsupported default kind: %s", f.Kind().String()) + return jujuerrors.Errorf("unsupported default kind: %s", f.Kind().String()) } } diff --git a/tui/paraprogress/paraprogress.go b/tui/paraprogress/paraprogress.go index 905f38376..4b21129c7 100644 --- a/tui/paraprogress/paraprogress.go +++ b/tui/paraprogress/paraprogress.go @@ -6,12 +6,12 @@ package paraprogress import ( "context" - "fmt" "os" "github.com/barkimedes/go-deepcopy" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/juju/errors" "github.com/muesli/termenv" "golang.org/x/term" "kraftkit.sh/log" @@ -38,7 +38,7 @@ type ParaProgress struct { func NewParaProgress(ctx context.Context, processes []*Process, opts ...ParaProgressOption) (*ParaProgress, error) { if len(processes) == 0 { - return nil, fmt.Errorf("no processes to perform") + return nil, errors.New("no processes to perform") } md := &ParaProgress{ @@ -146,7 +146,7 @@ func (md *ParaProgress) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg.String() { case "ctrl+c": md.quitting = true - md.err = fmt.Errorf("force quit") + md.err = errors.New("force quit") return md, tea.Quit } case StatusMsg: diff --git a/tui/processtree/update.go b/tui/processtree/update.go index cc51df353..d4388b975 100644 --- a/tui/processtree/update.go +++ b/tui/processtree/update.go @@ -5,10 +5,9 @@ package processtree import ( - "fmt" - "github.com/charmbracelet/bubbles/spinner" tea "github.com/charmbracelet/bubbletea" + "github.com/juju/errors" ) func (pt *ProcessTree) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -36,7 +35,7 @@ func (pt *ProcessTree) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg.String() { case "ctrl+c": pt.quitting = true - pt.err = fmt.Errorf("force quit") + pt.err = errors.New("force quit") return pt, tea.Quit } diff --git a/unikraft/app/application.go b/unikraft/app/application.go index 3324257fe..d93516553 100644 --- a/unikraft/app/application.go +++ b/unikraft/app/application.go @@ -14,6 +14,7 @@ import ( "sort" "strings" + "github.com/juju/errors" "github.com/sirupsen/logrus" "github.com/xlab/treeprint" "gopkg.in/yaml.v3" @@ -362,7 +363,7 @@ func (app application) MakeArgs(tc target.Target) (*core.MakeArgs, error) { for _, library := range unformattedLibraries { if !library.IsUnpacked() { - return nil, fmt.Errorf("cannot determine library \"%s\" path without component source", library.Name()) + return nil, errors.Errorf("cannot determine library \"%s\" path without component source", library.Name()) } libraries = append(libraries, library.Path()) @@ -409,7 +410,7 @@ func (app application) Make(ctx context.Context, tc target.Target, mopts ...make makefile_uk := filepath.Join(app.WorkingDir(), unikraft.Makefile_uk) if _, err := os.Stat(makefile_uk); err != nil && os.IsNotExist(err) { if _, err := os.OpenFile(makefile_uk, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o666); err != nil { - return fmt.Errorf("could not create application %s: %v", makefile_uk, err) + return errors.Annotatef(err, "could not create application %s", makefile_uk) } } @@ -447,7 +448,7 @@ func (app application) Configure(ctx context.Context, tc target.Target, extra kc // Write the configuration to a temporary file tmpfile, err := os.CreateTemp("", app.Name()+"-config*") if err != nil { - return fmt.Errorf("could not create temporary defconfig file: %v", err) + return errors.Annotate(err, "could not create temporary defconfig file") } defer tmpfile.Close() @@ -581,14 +582,14 @@ func (app application) Build(ctx context.Context, tc target.Target, opts ...Buil for _, o := range opts { err := o(bopts) if err != nil { - return fmt.Errorf("could not apply build option: %v", err) + return errors.Annotate(err, "could not apply build option") } } if !app.unikraft.IsUnpacked() { // TODO: Produce better error messages (see #34). In this case, we should // indicate that `kraft pkg pull` needs to occur - return fmt.Errorf("cannot build without Unikraft core component source") + return errors.Errorf("cannot build without Unikraft core component source") } bopts.mopts = append(bopts.mopts, []make.MakeOption{ @@ -763,11 +764,11 @@ func (app application) Save() error { var from yaml.Node if err := yaml.Unmarshal(yamlData, &from); err != nil { - return fmt.Errorf("could not unmarshal YAML: %s", err) + return errors.Errorf("could not unmarshal YAML: %s", err) } if err := yamlmerger.RecursiveMerge(&from, &into); err != nil { - return fmt.Errorf("could not merge YAML: %s", err) + return errors.Errorf("could not merge YAML: %s", err) } // Marshal the Node structure back to YAML diff --git a/unikraft/app/application_options.go b/unikraft/app/application_options.go index 1d3fac012..c8f51d8de 100644 --- a/unikraft/app/application_options.go +++ b/unikraft/app/application_options.go @@ -5,10 +5,10 @@ package app import ( - "fmt" "os" "path/filepath" + "github.com/juju/errors" "kraftkit.sh/kconfig" "kraftkit.sh/unikraft" "kraftkit.sh/unikraft/component" @@ -32,7 +32,7 @@ func NewApplicationFromOptions(aopts ...ApplicationOption) (Application, error) for _, o := range aopts { if err := o(ac); err != nil { - return nil, fmt.Errorf("could not apply option: %v", err) + return nil, errors.Annotate(err, "could not apply option") } } diff --git a/unikraft/app/build_options.go b/unikraft/app/build_options.go index 71b058170..59fdc72a6 100644 --- a/unikraft/app/build_options.go +++ b/unikraft/app/build_options.go @@ -5,9 +5,9 @@ package app import ( - "fmt" "os" + "github.com/juju/errors" "kraftkit.sh/exec" "kraftkit.sh/make" ) @@ -57,7 +57,7 @@ func WithBuildLogFile(path string) BuildOption { file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o666) if err != nil { - return fmt.Errorf("could not create or open build log file: %v", err) + return errors.Annotate(err, "could not create or open build log file") } bo.mopts = append(bo.mopts, make.WithExecOptions( diff --git a/unikraft/app/project.go b/unikraft/app/project.go index 4a84a0ac7..076e4f86c 100644 --- a/unikraft/app/project.go +++ b/unikraft/app/project.go @@ -18,10 +18,10 @@ package app import ( "context" - "fmt" "os" "path/filepath" + "github.com/juju/errors" "kraftkit.sh/kconfig" "kraftkit.sh/log" "kraftkit.sh/schema" @@ -30,7 +30,7 @@ import ( // ErrNoKraftfile is thrown when a project is instantiated at a directory // without a recognizable Kraftfile. -var ErrNoKraftfile = fmt.Errorf("no Kraftfile specified") +var ErrNoKraftfile = errors.New("no Kraftfile specified") // DefaultFileNames defines the kraft file names for auto-discovery (in order // of preference) @@ -53,7 +53,7 @@ func IsWorkdirInitialized(dir string) bool { func NewProjectFromOptions(ctx context.Context, opts ...ProjectOption) (Application, error) { popts, err := NewProjectOptions(opts...) if err != nil { - return nil, fmt.Errorf("could not apply project options: %v", err) + return nil, errors.Annotate(err, "could not apply project options") } workdir, err := popts.Workdir() @@ -116,7 +116,7 @@ func NewProjectFromOptions(ctx context.Context, opts ...ProjectOption) (Applicat if _, err := os.Stat(uk.BUILD_DIR); err != nil && os.IsNotExist(err) { if err := os.MkdirAll(uk.BUILD_DIR, 0o755); err != nil { - return nil, fmt.Errorf("creating build directory: %w", err) + return nil, errors.Annotate(err, "creating build directory") } } diff --git a/unikraft/app/project_options.go b/unikraft/app/project_options.go index 30b2a50f0..a5e1366f8 100644 --- a/unikraft/app/project_options.go +++ b/unikraft/app/project_options.go @@ -17,7 +17,6 @@ package app import ( - "fmt" "io" "os" "path/filepath" @@ -25,6 +24,7 @@ import ( interp "github.com/compose-spec/compose-go/interpolation" "github.com/compose-spec/compose-go/template" + "github.com/juju/errors" "kraftkit.sh/kconfig" ) @@ -290,7 +290,7 @@ func WithProjectDefaultKraftfiles() ProjectOption { candidates := findFiles(DefaultFileNames, pwd) if len(candidates) > 0 { if len(candidates) > 1 { - return fmt.Errorf("found multiple config files with supported names: %s", strings.Join(candidates, ", ")) + return errors.Errorf("found multiple config files with supported names: %s", strings.Join(candidates, ", ")) } return popts.AddKraftfile(candidates[0]) diff --git a/unikraft/arch/architecture.go b/unikraft/arch/architecture.go index 17d7c8a77..4eb421549 100644 --- a/unikraft/arch/architecture.go +++ b/unikraft/arch/architecture.go @@ -6,10 +6,10 @@ package arch import ( "context" - "fmt" "os" "strings" + "github.com/juju/errors" "kraftkit.sh/kconfig" "kraftkit.sh/unikraft" "kraftkit.sh/unikraft/component" @@ -42,7 +42,7 @@ func NewArchitectureFromSchema(value string) (ArchitectureConfig, error) { architecture := ArchitectureConfig{} if len(value) == 0 { - return architecture, fmt.Errorf("cannot ommit architecture name") + return architecture, errors.New("cannot ommit architecture name") } architecture.name = value diff --git a/unikraft/arch/host.go b/unikraft/arch/host.go index 0a9e2cfee..e02b87164 100644 --- a/unikraft/arch/host.go +++ b/unikraft/arch/host.go @@ -5,8 +5,9 @@ package arch import ( - "fmt" "runtime" + + "github.com/juju/errors" ) // HostArchitecture returns the architecture of the host or an error if @@ -19,6 +20,6 @@ func HostArchitecture() (string, error) { case "arm", "arm64": return arch, nil default: - return "", fmt.Errorf("unsupported architecture: %v", arch) + return "", errors.Errorf("unsupported architecture: %v", arch) } } diff --git a/unikraft/arch/transform.go b/unikraft/arch/transform.go index af5c273bc..0b16e05cc 100644 --- a/unikraft/arch/transform.go +++ b/unikraft/arch/transform.go @@ -6,8 +6,8 @@ package arch import ( "context" - "fmt" + "github.com/juju/errors" "kraftkit.sh/unikraft" ) @@ -21,7 +21,7 @@ func TransformFromSchema(ctx context.Context, data interface{}) (interface{}, er case string: architecture.name = value default: - return nil, fmt.Errorf("invalid type %T for architecture", data) + return nil, errors.Errorf("invalid type %T for architecture", data) } if uk != nil && uk.UK_BASE != "" { diff --git a/unikraft/core/core.go b/unikraft/core/core.go index 06eefb7d1..13fc404d7 100644 --- a/unikraft/core/core.go +++ b/unikraft/core/core.go @@ -6,10 +6,10 @@ package core import ( "context" - "fmt" "os" "path/filepath" + "github.com/juju/errors" "kraftkit.sh/kconfig" "kraftkit.sh/unikraft" "kraftkit.sh/unikraft/component" @@ -89,7 +89,7 @@ func (uc UnikraftConfig) IsUnpacked() bool { func (uc UnikraftConfig) KConfigTree(ctx context.Context, extra ...*kconfig.KeyValue) (*kconfig.KConfigFile, error) { config_uk := filepath.Join(uc.Path(), unikraft.Config_uk) if _, err := os.Stat(config_uk); err != nil { - return nil, fmt.Errorf("could not read component Config.uk: %v", err) + return nil, errors.Annotate(err, "could not read component Config.uk") } return kconfig.Parse(config_uk, uc.kconfig.Override(extra...).Slice()...) diff --git a/unikraft/elfloader/elfloader_pack.go b/unikraft/elfloader/elfloader_pack.go index 9c6a4155d..b788c8e07 100644 --- a/unikraft/elfloader/elfloader_pack.go +++ b/unikraft/elfloader/elfloader_pack.go @@ -6,8 +6,8 @@ package elfloader import ( "context" - "fmt" + "github.com/juju/errors" "kraftkit.sh/initrd" "kraftkit.sh/oci" "kraftkit.sh/pack" @@ -88,13 +88,13 @@ func NewELFLoaderFromPrebuilt(ctx context.Context, linuxu string, pbopts ...ELFL } if len(results) == 0 { - return nil, fmt.Errorf("could not find elfloader") + return nil, errors.New("could not find elfloader") } else if len(results) > 1 { options := make([]string, len(results)) for i, result := range results { options[i] = result.Name() } - return nil, fmt.Errorf("too many options: %v", options) + return nil, errors.Errorf("too many options: %v", options) } elfloader.pack = results[0] diff --git a/unikraft/export/v0/ukargparse/parse.go b/unikraft/export/v0/ukargparse/parse.go index 8ac243b9c..5792a0b37 100644 --- a/unikraft/export/v0/ukargparse/parse.go +++ b/unikraft/export/v0/ukargparse/parse.go @@ -5,8 +5,9 @@ package ukargparse import ( - "fmt" "strings" + + "github.com/juju/errors" ) type Params []Param @@ -19,7 +20,7 @@ func Parse(args ...string) (Params, error) { for _, arg := range args { libAndName := strings.SplitN(arg, ".", 1) if len(libAndName) != 2 { - return nil, fmt.Errorf("expected param to be in the format 'libname.param=value' but got: '%s'", arg) + return nil, errors.Errorf("expected param to be in the format 'libname.param=value' but got: '%s'", arg) } param := paramStr{ diff --git a/unikraft/lib/library.go b/unikraft/lib/library.go index 122237fc5..fe04dfb8f 100644 --- a/unikraft/lib/library.go +++ b/unikraft/lib/library.go @@ -7,12 +7,12 @@ package lib import ( "bufio" "context" - "fmt" "io" "os" "path/filepath" "strings" + "github.com/juju/errors" "github.com/sirupsen/logrus" "kraftkit.sh/kconfig" "kraftkit.sh/log" @@ -181,7 +181,7 @@ func (lc LibraryConfig) Path() string { func (lc LibraryConfig) KConfigTree(_ context.Context, env ...*kconfig.KeyValue) (*kconfig.KConfigFile, error) { config_uk := filepath.Join(lc.Path(), unikraft.Config_uk) if _, err := os.Stat(config_uk); err != nil { - return nil, fmt.Errorf("could not read component Config.uk: %v", err) + return nil, errors.Annotate(err, "could not read component Config.uk") } return kconfig.Parse(config_uk, lc.kconfig.Override(env...).Slice()...) @@ -215,7 +215,7 @@ func NewFromDir(ctx context.Context, dir string, opts ...LibraryOption) (Librari makefile_uk := filepath.Join(dir, unikraft.Makefile_uk) if _, err := os.Stat(makefile_uk); err != nil { - return nil, fmt.Errorf("cannot parse library from directory without Makefile.uk") + return nil, errors.New("cannot parse library from directory without Makefile.uk") } // TODO: Parse the Config.uk file to grab even more information, e.g. @@ -231,7 +231,7 @@ func NewFromDir(ctx context.Context, dir string, opts ...LibraryOption) (Librari fm, err := os.Open(makefile_uk) if err != nil { - return nil, fmt.Errorf("could not open Makefile.uk: %v", err) + return nil, errors.Annotate(err, "could not open Makefile.uk") } defer fm.Close() @@ -402,7 +402,7 @@ func NewFromDir(ctx context.Context, dir string, opts ...LibraryOption) (Librari }).Trace("reading") fe, err := os.Open(exportsyms_uk) if err != nil { - return nil, fmt.Errorf("could not open exportsyms.uk: %v", err) + return nil, errors.Annotate(err, "could not open exportsyms.uk") } defer fe.Close() diff --git a/unikraft/lib/transform.go b/unikraft/lib/transform.go index 16851bfc8..4b85f5058 100644 --- a/unikraft/lib/transform.go +++ b/unikraft/lib/transform.go @@ -6,9 +6,9 @@ package lib import ( "context" - "fmt" "os" + "github.com/juju/errors" "kraftkit.sh/kconfig" "kraftkit.sh/unikraft" "kraftkit.sh/unikraft/component" @@ -81,12 +81,12 @@ func TransformMapFromSchema(ctx context.Context, data interface{}) (interface{}, libraries[name] = comp default: - return data, fmt.Errorf("invalid type %T for component", props) + return data, errors.Errorf("invalid type %T for component", props) } } return libraries, nil } - return data, fmt.Errorf("invalid type %T for library", data) + return data, errors.Errorf("invalid type %T for library", data) } diff --git a/unikraft/plat/transform.go b/unikraft/plat/transform.go index 5511b28c7..8da7c94df 100644 --- a/unikraft/plat/transform.go +++ b/unikraft/plat/transform.go @@ -6,8 +6,8 @@ package plat import ( "context" - "fmt" + "github.com/juju/errors" mplatform "kraftkit.sh/machine/platform" "kraftkit.sh/unikraft" ) @@ -22,7 +22,7 @@ func TransformFromSchema(ctx context.Context, data interface{}) (interface{}, er case string: platform.name = value default: - return nil, fmt.Errorf("invalid type %T for platform", data) + return nil, errors.Errorf("invalid type %T for platform", data) } // If the user has provided an alias for a known internal platform name, diff --git a/unikraft/target/target.go b/unikraft/target/target.go index 1da81f872..e433b4b54 100644 --- a/unikraft/target/target.go +++ b/unikraft/target/target.go @@ -9,6 +9,7 @@ import ( "fmt" "path/filepath" + "github.com/juju/errors" "kraftkit.sh/initrd" "kraftkit.sh/kconfig" "kraftkit.sh/pack" @@ -157,7 +158,7 @@ func (tc *TargetConfig) ConfigFilename() string { } func (tc *TargetConfig) KConfigTree(_ context.Context, env ...*kconfig.KeyValue) (*kconfig.KConfigFile, error) { - return nil, fmt.Errorf("target does not have a Config.uk file") + return nil, errors.New("target does not have a Config.uk file") } func (tc *TargetConfig) PrintInfo(ctx context.Context) string { @@ -169,7 +170,7 @@ func (tc *TargetConfig) PrintInfo(ctx context.Context) string { // If we do not have a target name, return an error. func KernelName(target TargetConfig) (string, error) { if target.Name() == "" { - return "", fmt.Errorf("target name not set, cannot determine binary name") + return "", errors.New("target name not set, cannot determine binary name") } return fmt.Sprintf( diff --git a/unikraft/target/transform.go b/unikraft/target/transform.go index 6493c3d0d..d71dccf8b 100644 --- a/unikraft/target/transform.go +++ b/unikraft/target/transform.go @@ -6,9 +6,9 @@ package target import ( "context" - "fmt" "path/filepath" + "github.com/juju/errors" "kraftkit.sh/kconfig" "kraftkit.sh/unikraft" "kraftkit.sh/unikraft/arch" @@ -82,5 +82,5 @@ func TransformFromSchema(ctx context.Context, data interface{}) (interface{}, er return t, nil } - return data, fmt.Errorf("invalid type %T for target", data) + return data, errors.Errorf("invalid type %T for target", data) } diff --git a/unikraft/type.go b/unikraft/type.go index ea322d152..c38b9f95a 100644 --- a/unikraft/type.go +++ b/unikraft/type.go @@ -6,10 +6,11 @@ package unikraft import ( - "fmt" "path/filepath" "regexp" "strings" + + "github.com/juju/errors" ) type ComponentType string @@ -72,7 +73,7 @@ func GuessTypeNameVersion(input string) (ComponentType, string, string, error) { match := re.FindStringSubmatch(input) if len(match) == 0 { - return ComponentTypeUnknown, "", "", fmt.Errorf("cannot determine name and type from \"%s\"", input) + return ComponentTypeUnknown, "", "", errors.Errorf("cannot determine name and type from \"%s\"", input) } t, n, v := match[1], match[2], match[3] @@ -103,7 +104,7 @@ func PlaceComponent(workdir string, t ComponentType, name string) (string, error return filepath.Join(workdir, VendorDir, t.Plural(), name), nil } - return "", fmt.Errorf("cannot place component of unknown type") + return "", errors.New("cannot place component of unknown type") } // TypeNameVersion returns the canonical name of the component using the format diff --git a/unikraft/utils.go b/unikraft/utils.go index 33aaa829e..dd4c6af99 100644 --- a/unikraft/utils.go +++ b/unikraft/utils.go @@ -2,9 +2,9 @@ package unikraft import ( "debug/elf" - "fmt" "os" + "github.com/juju/errors" "kraftkit.sh/internal/set" ) @@ -16,7 +16,7 @@ func IsFileUnikraftUnikernel(path string) (bool, error) { if err != nil { return false, err } else if fs.IsDir() { - return false, fmt.Errorf("first positional argument is a directory: %v", path) + return false, errors.Errorf("first positional argument is a directory: %v", path) } // Sanity check whether the provided file is an ELF kernel with @@ -44,5 +44,5 @@ func IsFileUnikraftUnikernel(path string) (bool, error) { } } - return false, fmt.Errorf("provided file is not a Unikraft unikernel") + return false, errors.New("provided file is not a Unikraft unikernel") } diff --git a/utils/terminal.go b/utils/terminal.go index 6d9017dda..9cccd5337 100644 --- a/utils/terminal.go +++ b/utils/terminal.go @@ -24,9 +24,9 @@ package utils import ( - "fmt" "os" + "github.com/juju/errors" "github.com/mattn/go-isatty" "golang.org/x/term" ) @@ -44,5 +44,5 @@ var TerminalSize = func(w interface{}) (int, int, error) { return term.GetSize(int(f.Fd())) } - return 0, 0, fmt.Errorf("%v is not a file", w) + return 0, 0, errors.Errorf("%v is not a file", w) }