diff --git a/cmd/util/unpack.go b/cmd/util/unpack.go new file mode 100644 index 00000000..a073ddbd --- /dev/null +++ b/cmd/util/unpack.go @@ -0,0 +1,72 @@ +// Copyright © 2021 Ettore Di Giacinto +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, see . + +package util + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/docker/go-units" + "github.com/mudler/luet/pkg/config" + "github.com/mudler/luet/pkg/helpers" + . "github.com/mudler/luet/pkg/logger" + + "github.com/spf13/cobra" +) + +func NewUnpackCommand() *cobra.Command { + + return &cobra.Command{ + Use: "unpack image path", + Short: "Unpack a docker image natively", + Long: `unpack doesn't need the docker daemon to run, and unpacks a docker image in the specified directory: + + luet util unpack golang:alpine /alpine +`, + PreRun: func(cmd *cobra.Command, args []string) { + + if len(args) != 2 { + Fatal("Expects an image and a path") + } + + }, + Run: func(cmd *cobra.Command, args []string) { + + image := args[0] + destination, err := filepath.Abs(args[1]) + if err != nil { + Error("Invalid path %s", destination) + os.Exit(1) + } + + temp, err := config.LuetCfg.GetSystem().TempDir("contentstore") + if err != nil { + Fatal("Cannot create a tempdir", err.Error()) + } + + Info("Downloading", image, "to", destination) + info, err := helpers.DownloadAndExtractDockerImage(temp, image, destination) + if err != nil { + Error(err.Error()) + os.Exit(1) + } + Info(fmt.Sprintf("Pulled: %s", info.Target.Digest)) + Info(fmt.Sprintf("Size: %s", units.BytesSize(float64(info.ContentSize)))) + }, + } + +} diff --git a/pkg/helpers/docker.go b/pkg/helpers/docker.go new file mode 100644 index 00000000..a0a323a0 --- /dev/null +++ b/pkg/helpers/docker.go @@ -0,0 +1,44 @@ +// Copyright © 2021 Ettore Di Giacinto +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, see . + +package helpers + +import ( + "os" + + "github.com/mudler/luet/pkg/helpers/imgworker" + "github.com/pkg/errors" +) + +// DownloadAndExtractDockerImage is a re-adaption +// from genuinetools/img https://github.com/genuinetools/img/blob/54d0ca981c1260546d43961a538550eef55c87cf/pull.go +func DownloadAndExtractDockerImage(temp, image, dest string) (*imgworker.ListedImage, error) { + defer os.RemoveAll(temp) + c, err := imgworker.New(temp) + if err != nil { + return nil, errors.Wrapf(err, "failed creating client") + } + defer c.Close() + + listedImage, err := c.Pull(image) + if err != nil { + return nil, errors.Wrapf(err, "failed listing images") + + } + + os.RemoveAll(dest) + err = c.Unpack(image, dest) + return listedImage, err +} diff --git a/pkg/installer/client/imgworker/client.go b/pkg/helpers/imgworker/client.go similarity index 100% rename from pkg/installer/client/imgworker/client.go rename to pkg/helpers/imgworker/client.go diff --git a/pkg/installer/client/imgworker/pull.go b/pkg/helpers/imgworker/pull.go similarity index 100% rename from pkg/installer/client/imgworker/pull.go rename to pkg/helpers/imgworker/pull.go diff --git a/pkg/installer/client/imgworker/session.go b/pkg/helpers/imgworker/session.go similarity index 100% rename from pkg/installer/client/imgworker/session.go rename to pkg/helpers/imgworker/session.go diff --git a/pkg/installer/client/imgworker/unpack.go b/pkg/helpers/imgworker/unpack.go similarity index 100% rename from pkg/installer/client/imgworker/unpack.go rename to pkg/helpers/imgworker/unpack.go diff --git a/pkg/installer/client/imgworker/workeropts.go b/pkg/helpers/imgworker/workeropts.go similarity index 100% rename from pkg/installer/client/imgworker/workeropts.go rename to pkg/helpers/imgworker/workeropts.go diff --git a/pkg/installer/client/docker.go b/pkg/installer/client/docker.go index 9194213a..3998a42a 100644 --- a/pkg/installer/client/docker.go +++ b/pkg/installer/client/docker.go @@ -24,8 +24,6 @@ import ( "github.com/docker/go-units" "github.com/pkg/errors" - imgworker "github.com/mudler/luet/pkg/installer/client/imgworker" - "github.com/mudler/luet/pkg/compiler" "github.com/mudler/luet/pkg/config" "github.com/mudler/luet/pkg/helpers" @@ -40,33 +38,6 @@ func NewDockerClient(r RepoData) *DockerClient { return &DockerClient{RepoData: r} } -func downloadAndExtractDockerImage(image, dest string) error { - temp, err := config.LuetCfg.GetSystem().TempDir("contentstore") - if err != nil { - return err - } - defer os.RemoveAll(temp) - Debug("Temporary directory", temp) - c, err := imgworker.New(temp) - if err != nil { - return errors.Wrapf(err, "failed creating client") - } - defer c.Close() - - // FROM Slightly adapted from genuinetools/img https://github.com/genuinetools/img/blob/54d0ca981c1260546d43961a538550eef55c87cf/pull.go - Debug("Pulling image", image) - listedImage, err := c.Pull(image) - if err != nil { - return errors.Wrapf(err, "failed listing images") - - } - Debug("Pulled:", listedImage.Target.Digest) - Debug("Size:", units.BytesSize(float64(listedImage.ContentSize))) - Debug("Unpacking", image, "to", dest) - os.RemoveAll(dest) - return c.Unpack(image, dest) -} - func (c *DockerClient) DownloadArtifact(artifact compiler.Artifact) (compiler.Artifact, error) { //var u *url.URL = nil var err error @@ -110,12 +81,21 @@ func (c *DockerClient) DownloadArtifact(artifact compiler.Artifact) (compiler.Ar imageName := fmt.Sprintf("%s:%s", uri, artifact.GetCompileSpec().GetPackage().ImageID()) Info("Downloading image", imageName) + contentstore, err := config.LuetCfg.GetSystem().TempDir("contentstore") + if err != nil { + Warning("Cannot create contentstore", err.Error()) + continue + } + // imageName := fmt.Sprintf("%s/%s", uri, artifact.GetCompileSpec().GetPackage().GetPackageImageName()) - err = downloadAndExtractDockerImage(imageName, temp) + info, err := helpers.DownloadAndExtractDockerImage(contentstore, imageName, temp) if err != nil { Debug("Failed download of image", imageName) continue } + + Info(fmt.Sprintf("Pulled: %s", info.Target.Digest)) + Info(fmt.Sprintf("Size: %s", units.BytesSize(float64(info.ContentSize)))) Debug("\nCompressing result ", filepath.Join(temp), "to", cacheFile) newart := artifact @@ -162,16 +142,24 @@ func (c *DockerClient) DownloadFile(name string) (string, error) { continue } - Debug("Downloading file", name, "from", uri) + contentstore, err := config.LuetCfg.GetSystem().TempDir("contentstore") + if err != nil { + Warning("Cannot create contentstore", err.Error()) + continue + } imageName := fmt.Sprintf("%s:%s", uri, name) - //imageName := fmt.Sprintf("%s/%s:%s", uri, "repository", name) - err = downloadAndExtractDockerImage(imageName, temp) + Info("Downloading", imageName) + + info, err := helpers.DownloadAndExtractDockerImage(contentstore, imageName, temp) if err != nil { Debug("Failed download of image", imageName) continue } + Info(fmt.Sprintf("Pulled: %s", info.Target.Digest)) + Info(fmt.Sprintf("Size: %s", units.BytesSize(float64(info.ContentSize)))) + Debug("\nCopying file ", filepath.Join(temp, name), "to", file.Name()) err = helpers.CopyFile(filepath.Join(temp, name), file.Name())