vendor c/common

Also update the e2e pull test to account for the changes when pulling
from the dir transport.  Images pulled via the dir transport are not
tagged anymore; the path is not a reliable source.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2022-01-10 13:47:12 +01:00
parent 6ed2c639ac
commit b7380a7c36
58 changed files with 641 additions and 348 deletions

View File

@ -218,15 +218,7 @@ func (r *Runtime) newCopier(options *CopyOptions) (*copier, error) {
c.systemContext.DockerArchiveAdditionalTags = options.dockerArchiveAdditionalTags
if options.Architecture != "" {
c.systemContext.ArchitectureChoice = options.Architecture
}
if options.OS != "" {
c.systemContext.OSChoice = options.OS
}
if options.Variant != "" {
c.systemContext.VariantChoice = options.Variant
}
c.systemContext.OSChoice, c.systemContext.ArchitectureChoice, c.systemContext.VariantChoice = NormalizePlatform(options.OS, options.Architecture, options.Variant)
if options.SignaturePolicyPath != "" {
c.systemContext.SignaturePolicyPath = options.SignaturePolicyPath

View File

@ -19,26 +19,53 @@ import (
// indicates that the image matches the criteria.
type filterFunc func(*Image) (bool, error)
// filterImages returns a slice of images which are passing all specified
// filters.
func filterImages(images []*Image, filters []filterFunc) ([]*Image, error) {
if len(filters) == 0 {
return images, nil
}
result := []*Image{}
for i := range images {
include := true
var err error
for _, filter := range filters {
include, err = filter(images[i])
// Apply the specified filters. At least one filter of each key must apply.
func (i *Image) applyFilters(filters map[string][]filterFunc) (bool, error) {
matches := false
for key := range filters { // and
matches = false
for _, filter := range filters[key] { // or
var err error
matches, err = filter(i)
if err != nil {
return nil, err
// Some images may have been corrupted in the
// meantime, so do an extra check and make the
// error non-fatal (see containers/podman/issues/12582).
if errCorrupted := i.isCorrupted(""); errCorrupted != nil {
logrus.Errorf(errCorrupted.Error())
return false, nil
}
return false, err
}
if !include {
if matches {
break
}
}
if include {
if !matches {
return false, nil
}
}
return matches, nil
}
// filterImages returns a slice of images which are passing all specified
// filters.
func (r *Runtime) filterImages(ctx context.Context, images []*Image, options *ListImagesOptions) ([]*Image, error) {
if len(options.Filters) == 0 || len(images) == 0 {
return images, nil
}
filters, err := r.compileImageFilters(ctx, options)
if err != nil {
return nil, err
}
result := []*Image{}
for i := range images {
match, err := images[i].applyFilters(filters)
if err != nil {
return nil, err
}
if match {
result = append(result, images[i])
}
}
@ -48,7 +75,7 @@ func filterImages(images []*Image, filters []filterFunc) ([]*Image, error) {
// compileImageFilters creates `filterFunc`s for the specified filters. The
// required format is `key=value` with the following supported keys:
// after, since, before, containers, dangling, id, label, readonly, reference, intermediate
func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOptions) ([]filterFunc, error) {
func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOptions) (map[string][]filterFunc, error) {
logrus.Tracef("Parsing image filters %s", options.Filters)
var tree *layerTree
@ -63,12 +90,14 @@ func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOp
return tree, nil
}
filterFuncs := []filterFunc{}
for _, filter := range options.Filters {
filters := map[string][]filterFunc{}
duplicate := map[string]string{}
for _, f := range options.Filters {
var key, value string
split := strings.SplitN(filter, "=", 2)
var filter filterFunc
split := strings.SplitN(f, "=", 2)
if len(split) != 2 {
return nil, errors.Errorf("invalid image filter %q: must be in the format %q", filter, "filter=value")
return nil, errors.Errorf("invalid image filter %q: must be in the format %q", f, "filter=value")
}
key = split[0]
@ -76,87 +105,148 @@ func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOp
switch key {
case "after", "since":
img, _, err := r.LookupImage(value, nil)
img, err := r.time(key, value)
if err != nil {
return nil, errors.Wrapf(err, "could not find local image for filter %q", filter)
return nil, err
}
filterFuncs = append(filterFuncs, filterAfter(img.Created()))
key = "since"
filter = filterAfter(img.Created())
case "before":
img, _, err := r.LookupImage(value, nil)
img, err := r.time(key, value)
if err != nil {
return nil, errors.Wrapf(err, "could not find local image for filter %q", filter)
return nil, err
}
filterFuncs = append(filterFuncs, filterBefore(img.Created()))
filter = filterBefore(img.Created())
case "containers":
switch value {
case "false", "true":
case "external":
if options.IsExternalContainerFunc == nil {
return nil, fmt.Errorf("libimage error: external containers filter without callback")
}
default:
return nil, fmt.Errorf("unsupported value %q for containers filter", value)
if err := r.containers(duplicate, key, value, options.IsExternalContainerFunc); err != nil {
return nil, err
}
filterFuncs = append(filterFuncs, filterContainers(value, options.IsExternalContainerFunc))
filter = filterContainers(value, options.IsExternalContainerFunc)
case "dangling":
dangling, err := strconv.ParseBool(value)
dangling, err := r.bool(duplicate, key, value)
if err != nil {
return nil, errors.Wrapf(err, "non-boolean value %q for dangling filter", value)
return nil, err
}
t, err := getTree()
if err != nil {
return nil, err
}
filterFuncs = append(filterFuncs, filterDangling(ctx, dangling, t))
filter = filterDangling(ctx, dangling, t)
case "id":
filterFuncs = append(filterFuncs, filterID(value))
filter = filterID(value)
case "intermediate":
intermediate, err := strconv.ParseBool(value)
intermediate, err := r.bool(duplicate, key, value)
if err != nil {
return nil, errors.Wrapf(err, "non-boolean value %q for intermediate filter", value)
return nil, err
}
t, err := getTree()
if err != nil {
return nil, err
}
filterFuncs = append(filterFuncs, filterIntermediate(ctx, intermediate, t))
filter = filterIntermediate(ctx, intermediate, t)
case "label":
filterFuncs = append(filterFuncs, filterLabel(ctx, value))
filter = filterLabel(ctx, value)
case "readonly":
readOnly, err := strconv.ParseBool(value)
readOnly, err := r.bool(duplicate, key, value)
if err != nil {
return nil, errors.Wrapf(err, "non-boolean value %q for readonly filter", value)
return nil, err
}
filterFuncs = append(filterFuncs, filterReadOnly(readOnly))
filter = filterReadOnly(readOnly)
case "manifest":
manifest, err := r.bool(duplicate, key, value)
if err != nil {
return nil, err
}
filter = filterManifest(ctx, manifest)
case "reference":
filterFuncs = append(filterFuncs, filterReferences(value))
filter = filterReferences(value)
case "until":
ts, err := timetype.GetTimestamp(value, time.Now())
until, err := r.until(value)
if err != nil {
return nil, err
}
seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
if err != nil {
return nil, err
}
until := time.Unix(seconds, nanoseconds)
filterFuncs = append(filterFuncs, filterBefore(until))
filter = filterBefore(until)
default:
return nil, errors.Errorf("unsupported image filter %q", key)
}
filters[key] = append(filters[key], filter)
}
return filterFuncs, nil
return filters, nil
}
func (r *Runtime) containers(duplicate map[string]string, key, value string, externalFunc IsExternalContainerFunc) error {
if exists, ok := duplicate[key]; ok && exists != value {
return errors.Errorf("specifying %q filter more than once with different values is not supported", key)
}
duplicate[key] = value
switch value {
case "false", "true":
case "external":
if externalFunc == nil {
return fmt.Errorf("libimage error: external containers filter without callback")
}
default:
return fmt.Errorf("unsupported value %q for containers filter", value)
}
return nil
}
func (r *Runtime) until(value string) (time.Time, error) {
var until time.Time
ts, err := timetype.GetTimestamp(value, time.Now())
if err != nil {
return until, err
}
seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
if err != nil {
return until, err
}
return time.Unix(seconds, nanoseconds), nil
}
func (r *Runtime) time(key, value string) (*Image, error) {
img, _, err := r.LookupImage(value, nil)
if err != nil {
return nil, errors.Wrapf(err, "could not find local image for filter filter %q=%q", key, value)
}
return img, nil
}
func (r *Runtime) bool(duplicate map[string]string, key, value string) (bool, error) {
if exists, ok := duplicate[key]; ok && exists != value {
return false, errors.Errorf("specifying %q filter more than once with different values is not supported", key)
}
duplicate[key] = value
set, err := strconv.ParseBool(value)
if err != nil {
return false, errors.Wrapf(err, "non-boolean value %q for %s filter", key, value)
}
return set, nil
}
// filterManifest filters whether or not the image is a manifest list
func filterManifest(ctx context.Context, value bool) filterFunc {
return func(img *Image) (bool, error) {
isManifestList, err := img.IsManifestList(ctx)
if err != nil {
return false, err
}
return isManifestList == value, nil
}
}
// filterReferences creates a reference filter for matching the specified value.

View File

@ -35,17 +35,6 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) (
var loadErrors []error
for _, f := range []func() ([]string, string, error){
// DOCKER-ARCHIVE - must be first (see containers/podman/issues/10809)
func() ([]string, string, error) {
logrus.Debugf("-> Attempting to load %q as a Docker archive", path)
ref, err := dockerArchiveTransport.ParseReference(path)
if err != nil {
return nil, dockerArchiveTransport.Transport.Name(), err
}
images, err := r.loadMultiImageDockerArchive(ctx, ref, &options.CopyOptions)
return images, dockerArchiveTransport.Transport.Name(), err
},
// OCI
func() ([]string, string, error) {
logrus.Debugf("-> Attempting to load %q as an OCI directory", path)
@ -68,6 +57,17 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) (
return images, ociArchiveTransport.Transport.Name(), err
},
// DOCKER-ARCHIVE
func() ([]string, string, error) {
logrus.Debugf("-> Attempting to load %q as a Docker archive", path)
ref, err := dockerArchiveTransport.ParseReference(path)
if err != nil {
return nil, dockerArchiveTransport.Transport.Name(), err
}
images, err := r.loadMultiImageDockerArchive(ctx, ref, &options.CopyOptions)
return images, dockerArchiveTransport.Transport.Name(), err
},
// DIR
func() ([]string, string, error) {
logrus.Debugf("-> Attempting to load %q as a Docker dir", path)

View File

@ -1,13 +1,51 @@
package libimage
import (
"runtime"
"strings"
"github.com/containerd/containerd/platforms"
"github.com/containers/image/v5/docker/reference"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
// NormalizePlatform normalizes (according to the OCI spec) the specified os,
// arch and variant. If left empty, the individual item will not be normalized.
func NormalizePlatform(rawOS, rawArch, rawVariant string) (os, arch, variant string) {
os, arch, variant = rawOS, rawArch, rawVariant
if os == "" {
os = runtime.GOOS
}
if arch == "" {
arch = runtime.GOARCH
}
rawPlatform := os + "/" + arch
if variant != "" {
rawPlatform += "/" + variant
}
normalizedPlatform, err := platforms.Parse(rawPlatform)
if err != nil {
logrus.Debugf("Error normalizing platform: %v", err)
return rawOS, rawArch, rawVariant
}
logrus.Debugf("Normalized platform %s to %s", rawPlatform, normalizedPlatform)
os = rawOS
if rawOS != "" {
os = normalizedPlatform.OS
}
arch = rawArch
if rawArch != "" {
arch = normalizedPlatform.Architecture
}
variant = rawVariant
if rawVariant != "" {
variant = normalizedPlatform.Variant
}
return os, arch, variant
}
// NormalizeName normalizes the provided name according to the conventions by
// Podman and Buildah. If tag and digest are missing, the "latest" tag will be
// used. If it's a short name, it will be prefixed with "localhost/".

View File

@ -21,6 +21,7 @@ import (
"github.com/containers/image/v5/types"
"github.com/containers/storage"
digest "github.com/opencontainers/go-digest"
ociSpec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@ -169,6 +170,20 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP
return localImages, pullError
}
// nameFromAnnotations returns a reference string to be used as an image name,
// or an empty string. The annotations map may be nil.
func nameFromAnnotations(annotations map[string]string) string {
if annotations == nil {
return ""
}
// buildkit/containerd are using a custom annotation see
// containers/podman/issues/12560.
if annotations["io.containerd.image.name"] != "" {
return annotations["io.containerd.image.name"]
}
return annotations[ociSpec.AnnotationRefName]
}
// copyFromDefault is the default copier for a number of transports. Other
// transports require some specific dancing, sometimes Yoga.
func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]string, error) {
@ -201,15 +216,16 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
if err != nil {
return nil, err
}
// if index.json has no reference name, compute the image ID instead
if manifestDescriptor.Annotations == nil || manifestDescriptor.Annotations["org.opencontainers.image.ref.name"] == "" {
storageName = nameFromAnnotations(manifestDescriptor.Annotations)
switch len(storageName) {
case 0:
// If there's no reference name in the annotations, compute an ID.
storageName, err = getImageID(ctx, ref, nil)
if err != nil {
return nil, err
}
imageName = "sha256:" + storageName[1:]
} else {
storageName = manifestDescriptor.Annotations["org.opencontainers.image.ref.name"]
default:
named, err := NormalizeName(storageName)
if err != nil {
return nil, err
@ -227,8 +243,14 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
imageName = named.String()
default:
storageName = toLocalImageName(ref.StringWithinTransport())
imageName = storageName
// Path-based transports (e.g., dir) may include invalid
// characters, so we should pessimistically generate an ID
// instead of looking at the StringWithinTransport().
storageName, err = getImageID(ctx, ref, nil)
if err != nil {
return nil, err
}
imageName = "sha256:" + storageName[1:]
}
// Create a storage reference.

View File

@ -253,6 +253,8 @@ func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image,
if options.Variant == "" {
options.Variant = r.systemContext.VariantChoice
}
// Normalize platform to be OCI compatible (e.g., "aarch64" -> "arm64").
options.OS, options.Architecture, options.Variant = NormalizePlatform(options.OS, options.Architecture, options.Variant)
// First, check if we have an exact match in the storage. Maybe an ID
// or a fully-qualified image name.
@ -404,9 +406,15 @@ func (r *Runtime) lookupImageInDigestsAndRepoTags(name string, options *LookupIm
digest := digested.Digest()
for _, image := range allImages {
for _, d := range image.Digests() {
if d == digest {
return image, name, nil
if d != digest {
continue
}
// Also make sure that the matching image fits all criteria (e.g., manifest list).
if _, err := r.lookupImageInLocalStorage(name, image.ID(), options); err != nil {
return nil, "", err
}
return image, name, nil
}
}
return nil, "", errors.Wrap(storage.ErrImageUnknown, name)
@ -489,13 +497,16 @@ func (r *Runtime) imageReferenceMatchesContext(ref types.ImageReference, options
}
if options.Architecture != "" && options.Architecture != data.Architecture {
return false, err
logrus.Debugf("architecture %q does not match architecture %q of image %s", options.Architecture, data.Architecture, ref)
return false, nil
}
if options.OS != "" && options.OS != data.Os {
return false, err
logrus.Debugf("OS %q does not match OS %q of image %s", options.OS, data.Os, ref)
return false, nil
}
if options.Variant != "" && options.Variant != data.Variant {
return false, err
logrus.Debugf("variant %q does not match variant %q of image %s", options.Variant, data.Variant, ref)
return false, nil
}
return true, nil
@ -551,16 +562,7 @@ func (r *Runtime) ListImages(ctx context.Context, names []string, options *ListI
}
}
var filters []filterFunc
if len(options.Filters) > 0 {
compiledFilters, err := r.compileImageFilters(ctx, options)
if err != nil {
return nil, err
}
filters = append(filters, compiledFilters...)
}
return filterImages(images, filters)
return r.filterImages(ctx, images, options)
}
// RemoveImagesOptions allow for customizing image removal.

View File

@ -365,6 +365,29 @@ func readFileAsUint64(path string) (uint64, error) {
return ret, nil
}
func readFileByKeyAsUint64(path, key string) (uint64, error) {
content, err := ioutil.ReadFile(path)
if err != nil {
return 0, err
}
for _, line := range strings.Split(string(content), "\n") {
fields := strings.SplitN(line, " ", 2)
if fields[0] == key {
v := cleanString(string(fields[1]))
if v == "max" {
return math.MaxUint64, nil
}
ret, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return ret, errors.Wrapf(err, "parse %s from %s", v, path)
}
return ret, nil
}
}
return 0, fmt.Errorf("no key named %s from %s", key, path)
}
// New creates a new cgroup control
func New(path string, resources *spec.LinuxResources) (*CgroupControl, error) {
cgroup2, err := IsCgroup2UnifiedMode()
@ -509,32 +532,6 @@ func (c *CgroupControl) Delete() error {
return c.DeleteByPath(c.path)
}
// rmDirRecursively delete recursively a cgroup directory.
// It differs from os.RemoveAll as it doesn't attempt to unlink files.
// On cgroupfs we are allowed only to rmdir empty directories.
func rmDirRecursively(path string) error {
if err := os.Remove(path); err == nil || os.IsNotExist(err) {
return nil
}
entries, err := ioutil.ReadDir(path)
if err != nil {
return err
}
for _, i := range entries {
if i.IsDir() {
if err := rmDirRecursively(filepath.Join(path, i.Name())); err != nil {
return err
}
}
}
if err := os.Remove(path); err != nil {
if !os.IsNotExist(err) {
return errors.Wrapf(err, "remove %s", path)
}
}
return nil
}
// DeleteByPathConn deletes the specified cgroup path using the specified
// dbus connection if needed.
func (c *CgroupControl) DeleteByPathConn(path string, conn *systemdDbus.Conn) error {

View File

@ -5,11 +5,13 @@ package cgroups
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"syscall"
"time"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
@ -88,3 +90,40 @@ func UserOwnsCurrentSystemdCgroup() (bool, error) {
}
return true, nil
}
// rmDirRecursively delete recursively a cgroup directory.
// It differs from os.RemoveAll as it doesn't attempt to unlink files.
// On cgroupfs we are allowed only to rmdir empty directories.
func rmDirRecursively(path string) error {
if err := os.Remove(path); err == nil || os.IsNotExist(err) {
return nil
}
entries, err := ioutil.ReadDir(path)
if err != nil {
return err
}
for _, i := range entries {
if i.IsDir() {
if err := rmDirRecursively(filepath.Join(path, i.Name())); err != nil {
return err
}
}
}
attempts := 0
for {
err := os.Remove(path)
if err == nil || os.IsNotExist(err) {
return nil
}
if errors.Is(err, unix.EBUSY) {
// attempt up to 5 seconds if the cgroup is busy
if attempts < 500 {
time.Sleep(time.Millisecond * 10)
attempts++
continue
}
}
return errors.Wrapf(err, "remove %s", path)
}
}

View File

@ -2,6 +2,10 @@
package cgroups
import (
"os"
)
// IsCgroup2UnifiedMode returns whether we are running in cgroup 2 cgroup2 mode.
func IsCgroup2UnifiedMode() (bool, error) {
return false, nil
@ -12,3 +16,7 @@ func IsCgroup2UnifiedMode() (bool, error) {
func UserOwnsCurrentSystemdCgroup() (bool, error) {
return false, nil
}
func rmDirRecursively(path string) error {
return os.RemoveAll(path)
}

View File

@ -7,8 +7,7 @@ import (
spec "github.com/opencontainers/runtime-spec/specs-go"
)
type memHandler struct {
}
type memHandler struct{}
func getMemoryHandler() *memHandler {
return &memHandler{}
@ -41,22 +40,23 @@ func (c *memHandler) Stat(ctr *CgroupControl, m *Metrics) error {
usage := MemoryUsage{}
var memoryRoot string
filenames := map[string]string{}
var limitFilename string
if ctr.cgroup2 {
memoryRoot = filepath.Join(cgroupRoot, ctr.path)
filenames["usage"] = "memory.current"
filenames["limit"] = "memory.max"
limitFilename = "memory.max"
if usage.Usage, err = readFileByKeyAsUint64(filepath.Join(memoryRoot, "memory.stat"), "anon"); err != nil {
return err
}
} else {
memoryRoot = ctr.getCgroupv1Path(Memory)
filenames["usage"] = "memory.usage_in_bytes"
filenames["limit"] = "memory.limit_in_bytes"
limitFilename = "memory.limit_in_bytes"
if usage.Usage, err = readFileAsUint64(filepath.Join(memoryRoot, "memory.usage_in_bytes")); err != nil {
return err
}
}
usage.Usage, err = readFileAsUint64(filepath.Join(memoryRoot, filenames["usage"]))
if err != nil {
return err
}
usage.Limit, err = readFileAsUint64(filepath.Join(memoryRoot, filenames["limit"]))
usage.Limit, err = readFileAsUint64(filepath.Join(memoryRoot, limitFilename))
if err != nil {
return err
}

View File

@ -34,6 +34,9 @@ func (c *pidHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) error {
// Create the cgroup
func (c *pidHandler) Create(ctr *CgroupControl) (bool, error) {
if ctr.cgroup2 {
return false, nil
}
return ctr.createCgroupDirectory(Pids)
}

View File

@ -48,6 +48,18 @@ const (
BoltDBStateStore RuntimeStateStore = iota
)
// ProxyEnv is a list of Proxy Environment variables
var ProxyEnv = []string{
"http_proxy",
"https_proxy",
"ftp_proxy",
"no_proxy",
"HTTP_PROXY",
"HTTPS_PROXY",
"FTP_PROXY",
"NO_PROXY",
}
// Config contains configuration options for container tools
type Config struct {
// Containers specify settings that configure how containers will run ont the system
@ -897,8 +909,7 @@ func (c *Config) GetDefaultEnvEx(envHost, httpProxy bool) []string {
if envHost {
env = append(env, os.Environ()...)
} else if httpProxy {
proxy := []string{"http_proxy", "https_proxy", "ftp_proxy", "no_proxy", "HTTP_PROXY", "HTTPS_PROXY", "FTP_PROXY", "NO_PROXY"}
for _, p := range proxy {
for _, p := range ProxyEnv {
if val, ok := os.LookupEnv(p); ok {
env = append(env, fmt.Sprintf("%s=%s", p, val))
}

View File

@ -11,6 +11,7 @@ import (
"github.com/containers/common/pkg/apparmor"
"github.com/containers/common/pkg/cgroupv2"
"github.com/containers/common/pkg/util"
"github.com/containers/storage/pkg/homedir"
"github.com/containers/storage/pkg/unshare"
"github.com/containers/storage/types"
@ -202,7 +203,6 @@ func DefaultConfig() (*Config, error) {
UserNSSize: DefaultUserNSSize,
},
Network: NetworkConfig{
NetworkBackend: "cni",
DefaultNetwork: "podman",
DefaultSubnet: DefaultSubnet,
NetworkConfigDir: cniConfig,
@ -371,7 +371,7 @@ func defaultTmpDir() (string, error) {
return "/run/libpod", nil
}
runtimeDir, err := getRuntimeDir()
runtimeDir, err := util.GetRuntimeDir()
if err != nil {
return "", err
}

View File

@ -1,3 +1,5 @@
// +build linux,seccomp
package seccomp
import (

24
vendor/github.com/containers/common/pkg/util/util.go generated vendored Normal file
View File

@ -0,0 +1,24 @@
package util
import "regexp"
// StringInSlice determines if a string is in a string slice, returns bool
func StringInSlice(s string, sl []string) bool {
for _, i := range sl {
if i == s {
return true
}
}
return false
}
// StringMatchRegexSlice determines if a given string matches one of the given regexes, returns bool
func StringMatchRegexSlice(s string, re []string) bool {
for _, r := range re {
m, err := regexp.MatchString(r, s)
if err == nil && m {
return true
}
}
return false
}

View File

@ -1,6 +1,6 @@
// +build linux darwin
package config
package util
import (
"fmt"
@ -19,8 +19,8 @@ var (
rootlessRuntimeDir string
)
// getRuntimeDir returns the runtime directory
func getRuntimeDir() (string, error) {
// GetRuntimeDir returns the runtime directory
func GetRuntimeDir() (string, error) {
var rootlessRuntimeDirError error
rootlessRuntimeDirOnce.Do(func() {

View File

@ -1,12 +1,12 @@
// +build windows
package config
package util
import (
"github.com/pkg/errors"
)
// getRuntimeDir returns the runtime directory
func getRuntimeDir() (string, error) {
func GetRuntimeDir() (string, error) {
return "", errors.New("this function is not implemented for windows")
}