diff options
Diffstat (limited to 'vendor/github.com/projectatomic/buildah/util/util.go')
-rw-r--r-- | vendor/github.com/projectatomic/buildah/util/util.go | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/vendor/github.com/projectatomic/buildah/util/util.go b/vendor/github.com/projectatomic/buildah/util/util.go new file mode 100644 index 000000000..49d6fcc4e --- /dev/null +++ b/vendor/github.com/projectatomic/buildah/util/util.go @@ -0,0 +1,221 @@ +package util + +import ( + "fmt" + "io" + "net/url" + "path" + "strings" + "time" + + "github.com/containers/image/directory" + dockerarchive "github.com/containers/image/docker/archive" + "github.com/containers/image/docker/reference" + ociarchive "github.com/containers/image/oci/archive" + "github.com/containers/image/pkg/sysregistries" + is "github.com/containers/image/storage" + "github.com/containers/image/tarball" + "github.com/containers/image/types" + "github.com/containers/storage" + "github.com/docker/distribution/registry/api/errcode" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +const ( + minimumTruncatedIDLength = 3 +) + +var ( + // RegistryDefaultPathPrefix contains a per-registry listing of default prefixes + // to prepend to image names that only contain a single path component. + RegistryDefaultPathPrefix = map[string]string{ + "index.docker.io": "library", + "docker.io": "library", + } + // Transports contains the possible transports used for images + Transports = map[string]string{ + dockerarchive.Transport.Name(): "", + ociarchive.Transport.Name(): "", + directory.Transport.Name(): "", + tarball.Transport.Name(): "", + } + // DockerArchive is the transport we prepend to an image name + // when saving to docker-archive + DockerArchive = dockerarchive.Transport.Name() + // OCIArchive is the transport we prepend to an image name + // when saving to oci-archive + OCIArchive = ociarchive.Transport.Name() + // DirTransport is the transport for pushing and pulling + // images to and from a directory + DirTransport = directory.Transport.Name() + // TarballTransport is the transport for importing a tar archive + // and creating a filesystem image + TarballTransport = tarball.Transport.Name() +) + +// ResolveName checks if name is a valid image name, and if that name doesn't include a domain +// portion, returns a list of the names which it might correspond to in the registries. +func ResolveName(name string, firstRegistry string, sc *types.SystemContext, store storage.Store) []string { + if name == "" { + return nil + } + + // Maybe it's a truncated image ID. Don't prepend a registry name, then. + if len(name) >= minimumTruncatedIDLength { + if img, err := store.Image(name); err == nil && img != nil && strings.HasPrefix(img.ID, name) { + // It's a truncated version of the ID of an image that's present in local storage; + // we need to expand the ID. + return []string{img.ID} + } + } + + // If the image is from a different transport + split := strings.SplitN(name, ":", 2) + if len(split) == 2 { + if _, ok := Transports[split[0]]; ok { + return []string{split[1]} + } + } + + // If the image name already included a domain component, we're done. + named, err := reference.ParseNormalizedNamed(name) + if err != nil { + return []string{name} + } + if named.String() == name { + // Parsing produced the same result, so there was a domain name in there to begin with. + return []string{name} + } + if reference.Domain(named) != "" && RegistryDefaultPathPrefix[reference.Domain(named)] != "" { + // If this domain can cause us to insert something in the middle, check if that happened. + repoPath := reference.Path(named) + domain := reference.Domain(named) + defaultPrefix := RegistryDefaultPathPrefix[reference.Domain(named)] + "/" + if strings.HasPrefix(repoPath, defaultPrefix) && path.Join(domain, repoPath[len(defaultPrefix):]) == name { + // Yup, parsing just inserted a bit in the middle, so there was a domain name there to begin with. + return []string{name} + } + } + + // Figure out the list of registries. + registries, err := sysregistries.GetRegistries(sc) + if err != nil { + logrus.Debugf("unable to complete image name %q: %v", name, err) + return []string{name} + } + if sc.DockerInsecureSkipTLSVerify { + if unverifiedRegistries, err := sysregistries.GetInsecureRegistries(sc); err == nil { + registries = append(registries, unverifiedRegistries...) + } + } + + // Create all of the combinations. Some registries need an additional component added, so + // use our lookaside map to keep track of them. If there are no configured registries, at + // least return the name as it was passed to us. + candidates := []string{} + for _, registry := range append([]string{firstRegistry}, registries...) { + if registry == "" { + continue + } + middle := "" + if prefix, ok := RegistryDefaultPathPrefix[registry]; ok && strings.IndexRune(name, '/') == -1 { + middle = prefix + } + candidate := path.Join(registry, middle, name) + candidates = append(candidates, candidate) + } + if len(candidates) == 0 { + candidates = append(candidates, name) + } + return candidates +} + +// ExpandNames takes unqualified names, parses them as image names, and returns +// the fully expanded result, including a tag. Names which don't include a registry +// name will be marked for the most-preferred registry (i.e., the first one in our +// configuration). +func ExpandNames(names []string) ([]string, error) { + expanded := make([]string, 0, len(names)) + for _, n := range names { + name, err := reference.ParseNormalizedNamed(n) + if err != nil { + return nil, errors.Wrapf(err, "error parsing name %q", n) + } + name = reference.TagNameOnly(name) + tag := "" + digest := "" + if tagged, ok := name.(reference.NamedTagged); ok { + tag = ":" + tagged.Tag() + } + if digested, ok := name.(reference.Digested); ok { + digest = "@" + digested.Digest().String() + } + expanded = append(expanded, name.Name()+tag+digest) + } + return expanded, nil +} + +// FindImage locates the locally-stored image which corresponds to a given name. +func FindImage(store storage.Store, image string) (*storage.Image, error) { + var img *storage.Image + ref, err := is.Transport.ParseStoreReference(store, image) + if err == nil { + img, err = is.Transport.GetStoreImage(store, ref) + } + if err != nil { + img2, err2 := store.Image(image) + if err2 != nil { + if ref == nil { + return nil, errors.Wrapf(err, "error parsing reference to image %q", image) + } + return nil, errors.Wrapf(err, "unable to locate image %q", image) + } + img = img2 + } + return img, nil +} + +// AddImageNames adds the specified names to the specified image. +func AddImageNames(store storage.Store, image *storage.Image, addNames []string) error { + names, err := ExpandNames(addNames) + if err != nil { + return err + } + err = store.SetNames(image.ID, append(image.Names, names...)) + if err != nil { + return errors.Wrapf(err, "error adding names (%v) to image %q", names, image.ID) + } + return nil +} + +// GetFailureCause checks the type of the error "err" and returns a new +// error message that reflects the reason of the failure. +// In case err type is not a familiar one the error "defaultError" is returned. +func GetFailureCause(err, defaultError error) error { + switch nErr := errors.Cause(err).(type) { + case errcode.Errors: + return err + case errcode.Error, *url.Error: + return nErr + default: + return defaultError + } +} + +// GetLocalTime discover the UTC offset and then add that to the +// passed in time to arrive at the local time. +func GetLocalTime(localTime time.Time) time.Time { + t := time.Now() + _, offset := t.Local().Zone() + localTime = localTime.Add(time.Second * time.Duration(offset)) + return localTime +} + +// WriteError writes `lastError` into `w` if not nil and return the next error `err` +func WriteError(w io.Writer, err error, lastError error) error { + if lastError != nil { + fmt.Fprintln(w, lastError) + } + return err +} |