133 lines
3.1 KiB
Go
133 lines
3.1 KiB
Go
//go:build !remote
|
|
|
|
package libimage
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
|
|
"github.com/containers/common/pkg/download"
|
|
storageTransport "github.com/containers/image/v5/storage"
|
|
tarballTransport "github.com/containers/image/v5/tarball"
|
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// ImportOptions allow for customizing image imports.
|
|
type ImportOptions struct {
|
|
CopyOptions
|
|
|
|
// Apply the specified changes to the created image. Please refer to
|
|
// `ImageConfigFromChanges` for supported change instructions.
|
|
Changes []string
|
|
// Set the commit message as a comment to created image's history.
|
|
CommitMessage string
|
|
// Tag the imported image with this value.
|
|
Tag string
|
|
// Overwrite OS of imported image.
|
|
OS string
|
|
// Overwrite Arch of imported image.
|
|
Arch string
|
|
}
|
|
|
|
// Import imports a custom tarball at the specified path. Returns the name of
|
|
// the imported image.
|
|
func (r *Runtime) Import(ctx context.Context, path string, options *ImportOptions) (string, error) {
|
|
logrus.Debugf("Importing image from %q", path)
|
|
|
|
if options == nil {
|
|
options = &ImportOptions{}
|
|
}
|
|
|
|
ic := v1.ImageConfig{}
|
|
if len(options.Changes) > 0 {
|
|
config, err := ImageConfigFromChanges(options.Changes)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
ic = config.ImageConfig
|
|
}
|
|
|
|
history := []v1.History{
|
|
{Comment: options.CommitMessage},
|
|
}
|
|
|
|
config := v1.Image{
|
|
Config: ic,
|
|
History: history,
|
|
Platform: v1.Platform{
|
|
OS: options.OS,
|
|
Architecture: options.Arch,
|
|
Variant: options.Variant,
|
|
},
|
|
}
|
|
|
|
u, err := url.ParseRequestURI(path)
|
|
if err == nil && u.Scheme != "" {
|
|
// If source is a URL, download the file.
|
|
fmt.Printf("Downloading from %q\n", path) //nolint:forbidigo
|
|
file, err := download.FromURL(r.systemContext.BigFilesTemporaryDir, path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer os.Remove(file)
|
|
path = file
|
|
} else if path == "-" {
|
|
// "-" special cases stdin
|
|
path = os.Stdin.Name()
|
|
}
|
|
|
|
srcRef, err := tarballTransport.Transport.ParseReference(path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
updater, ok := srcRef.(tarballTransport.ConfigUpdater)
|
|
if !ok {
|
|
return "", errors.New("unexpected type, a tarball reference should implement tarball.ConfigUpdater")
|
|
}
|
|
annotations := make(map[string]string)
|
|
if err := updater.ConfigUpdate(config, annotations); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
id, err := getImageID(ctx, srcRef, r.systemContextCopy())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
destRef, err := storageTransport.Transport.ParseStoreReference(r.store, id)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
c, err := r.newCopier(&options.CopyOptions)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer c.Close()
|
|
|
|
if _, err := c.Copy(ctx, srcRef, destRef); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Strip the leading @ off the id.
|
|
name := id[1:]
|
|
|
|
// If requested, tag the imported image.
|
|
if options.Tag != "" {
|
|
image, _, err := r.LookupImage(name, nil)
|
|
if err != nil {
|
|
return "", fmt.Errorf("looking up imported image: %w", err)
|
|
}
|
|
if err := image.Tag(options.Tag); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
return "sha256:" + name, nil
|
|
}
|