summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xAPI.md444
-rw-r--r--Makefile12
-rw-r--r--cmd/podman/attach.go5
-rw-r--r--cmd/podman/build.go114
-rw-r--r--cmd/podman/checkpoint.go1
-rw-r--r--cmd/podman/cleanup.go23
-rw-r--r--cmd/podman/cliconfig/config.go6
-rw-r--r--cmd/podman/commands.go60
-rw-r--r--cmd/podman/commands_remoteclient.go26
-rw-r--r--cmd/podman/commit.go2
-rw-r--r--cmd/podman/common.go24
-rw-r--r--cmd/podman/common_test.go26
-rw-r--r--cmd/podman/container.go7
-rw-r--r--cmd/podman/containers_prune.go14
-rw-r--r--cmd/podman/create.go5
-rw-r--r--cmd/podman/diff.go4
-rw-r--r--cmd/podman/exec.go2
-rw-r--r--cmd/podman/exists.go3
-rw-r--r--cmd/podman/export.go2
-rw-r--r--cmd/podman/generate.go2
-rw-r--r--cmd/podman/generate_kube.go1
-rw-r--r--cmd/podman/history.go4
-rw-r--r--cmd/podman/image.go7
-rw-r--r--cmd/podman/images.go9
-rw-r--r--cmd/podman/images_prune.go1
-rw-r--r--cmd/podman/import.go2
-rw-r--r--cmd/podman/info.go2
-rw-r--r--cmd/podman/inspect.go2
-rw-r--r--cmd/podman/kill.go2
-rw-r--r--cmd/podman/load.go2
-rw-r--r--cmd/podman/login.go2
-rw-r--r--cmd/podman/logout.go2
-rw-r--r--cmd/podman/logs.go2
-rw-r--r--cmd/podman/main.go26
-rw-r--r--cmd/podman/mount.go2
-rw-r--r--cmd/podman/pause.go2
-rw-r--r--cmd/podman/play.go15
-rw-r--r--cmd/podman/play_kube.go1
-rw-r--r--cmd/podman/pod.go2
-rw-r--r--cmd/podman/pod_create.go1
-rw-r--r--cmd/podman/pod_inspect.go1
-rw-r--r--cmd/podman/pod_kill.go1
-rw-r--r--cmd/podman/pod_pause.go1
-rw-r--r--cmd/podman/pod_ps.go1
-rw-r--r--cmd/podman/pod_restart.go1
-rw-r--r--cmd/podman/pod_rm.go1
-rw-r--r--cmd/podman/pod_start.go1
-rw-r--r--cmd/podman/pod_stats.go1
-rw-r--r--cmd/podman/pod_stop.go1
-rw-r--r--cmd/podman/pod_top.go1
-rw-r--r--cmd/podman/pod_unpause.go1
-rw-r--r--cmd/podman/port.go9
-rw-r--r--cmd/podman/ps.go4
-rw-r--r--cmd/podman/pull.go2
-rw-r--r--cmd/podman/push.go17
-rw-r--r--cmd/podman/refresh.go2
-rw-r--r--cmd/podman/restart.go2
-rw-r--r--cmd/podman/restore.go2
-rw-r--r--cmd/podman/rm.go18
-rw-r--r--cmd/podman/rmi.go3
-rw-r--r--cmd/podman/run.go47
-rw-r--r--cmd/podman/runlabel.go1
-rw-r--r--cmd/podman/save.go3
-rw-r--r--cmd/podman/search.go3
-rw-r--r--cmd/podman/shared/container.go7
-rw-r--r--cmd/podman/sign.go3
-rw-r--r--cmd/podman/start.go12
-rw-r--r--cmd/podman/stats.go3
-rw-r--r--cmd/podman/stop.go3
-rw-r--r--cmd/podman/system.go7
-rw-r--r--cmd/podman/system_prune.go4
-rw-r--r--cmd/podman/tag.go3
-rw-r--r--cmd/podman/top.go3
-rw-r--r--cmd/podman/trust.go1
-rw-r--r--cmd/podman/trust_set_show.go3
-rw-r--r--cmd/podman/umount.go3
-rw-r--r--cmd/podman/unpause.go3
-rw-r--r--cmd/podman/varlink.go7
-rw-r--r--cmd/podman/varlink/io.podman.varlink220
-rw-r--r--cmd/podman/varlink_dummy.go10
-rw-r--r--cmd/podman/version.go2
-rw-r--r--cmd/podman/volume.go2
-rw-r--r--cmd/podman/volume_create.go37
-rw-r--r--cmd/podman/volume_inspect.go23
-rw-r--r--cmd/podman/volume_ls.go43
-rw-r--r--cmd/podman/volume_prune.go1
-rw-r--r--cmd/podman/volume_rm.go37
-rw-r--r--cmd/podman/wait.go3
-rw-r--r--commands.md1
-rw-r--r--completions/bash/podman1
-rw-r--r--contrib/perftest/main.go2
-rw-r--r--docs/podman-rm.1.md4
-rw-r--r--docs/podman.1.md1
-rwxr-xr-xhack/get_ci_vm.sh33
-rw-r--r--libpod/adapter/runtime.go152
-rw-r--r--libpod/adapter/runtime_remote.go234
-rw-r--r--libpod/adapter/volumes_remote.go33
-rw-r--r--libpod/container.go15
-rw-r--r--libpod/container_attach_linux.go4
-rw-r--r--libpod/container_internal.go154
-rw-r--r--libpod/container_internal_linux.go7
-rw-r--r--libpod/errors.go16
-rw-r--r--libpod/image/utils.go17
-rw-r--r--libpod/kube.go6
-rw-r--r--libpod/options.go3
-rw-r--r--libpod/runtime_ctr.go44
-rw-r--r--libpod/runtime_img.go2
-rw-r--r--libpod/runtime_volume.go51
-rw-r--r--libpod/volume_internal.go4
-rw-r--r--pkg/spec/createconfig.go59
-rw-r--r--pkg/util/utils.go10
-rw-r--r--pkg/varlinkapi/containers.go35
-rw-r--r--pkg/varlinkapi/containers_create.go7
-rw-r--r--pkg/varlinkapi/images.go282
-rw-r--r--pkg/varlinkapi/system.go25
-rw-r--r--pkg/varlinkapi/transfers.go2
-rw-r--r--pkg/varlinkapi/util.go35
-rw-r--r--pkg/varlinkapi/volumes.go74
-rw-r--r--test/bin2img/bin2img.go229
-rw-r--r--test/copyimg/copyimg.go204
-rw-r--r--test/e2e/create_test.go8
-rw-r--r--test/e2e/run_test.go2
-rw-r--r--utils/utils.go12
-rw-r--r--vendor.conf6
-rw-r--r--vendor/github.com/containers/image/copy/copy.go87
-rw-r--r--vendor/github.com/containers/image/docker/docker_client.go33
-rw-r--r--vendor/github.com/containers/image/docker/docker_image.go2
-rw-r--r--vendor/github.com/containers/image/docker/docker_image_dest.go62
-rw-r--r--vendor/github.com/containers/image/docker/docker_image_src.go16
-rw-r--r--vendor/github.com/containers/image/docker/tarfile/src.go76
-rw-r--r--vendor/github.com/containers/image/ostree/ostree_src.go13
-rw-r--r--vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go23
-rw-r--r--vendor/github.com/containers/image/storage/storage_image.go73
-rw-r--r--vendor/github.com/containers/image/storage/storage_reference.go22
-rw-r--r--vendor/github.com/containers/image/storage/storage_transport.go5
-rw-r--r--vendor/github.com/containers/image/version/version.go2
-rw-r--r--vendor/github.com/containers/storage/images.go193
-rw-r--r--vendor/github.com/containers/storage/images_ffjson.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/config/config.go96
-rw-r--r--vendor/github.com/containers/storage/store.go441
-rw-r--r--vendor/github.com/containers/storage/vendor.conf9
-rw-r--r--vendor/github.com/urfave/cli/LICENSE21
-rw-r--r--vendor/github.com/urfave/cli/README.md1526
-rw-r--r--vendor/github.com/urfave/cli/app.go508
-rw-r--r--vendor/github.com/urfave/cli/category.go44
-rw-r--r--vendor/github.com/urfave/cli/cli.go22
-rw-r--r--vendor/github.com/urfave/cli/command.go383
-rw-r--r--vendor/github.com/urfave/cli/context.go287
-rw-r--r--vendor/github.com/urfave/cli/errors.go115
-rw-r--r--vendor/github.com/urfave/cli/flag.go786
-rw-r--r--vendor/github.com/urfave/cli/flag_generated.go640
-rw-r--r--vendor/github.com/urfave/cli/funcs.go44
-rw-r--r--vendor/github.com/urfave/cli/help.go345
-rw-r--r--vendor/github.com/urfave/cli/sort.go29
154 files changed, 2494 insertions, 6618 deletions
diff --git a/API.md b/API.md
index f32325d37..dd19aaf42 100755
--- a/API.md
+++ b/API.md
@@ -3,9 +3,7 @@ Podman Service Interface and API description. The master version of this docume
in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in the upstream libpod repository.
## Index
-[func AttachToContainer() NotImplemented](#AttachToContainer)
-
-[func BuildImage(build: BuildInfo) BuildResponse](#BuildImage)
+[func BuildImage(build: BuildInfo) MoreResponse](#BuildImage)
[func Commit(name: string, image_name: string, changes: []string, author: string, message: string, pause: bool, manifestType: string) string](#Commit)
@@ -27,8 +25,6 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func CreateContainer(create: Create) string](#CreateContainer)
-[func CreateImage() NotImplemented](#CreateImage)
-
[func CreatePod(create: PodCreate) string](#CreatePod)
[func DeleteStoppedContainers() []string](#DeleteStoppedContainers)
@@ -39,19 +35,15 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func ExportImage(name: string, destination: string, compress: bool, tags: []string) string](#ExportImage)
-[func GenerateKube() NotImplemented](#GenerateKube)
-
-[func GenerateKubeService() NotImplemented](#GenerateKubeService)
-
[func GetAttachSockets(name: string) Sockets](#GetAttachSockets)
-[func GetContainer(name: string) ListContainerData](#GetContainer)
+[func GetContainer(id: string) Container](#GetContainer)
[func GetContainerLogs(name: string) []string](#GetContainerLogs)
[func GetContainerStats(name: string) ContainerStats](#GetContainerStats)
-[func GetImage(name: string) ImageInList](#GetImage)
+[func GetImage(id: string) Image](#GetImage)
[func GetInfo() PodmanInfo](#GetInfo)
@@ -59,7 +51,9 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func GetPodStats(name: string) string, ContainerStats](#GetPodStats)
-[func GetVersion() Version](#GetVersion)
+[func GetVersion() string, string, string, string, string, int](#GetVersion)
+
+[func GetVolumes(args: []string, all: bool) Volume](#GetVolumes)
[func HistoryImage(name: string) ImageHistory](#HistoryImage)
@@ -67,7 +61,7 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func ImagesPrune(all: bool) []string](#ImagesPrune)
-[func ImportImage(source: string, reference: string, message: string, changes: []string) string](#ImportImage)
+[func ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) string](#ImportImage)
[func InspectContainer(name: string) string](#InspectContainer)
@@ -83,13 +77,11 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func ListContainerMounts() map[string]](#ListContainerMounts)
-[func ListContainerPorts(name: string) NotImplemented](#ListContainerPorts)
-
[func ListContainerProcesses(name: string, opts: []string) []string](#ListContainerProcesses)
-[func ListContainers() ListContainerData](#ListContainers)
+[func ListContainers() Container](#ListContainers)
-[func ListImages() ImageInList](#ListImages)
+[func ListImages() Image](#ListImages)
[func ListPods() ListPodData](#ListPods)
@@ -99,29 +91,25 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func PausePod(name: string) string](#PausePod)
-[func Ping() StringResponse](#Ping)
-
[func PullImage(name: string, certDir: string, creds: string, signaturePolicy: string, tlsVerify: bool) string](#PullImage)
-[func PushImage(name: string, tag: string, tlsverify: bool, signaturePolicy: string, creds: string, certDir: string, compress: bool, format: string, removeSignatures: bool, signBy: string) string](#PushImage)
+[func PushImage(name: string, tag: string, tlsverify: bool, signaturePolicy: string, creds: string, certDir: string, compress: bool, format: string, removeSignatures: bool, signBy: string) MoreResponse](#PushImage)
-[func RemoveContainer(name: string, force: bool) string](#RemoveContainer)
+[func ReceiveFile(path: string, delete: bool) int](#ReceiveFile)
+
+[func RemoveContainer(name: string, force: bool, removeVolumes: bool) string](#RemoveContainer)
[func RemoveImage(name: string, force: bool) string](#RemoveImage)
[func RemovePod(name: string, force: bool) string](#RemovePod)
-[func RenameContainer() NotImplemented](#RenameContainer)
-
-[func ReplayKube() NotImplemented](#ReplayKube)
-
-[func ResizeContainerTty() NotImplemented](#ResizeContainerTty)
-
[func RestartContainer(name: string, timeout: int) string](#RestartContainer)
[func RestartPod(name: string) string](#RestartPod)
-[func SearchImage(name: string, limit: int) ImageSearch](#SearchImage)
+[func SearchImages(query: string, limit: ) ImageSearchResult](#SearchImages)
+
+[func SendFile(type: string, length: int) string](#SendFile)
[func StartContainer(name: string) string](#StartContainer)
@@ -133,23 +121,23 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func TagImage(name: string, tagged: string) string](#TagImage)
-[func TopPod() NotImplemented](#TopPod)
-
[func UnmountContainer(name: string, force: bool) ](#UnmountContainer)
[func UnpauseContainer(name: string) string](#UnpauseContainer)
[func UnpausePod(name: string) string](#UnpausePod)
-[func UpdateContainer() NotImplemented](#UpdateContainer)
+[func VolumeCreate(options: VolumeCreateOpts) string](#VolumeCreate)
-[func WaitContainer(name: string) int](#WaitContainer)
+[func VolumeRemove(options: VolumeRemoveOpts) []string](#VolumeRemove)
-[func WaitPod() NotImplemented](#WaitPod)
+[func WaitContainer(name: string) int](#WaitContainer)
[type BuildInfo](#BuildInfo)
-[type BuildResponse](#BuildResponse)
+[type BuildOptions](#BuildOptions)
+
+[type Container](#Container)
[type ContainerChanges](#ContainerChanges)
@@ -169,11 +157,11 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[type IDMappingOptions](#IDMappingOptions)
-[type ImageHistory](#ImageHistory)
+[type Image](#Image)
-[type ImageInList](#ImageInList)
+[type ImageHistory](#ImageHistory)
-[type ImageSearch](#ImageSearch)
+[type ImageSearchResult](#ImageSearchResult)
[type InfoDistribution](#InfoDistribution)
@@ -185,12 +173,12 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[type InfoStore](#InfoStore)
-[type ListContainerData](#ListContainerData)
-
[type ListPodContainerInfo](#ListPodContainerInfo)
[type ListPodData](#ListPodData)
+[type MoreResponse](#MoreResponse)
+
[type NotImplemented](#NotImplemented)
[type PodContainerErrorData](#PodContainerErrorData)
@@ -205,7 +193,11 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[type StringResponse](#StringResponse)
-[type Version](#Version)
+[type Volume](#Volume)
+
+[type VolumeCreateOpts](#VolumeCreateOpts)
+
+[type VolumeRemoveOpts](#VolumeRemoveOpts)
[error ContainerNotFound](#ContainerNotFound)
@@ -224,17 +216,12 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[error RuntimeError](#RuntimeError)
## Methods
-### <a name="AttachToContainer"></a>func AttachToContainer
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method AttachToContainer() [NotImplemented](#NotImplemented)</div>
-This method has not be implemented yet.
### <a name="BuildImage"></a>func BuildImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method BuildImage(build: [BuildInfo](#BuildInfo)) [BuildResponse](#BuildResponse)</div>
+method BuildImage(build: [BuildInfo](#BuildInfo)) [MoreResponse](#MoreResponse)</div>
BuildImage takes a [BuildInfo](#BuildInfo) structure and builds an image. At a minimum, you must provide the
-'dockerfile' and 'tags' options in the BuildInfo structure. It will return a [BuildResponse](#BuildResponse) structure
+'dockerfile' and 'tags' options in the BuildInfo structure. It will return a [MoreResponse](#MoreResponse) structure
that contains the build logs and resulting image ID.
### <a name="Commit"></a>func Commit
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -316,11 +303,6 @@ $ varlink call unix:/run/podman/io.podman/io.podman.CreateContainer '{"create":
"container": "8759dafbc0a4dc3bcfb57eeb72e4331eb73c5cc09ab968e65ce45b9ad5c4b6bb"
}
~~~
-### <a name="CreateImage"></a>func CreateImage
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method CreateImage() [NotImplemented](#NotImplemented)</div>
-This function is not implemented yet.
### <a name="CreatePod"></a>func CreatePod
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -398,18 +380,6 @@ a booleon option to force compression. It also takes in a string array of tags
tags of the same image to a tarball (each tag should be of the form <image>:<tag>). Upon completion, the ID
of the image is returned. If the image cannot be found in local storage, an [ImageNotFound](#ImageNotFound)
error will be returned. See also [ImportImage](ImportImage).
-### <a name="GenerateKube"></a>func GenerateKube
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method GenerateKube() [NotImplemented](#NotImplemented)</div>
-GenerateKube generates a Kubernetes v1 Pod description of a Podman container or pod
-and its containers. The description is in YAML. See also [ReplayKube](ReplayKube).
-### <a name="GenerateKubeService"></a>func GenerateKubeService
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method GenerateKubeService() [NotImplemented](#NotImplemented)</div>
-GenerateKubeService generates a Kubernetes v1 Service description of a Podman container or pod
-and its containers. The description is in YAML. See also [GenerateKube](GenerateKube).
### <a name="GetAttachSockets"></a>func GetAttachSockets
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -432,10 +402,11 @@ $ varlink call -m unix:/run/io.podman/io.podman.GetAttachSockets '{"name": "b762
### <a name="GetContainer"></a>func GetContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method GetContainer(name: [string](https://godoc.org/builtin#string)) [ListContainerData](#ListContainerData)</div>
-GetContainer takes a name or ID of a container and returns single ListContainerData
-structure. A [ContainerNotFound](#ContainerNotFound) error will be returned if the container cannot be found.
-See also [ListContainers](ListContainers) and [InspectContainer](#InspectContainer).
+method GetContainer(id: [string](https://godoc.org/builtin#string)) [Container](#Container)</div>
+GetContainer returns information about a single container. If a container
+with the given id doesn't exist, a [ContainerNotFound](#ContainerNotFound)
+error will be returned. See also [ListContainers](ListContainers) and
+[InspectContainer](#InspectContainer).
### <a name="GetContainerLogs"></a>func GetContainerLogs
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -476,9 +447,9 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.GetContainerStats '{"name
### <a name="GetImage"></a>func GetImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method GetImage(name: [string](https://godoc.org/builtin#string)) [ImageInList](#ImageInList)</div>
-GetImage returns a single image in an [ImageInList](#ImageInList) struct. You must supply an image name as a string.
-If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be returned.
+method GetImage(id: [string](https://godoc.org/builtin#string)) [Image](#Image)</div>
+GetImage returns information about a single image in storage.
+If the image caGetImage returns be found, [ImageNotFound](#ImageNotFound) will be returned.
### <a name="GetInfo"></a>func GetInfo
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -553,9 +524,13 @@ $ varlink call unix:/run/podman/io.podman/io.podman.GetPodStats '{"name": "7f62b
### <a name="GetVersion"></a>func GetVersion
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method GetVersion() [Version](#Version)</div>
-GetVersion returns a Version structure describing the libpod setup on their
-system.
+method GetVersion() [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [string](https://godoc.org/builtin#string), [int](https://godoc.org/builtin#int)</div>
+GetVersion returns version and build information of the podman service
+### <a name="GetVolumes"></a>func GetVolumes
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method GetVolumes(args: [[]string](#[]string), all: [bool](https://godoc.org/builtin#bool)) [Volume](#Volume)</div>
+
### <a name="HistoryImage"></a>func HistoryImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -586,7 +561,7 @@ the IDs of the removed images are returned.
### <a name="ImportImage"></a>func ImportImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method ImportImage(source: [string](https://godoc.org/builtin#string), reference: [string](https://godoc.org/builtin#string), message: [string](https://godoc.org/builtin#string), changes: [[]string](#[]string)) [string](https://godoc.org/builtin#string)</div>
+method ImportImage(source: [string](https://godoc.org/builtin#string), reference: [string](https://godoc.org/builtin#string), message: [string](https://godoc.org/builtin#string), changes: [[]string](#[]string), delete: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div>
ImportImage imports an image from a source (like tarball) into local storage. The image can have additional
descriptions added to it using the message and changes options. See also [ExportImage](ExportImage).
### <a name="InspectContainer"></a>func InspectContainer
@@ -656,11 +631,6 @@ $ varlink call unix:/run/podman/io.podman/io.podman.ListContainerMounts
}
}
~~~
-### <a name="ListContainerPorts"></a>func ListContainerPorts
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method ListContainerPorts(name: [string](https://godoc.org/builtin#string)) [NotImplemented](#NotImplemented)</div>
-This function is not implemented yet.
### <a name="ListContainerProcesses"></a>func ListContainerProcesses
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -684,15 +654,15 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.ListContainerProcesses '{
### <a name="ListContainers"></a>func ListContainers
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method ListContainers() [ListContainerData](#ListContainerData)</div>
-ListContainers returns a list of containers in no particular order. There are
-returned as an array of ListContainerData structs. See also [GetContainer](#GetContainer).
+method ListContainers() [Container](#Container)</div>
+ListContainers returns information about all containers.
+See also [GetContainer](#GetContainer).
### <a name="ListImages"></a>func ListImages
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method ListImages() [ImageInList](#ImageInList)</div>
-ListImages returns an array of ImageInList structures which provide basic information about
-an image currently in storage. See also [InspectImage](InspectImage).
+method ListImages() [Image](#Image)</div>
+ListImages returns information about the images that are currently in storage.
+See also [InspectImage](InspectImage).
### <a name="ListPods"></a>func ListPods
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -778,20 +748,6 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.PausePod '{"name": "fooba
"pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f"
}
~~~
-### <a name="Ping"></a>func Ping
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method Ping() [StringResponse](#StringResponse)</div>
-Ping provides a response for developers to ensure their varlink setup is working.
-#### Example
-~~~
-$ varlink call -m unix:/run/podman/io.podman/io.podman.Ping
-{
- "ping": {
- "message": "OK"
- }
-}
-~~~
### <a name="PullImage"></a>func PullImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -808,17 +764,22 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.PullImage '{"name": "regi
### <a name="PushImage"></a>func PushImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method PushImage(name: [string](https://godoc.org/builtin#string), tag: [string](https://godoc.org/builtin#string), tlsverify: [bool](https://godoc.org/builtin#bool), signaturePolicy: [string](https://godoc.org/builtin#string), creds: [string](https://godoc.org/builtin#string), certDir: [string](https://godoc.org/builtin#string), compress: [bool](https://godoc.org/builtin#bool), format: [string](https://godoc.org/builtin#string), removeSignatures: [bool](https://godoc.org/builtin#bool), signBy: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
+method PushImage(name: [string](https://godoc.org/builtin#string), tag: [string](https://godoc.org/builtin#string), tlsverify: [bool](https://godoc.org/builtin#bool), signaturePolicy: [string](https://godoc.org/builtin#string), creds: [string](https://godoc.org/builtin#string), certDir: [string](https://godoc.org/builtin#string), compress: [bool](https://godoc.org/builtin#bool), format: [string](https://godoc.org/builtin#string), removeSignatures: [bool](https://godoc.org/builtin#bool), signBy: [string](https://godoc.org/builtin#string)) [MoreResponse](#MoreResponse)</div>
PushImage takes three input arguments: the name or ID of an image, the fully-qualified destination name of the image,
and a boolean as to whether tls-verify should be used (with false disabling TLS, not affecting the default behavior).
It will return an [ImageNotFound](#ImageNotFound) error if
-the image cannot be found in local storage; otherwise the ID of the image will be returned on success.
+the image cannot be found in local storage; otherwise it will return a [MoreResponse](#MoreResponse)
+### <a name="ReceiveFile"></a>func ReceiveFile
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method ReceiveFile(path: [string](https://godoc.org/builtin#string), delete: [bool](https://godoc.org/builtin#bool)) [int](https://godoc.org/builtin#int)</div>
+
### <a name="RemoveContainer"></a>func RemoveContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method RemoveContainer(name: [string](https://godoc.org/builtin#string), force: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div>
+method RemoveContainer(name: [string](https://godoc.org/builtin#string), force: [bool](https://godoc.org/builtin#bool), removeVolumes: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div>
RemoveContainer takes requires the name or ID of container as well a boolean representing whether a running
-container can be stopped and removed. Upon successful removal of the container, its ID is returned. If the
+container can be stopped and removed. It also takes a flag on whether or not to remove builtin volumes. Upon successful removal of the container, its ID is returned. If the
container cannot be found by name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned.
#### Example
~~~
@@ -859,22 +820,6 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.RemovePod '{"name": "62f4
"pod": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20"
}
~~~
-### <a name="RenameContainer"></a>func RenameContainer
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method RenameContainer() [NotImplemented](#NotImplemented)</div>
-This method has not be implemented yet.
-### <a name="ReplayKube"></a>func ReplayKube
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method ReplayKube() [NotImplemented](#NotImplemented)</div>
-ReplayKube recreates a pod and its containers based on a Kubernetes v1 Pod description (in YAML)
-like that created by GenerateKube. See also [GenerateKube](GenerateKube).
-### <a name="ResizeContainerTty"></a>func ResizeContainerTty
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method ResizeContainerTty() [NotImplemented](#NotImplemented)</div>
-This method has not be implemented yet.
### <a name="RestartContainer"></a>func RestartContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -900,13 +845,18 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.RestartPod '{"name": "135
"pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6"
}
~~~
-### <a name="SearchImage"></a>func SearchImage
+### <a name="SearchImages"></a>func SearchImages
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method SearchImages(query: [string](https://godoc.org/builtin#string), limit: [](#)) [ImageSearchResult](#ImageSearchResult)</div>
+SearchImages searches available registries for images that contain the
+contents of "query" in their name. If "limit" is given, limits the amount of
+search results per registry.
+### <a name="SendFile"></a>func SendFile
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method SearchImage(name: [string](https://godoc.org/builtin#string), limit: [int](https://godoc.org/builtin#int)) [ImageSearch](#ImageSearch)</div>
-SearchImage takes the string of an image name and a limit of searches from each registries to be returned. SearchImage
-will then use a glob-like match to find the image you are searching for. The images are returned in an array of
-ImageSearch structures which contain information about the image as well as its fully-qualified name.
+method SendFile(type: [string](https://godoc.org/builtin#string), length: [int](https://godoc.org/builtin#int)) [string](https://godoc.org/builtin#string)</div>
+
### <a name="StartContainer"></a>func StartContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -968,11 +918,6 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.StopPod '{"name": "135d71
method TagImage(name: [string](https://godoc.org/builtin#string), tagged: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
TagImage takes the name or ID of an image in local storage as well as the desired tag name. If the image cannot
be found, an [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of the image is returned on success.
-### <a name="TopPod"></a>func TopPod
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method TopPod() [NotImplemented](#NotImplemented)</div>
-This method has not been implemented yet.
### <a name="UnmountContainer"></a>func UnmountContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -1007,11 +952,16 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.UnpausePod '{"name": "foo
"pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f"
}
~~~
-### <a name="UpdateContainer"></a>func UpdateContainer
+### <a name="VolumeCreate"></a>func VolumeCreate
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method UpdateContainer() [NotImplemented](#NotImplemented)</div>
-This method has not be implemented yet.
+method VolumeCreate(options: [VolumeCreateOpts](#VolumeCreateOpts)) [string](https://godoc.org/builtin#string)</div>
+
+### <a name="VolumeRemove"></a>func VolumeRemove
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method VolumeRemove(options: [VolumeRemoveOpts](#VolumeRemoveOpts)) [[]string](#[]string)</div>
+
### <a name="WaitContainer"></a>func WaitContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -1019,70 +969,122 @@ method WaitContainer(name: [string](https://godoc.org/builtin#string)) [int](htt
WaitContainer takes the name or ID of a container and waits until the container stops. Upon stopping, the return
code of the container is returned. If the container container cannot be found by ID or name,
a [ContainerNotFound](#ContainerNotFound) error is returned.
-### <a name="WaitPod"></a>func WaitPod
-<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-
-method WaitPod() [NotImplemented](#NotImplemented)</div>
-This method has not be implemented yet.
## Types
### <a name="BuildInfo"></a>type BuildInfo
BuildInfo is used to describe user input for building images
-dockerfile [[]string](#[]string)
+additionalTags [[]string](#[]string)
-tags [[]string](#[]string)
+annotations [[]string](#[]string)
-add_hosts [[]string](#[]string)
+buildArgs [map[string]](#map[string])
-cgroup_parent [string](https://godoc.org/builtin#string)
+buildOptions [BuildOptions](#BuildOptions)
-cpu_period [int](https://godoc.org/builtin#int)
+cniConfigDir [string](https://godoc.org/builtin#string)
-cpu_quota [int](https://godoc.org/builtin#int)
+cniPluginDir [string](https://godoc.org/builtin#string)
-cpu_shares [int](https://godoc.org/builtin#int)
+compression [string](https://godoc.org/builtin#string)
-cpuset_cpus [string](https://godoc.org/builtin#string)
+contextDir [string](https://godoc.org/builtin#string)
-cpuset_mems [string](https://godoc.org/builtin#string)
+defaultsMountFilePath [string](https://godoc.org/builtin#string)
-memory [string](https://godoc.org/builtin#string)
+dockerfiles [[]string](#[]string)
-memory_swap [string](https://godoc.org/builtin#string)
+err [string](https://godoc.org/builtin#string)
-security_opts [[]string](#[]string)
+forceRmIntermediateCtrs [bool](https://godoc.org/builtin#bool)
-shm_size [string](https://godoc.org/builtin#string)
+iidfile [string](https://godoc.org/builtin#string)
-ulimit [[]string](#[]string)
+label [[]string](#[]string)
-volume [[]string](#[]string)
+layers [bool](https://godoc.org/builtin#bool)
+
+nocache [bool](https://godoc.org/builtin#bool)
+
+out [string](https://godoc.org/builtin#string)
+
+output [string](https://godoc.org/builtin#string)
+
+outputFormat [string](https://godoc.org/builtin#string)
+
+pullPolicy [string](https://godoc.org/builtin#string)
+
+quiet [bool](https://godoc.org/builtin#bool)
+
+remoteIntermediateCtrs [bool](https://godoc.org/builtin#bool)
+
+reportWriter [string](https://godoc.org/builtin#string)
+
+runtimeArgs [[]string](#[]string)
+
+signaturePolicyPath [string](https://godoc.org/builtin#string)
squash [bool](https://godoc.org/builtin#bool)
+### <a name="BuildOptions"></a>type BuildOptions
-pull [bool](https://godoc.org/builtin#bool)
+BuildOptions are are used to describe describe physical attributes of the build
-pull_always [bool](https://godoc.org/builtin#bool)
+addHosts [[]string](#[]string)
-force_rm [bool](https://godoc.org/builtin#bool)
+cgroupParent [string](https://godoc.org/builtin#string)
-rm [bool](https://godoc.org/builtin#bool)
+cpuPeriod [int](https://godoc.org/builtin#int)
-label [[]string](#[]string)
+cpuQuota [int](https://godoc.org/builtin#int)
-annotations [[]string](#[]string)
+cpuShares [int](https://godoc.org/builtin#int)
-build_args [map[string]](#map[string])
+cpusetCpus [string](https://godoc.org/builtin#string)
-image_format [string](https://godoc.org/builtin#string)
-### <a name="BuildResponse"></a>type BuildResponse
+cpusetMems [string](https://godoc.org/builtin#string)
+
+memory [int](https://godoc.org/builtin#int)
+
+memorySwap [int](https://godoc.org/builtin#int)
+
+shmSize [string](https://godoc.org/builtin#string)
+
+ulimit [[]string](#[]string)
+
+volume [[]string](#[]string)
+### <a name="Container"></a>type Container
-BuildResponse is used to describe the responses for building images
-logs [[]string](#[]string)
id [string](https://godoc.org/builtin#string)
+
+image [string](https://godoc.org/builtin#string)
+
+imageid [string](https://godoc.org/builtin#string)
+
+command [[]string](#[]string)
+
+createdat [string](https://godoc.org/builtin#string)
+
+runningfor [string](https://godoc.org/builtin#string)
+
+status [string](https://godoc.org/builtin#string)
+
+ports [ContainerPortMappings](#ContainerPortMappings)
+
+rootfssize [int](https://godoc.org/builtin#int)
+
+rwsize [int](https://godoc.org/builtin#int)
+
+names [string](https://godoc.org/builtin#string)
+
+labels [map[string]](#map[string])
+
+mounts [ContainerMount](#ContainerMount)
+
+containerrunning [bool](https://godoc.org/builtin#bool)
+
+namespaces [ContainerNameSpace](#ContainerNameSpace)
### <a name="ContainerChanges"></a>type ContainerChanges
ContainerChanges describes the return struct for ListContainerChanges
@@ -1366,25 +1368,9 @@ host_gid_mapping [bool](https://godoc.org/builtin#bool)
uid_map [IDMap](#IDMap)
gid_map [IDMap](#IDMap)
-### <a name="ImageHistory"></a>type ImageHistory
-
-ImageHistory describes the returned structure from ImageHistory.
+### <a name="Image"></a>type Image
-id [string](https://godoc.org/builtin#string)
-created [string](https://godoc.org/builtin#string)
-
-createdBy [string](https://godoc.org/builtin#string)
-
-tags [[]string](#[]string)
-
-size [int](https://godoc.org/builtin#int)
-
-comment [string](https://godoc.org/builtin#string)
-### <a name="ImageInList"></a>type ImageInList
-
-ImageInList describes the structure that is returned in
-ListImages.
id [string](https://godoc.org/builtin#string)
@@ -1405,10 +1391,24 @@ containers [int](https://godoc.org/builtin#int)
labels [map[string]](#map[string])
isParent [bool](https://godoc.org/builtin#bool)
-### <a name="ImageSearch"></a>type ImageSearch
+### <a name="ImageHistory"></a>type ImageHistory
+
+ImageHistory describes the returned structure from ImageHistory.
+
+id [string](https://godoc.org/builtin#string)
+
+created [string](https://godoc.org/builtin#string)
-ImageSearch is the returned structure for SearchImage. It is returned
-in array form.
+createdBy [string](https://godoc.org/builtin#string)
+
+tags [[]string](#[]string)
+
+size [int](https://godoc.org/builtin#int)
+
+comment [string](https://godoc.org/builtin#string)
+### <a name="ImageSearchResult"></a>type ImageSearchResult
+
+Represents a single search result from SearchImages
description [string](https://godoc.org/builtin#string)
@@ -1490,39 +1490,6 @@ graph_root [string](https://godoc.org/builtin#string)
graph_status [InfoGraphStatus](#InfoGraphStatus)
run_root [string](https://godoc.org/builtin#string)
-### <a name="ListContainerData"></a>type ListContainerData
-
-ListContainerData is the returned struct for an individual container
-
-id [string](https://godoc.org/builtin#string)
-
-image [string](https://godoc.org/builtin#string)
-
-imageid [string](https://godoc.org/builtin#string)
-
-command [[]string](#[]string)
-
-createdat [string](https://godoc.org/builtin#string)
-
-runningfor [string](https://godoc.org/builtin#string)
-
-status [string](https://godoc.org/builtin#string)
-
-ports [ContainerPortMappings](#ContainerPortMappings)
-
-rootfssize [int](https://godoc.org/builtin#int)
-
-rwsize [int](https://godoc.org/builtin#int)
-
-names [string](https://godoc.org/builtin#string)
-
-labels [map[string]](#map[string])
-
-mounts [ContainerMount](#ContainerMount)
-
-containerrunning [bool](https://godoc.org/builtin#bool)
-
-namespaces [ContainerNameSpace](#ContainerNameSpace)
### <a name="ListPodContainerInfo"></a>type ListPodContainerInfo
ListPodContainerInfo is a returned struct for describing containers
@@ -1552,6 +1519,13 @@ labels [map[string]](#map[string])
numberofcontainers [string](https://godoc.org/builtin#string)
containersinfo [ListPodContainerInfo](#ListPodContainerInfo)
+### <a name="MoreResponse"></a>type MoreResponse
+
+MoreResponse is a struct for when responses from varlink requires longer output
+
+logs [[]string](#[]string)
+
+id [string](https://godoc.org/builtin#string)
### <a name="NotImplemented"></a>type NotImplemented
@@ -1639,21 +1613,41 @@ control_socket [string](https://godoc.org/builtin#string)
message [string](https://godoc.org/builtin#string)
-### <a name="Version"></a>type Version
+### <a name="Volume"></a>type Volume
-Version is the structure returned by GetVersion
-version [string](https://godoc.org/builtin#string)
-go_version [string](https://godoc.org/builtin#string)
+name [string](https://godoc.org/builtin#string)
-git_commit [string](https://godoc.org/builtin#string)
+labels [map[string]](#map[string])
+
+mountPoint [string](https://godoc.org/builtin#string)
-built [int](https://godoc.org/builtin#int)
+driver [string](https://godoc.org/builtin#string)
+
+options [map[string]](#map[string])
+
+scope [string](https://godoc.org/builtin#string)
+### <a name="VolumeCreateOpts"></a>type VolumeCreateOpts
+
+
+
+volumeName [string](https://godoc.org/builtin#string)
+
+driver [string](https://godoc.org/builtin#string)
+
+labels [map[string]](#map[string])
+
+options [map[string]](#map[string])
+### <a name="VolumeRemoveOpts"></a>type VolumeRemoveOpts
+
+
+
+volumes [[]string](#[]string)
-os_arch [string](https://godoc.org/builtin#string)
+all [bool](https://godoc.org/builtin#bool)
-remote_api_version [int](https://godoc.org/builtin#int)
+force [bool](https://godoc.org/builtin#bool)
## Errors
### <a name="ContainerNotFound"></a>type ContainerNotFound
diff --git a/Makefile b/Makefile
index 08dd586be..f634fcc81 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo
PACKAGES ?= $(shell $(GO) list -tags "${BUILDTAGS}" ./... | grep -v github.com/containers/libpod/vendor | grep -v e2e | grep -v system )
COMMIT_NO ?= $(shell git rev-parse HEAD 2> /dev/null || true)
-GIT_COMMIT ?= $(if $(shell git status --porcelain --untracked-files=no),"${COMMIT_NO}-dirty","${COMMIT_NO}")
+GIT_COMMIT ?= $(if $(shell git status --porcelain --untracked-files=no),${COMMIT_NO}-dirty,${COMMIT_NO})
BUILD_INFO ?= $(shell date +%s)
LIBPOD := ${PROJECT}/libpod
LDFLAGS_PODMAN ?= $(LDFLAGS) -X $(LIBPOD).gitCommit=$(GIT_COMMIT) -X $(LIBPOD).buildInfo=$(BUILD_INFO)
@@ -94,6 +94,7 @@ help:
ifeq ("$(wildcard $(GOPKGDIR))","")
mkdir -p "$(GOPKGBASEDIR)"
ln -sf "$(CURDIR)" "$(GOPKGBASEDIR)"
+ ln -sf "$(CURDIR)/vendor/github.com/varlink" "$(FIRST_GOPATH)/src/github.com/varlink"
endif
touch $@
@@ -105,11 +106,6 @@ gofmt: ## Verify the source code gofmt
find . -name '*.go' ! -path './vendor/*' -exec gofmt -s -w {} \+
git diff --exit-code
-test/bin2img/bin2img: .gopathok $(wildcard test/bin2img/*.go)
- $(GO) build -ldflags '$(LDFLAGS)' -tags "$(BUILDTAGS) containers_image_ostree_stub" -o $@ $(PROJECT)/test/bin2img
-
-test/copyimg/copyimg: .gopathok $(wildcard test/copyimg/*.go)
- $(GO) build -ldflags '$(LDFLAGS)' -tags "$(BUILDTAGS) containers_image_ostree_stub" -o $@ $(PROJECT)/test/copyimg
test/checkseccomp/checkseccomp: .gopathok $(wildcard test/checkseccomp/*.go)
$(GO) build -ldflags '$(LDFLAGS)' -tags "$(BUILDTAGS) containers_image_ostree_stub" -o $@ $(PROJECT)/test/checkseccomp
@@ -140,9 +136,7 @@ clean: ## Clean artifacts
_output \
bin \
build \
- test/bin2img/bin2img \
test/checkseccomp/checkseccomp \
- test/copyimg/copyimg \
test/goecho/goecho \
test/testdata/redis-image \
cmd/podman/varlink/iopodman.go \
@@ -210,7 +204,7 @@ binaries: varlink_generate podman podman-remote ## Build podman
install.catatonit:
./hack/install_catatonit.sh
-test-binaries: test/bin2img/bin2img test/copyimg/copyimg test/checkseccomp/checkseccomp test/goecho/goecho install.catatonit
+test-binaries: test/checkseccomp/checkseccomp test/goecho/goecho install.catatonit
MANPAGES_MD ?= $(wildcard docs/*.md pkg/*/docs/*.md)
MANPAGES ?= $(MANPAGES_MD:%.md=%)
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go
index 8b0fd7ffd..ed175bdf4 100644
--- a/cmd/podman/attach.go
+++ b/cmd/podman/attach.go
@@ -28,14 +28,13 @@ var (
func init() {
attachCommand.Command = _attachCommand
+ attachCommand.SetUsageTemplate(UsageTemplate())
flags := attachCommand.Flags()
flags.StringVar(&attachCommand.DetachKeys, "detach-keys", "", "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
flags.BoolVar(&attachCommand.NoStdin, "no-stdin", false, "Do not attach STDIN. The default is false")
flags.BoolVar(&attachCommand.SigProxy, "sig-proxy", true, "Proxy received signals to the process (default true)")
flags.BoolVarP(&attachCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
-
- rootCmd.AddCommand(attachCommand.Command)
}
func attachCmd(c *cliconfig.AttachValues) error {
@@ -75,7 +74,7 @@ func attachCmd(c *cliconfig.AttachValues) error {
inputStream = nil
}
- if err := startAttachCtr(ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, c.SigProxy, false); err != nil {
+ if err := startAttachCtr(ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, c.SigProxy, false); err != nil && errors.Cause(err) != libpod.ErrDetach {
return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
}
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index 20f621e84..30a734377 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -1,7 +1,6 @@
package main
import (
- "io/ioutil"
"os"
"path/filepath"
"strings"
@@ -9,10 +8,9 @@ import (
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
buildahcli "github.com/containers/buildah/pkg/cli"
- "github.com/containers/buildah/pkg/parse"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/libpod/adapter"
+ "github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -48,6 +46,7 @@ var (
func init() {
buildCommand.Command = _buildCommand
+ buildCommand.SetUsageTemplate(UsageTemplate())
flags := buildCommand.Flags()
flags.SetInterspersed(false)
@@ -58,8 +57,6 @@ func init() {
flags.AddFlagSet(&budFlags)
flags.AddFlagSet(&fromAndBugFlags)
-
- rootCmd.AddCommand(buildCommand.Command)
}
func getDockerfiles(files []string) []string {
@@ -77,7 +74,6 @@ func getDockerfiles(files []string) []string {
func buildCmd(c *cliconfig.BuildValues) error {
// The following was taken directly from containers/buildah/cmd/bud.go
// TODO Find a away to vendor more of this in rather than copy from bud
-
output := ""
tags := []string{}
if c.Flag("tag").Changed {
@@ -87,6 +83,7 @@ func buildCmd(c *cliconfig.BuildValues) error {
tags = tags[1:]
}
}
+
pullPolicy := imagebuildah.PullNever
if c.Pull {
pullPolicy = imagebuildah.PullIfMissing
@@ -174,16 +171,17 @@ func buildCmd(c *cliconfig.BuildValues) error {
dockerfiles = append(dockerfiles, filepath.Join(contextDir, "Dockerfile"))
}
+ runtime, err := adapter.GetRuntime(&c.PodmanCommand)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+
runtimeFlags := []string{}
for _, arg := range c.RuntimeOpts {
runtimeFlags = append(runtimeFlags, "--"+arg)
}
// end from buildah
- runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
defer runtime.Shutdown(false)
var stdout, stderr, reporter *os.File
@@ -202,72 +200,64 @@ func buildCmd(c *cliconfig.BuildValues) error {
reporter = f
}
- systemContext, err := parse.SystemContextFromOptions(c.PodmanCommand.Command)
- if err != nil {
- return errors.Wrapf(err, "error building system context")
- }
- systemContext.AuthFilePath = getAuthFile(c.Authfile)
- commonOpts, err := parse.CommonBuildOptions(c.PodmanCommand.Command)
- if err != nil {
- return err
+ var memoryLimit, memorySwap int64
+ if c.Flags().Changed("memory") {
+ memoryLimit, err = units.RAMInBytes(c.Memory)
+ if err != nil {
+ return err
+ }
}
- namespaceOptions, networkPolicy, err := parse.NamespaceOptions(c.PodmanCommand.Command)
- if err != nil {
- return errors.Wrapf(err, "error parsing namespace-related options")
- }
- usernsOption, idmappingOptions, err := parse.IDMappingOptions(c.PodmanCommand.Command)
- if err != nil {
- return errors.Wrapf(err, "error parsing ID mapping options")
+ if c.Flags().Changed("memory-swap") {
+ memorySwap, err = units.RAMInBytes(c.MemorySwap)
+ if err != nil {
+ return err
+ }
}
- namespaceOptions.AddOrReplace(usernsOption...)
- ociruntime := runtime.GetOCIRuntimePath()
- if c.Flag("runtime").Changed {
- ociruntime = c.Runtime
+ buildOpts := buildah.CommonBuildOptions{
+ AddHost: c.AddHost,
+ CgroupParent: c.CgroupParent,
+ CPUPeriod: c.CPUPeriod,
+ CPUQuota: c.CPUQuota,
+ CPUShares: c.CPUShares,
+ CPUSetCPUs: c.CPUSetCPUs,
+ CPUSetMems: c.CPUSetMems,
+ Memory: memoryLimit,
+ MemorySwap: memorySwap,
+ ShmSize: c.ShmSize,
+ Ulimit: c.Ulimit,
+ Volumes: c.Volume,
}
+
options := imagebuildah.BuildOptions{
- ContextDirectory: contextDir,
- PullPolicy: pullPolicy,
- Compression: imagebuildah.Gzip,
- Quiet: c.Quiet,
- SignaturePolicyPath: c.SignaturePolicy,
- Args: args,
- Output: output,
+ CommonBuildOpts: &buildOpts,
AdditionalTags: tags,
- Out: stdout,
- Err: stderr,
- ReportWriter: reporter,
- Runtime: ociruntime,
- RuntimeArgs: runtimeFlags,
- OutputFormat: format,
- SystemContext: systemContext,
- NamespaceOptions: namespaceOptions,
- ConfigureNetwork: networkPolicy,
- CNIPluginPath: c.CNIPlugInPath,
+ Annotations: c.Annotation,
+ Args: args,
CNIConfigDir: c.CNIConfigDir,
- IDMappingOptions: idmappingOptions,
- CommonBuildOpts: commonOpts,
+ CNIPluginPath: c.CNIPlugInPath,
+ Compression: imagebuildah.Gzip,
+ ContextDirectory: contextDir,
DefaultMountsFilePath: c.GlobalFlags.DefaultMountsFile,
+ Err: stderr,
+ ForceRmIntermediateCtrs: c.ForceRm,
IIDFile: c.Iidfile,
- Squash: c.Squash,
Labels: c.Label,
- Annotations: c.Annotation,
Layers: layers,
NoCache: c.NoCache,
+ Out: stdout,
+ Output: output,
+ OutputFormat: format,
+ PullPolicy: pullPolicy,
+ Quiet: c.Quiet,
RemoveIntermediateCtrs: c.Rm,
- ForceRmIntermediateCtrs: c.ForceRm,
- }
-
- if c.Quiet {
- options.ReportWriter = ioutil.Discard
- }
-
- if rootless.IsRootless() {
- options.Isolation = buildah.IsolationOCIRootless
+ ReportWriter: reporter,
+ RuntimeArgs: runtimeFlags,
+ SignaturePolicyPath: c.SignaturePolicy,
+ Squash: c.Squash,
}
-
- return runtime.Build(getContext(), options, dockerfiles...)
+ return runtime.Build(getContext(), c, options, dockerfiles)
}
// Tail returns a string slice after the first element unless there are
diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go
index 2a978bea8..aa4034ccd 100644
--- a/cmd/podman/checkpoint.go
+++ b/cmd/podman/checkpoint.go
@@ -35,6 +35,7 @@ var (
func init() {
checkpointCommand.Command = _checkpointCommand
+ checkpointCommand.SetUsageTemplate(UsageTemplate())
flags := checkpointCommand.Flags()
flags.BoolVarP(&checkpointCommand.Keep, "keep", "k", false, "Keep all temporary checkpoint files")
diff --git a/cmd/podman/cleanup.go b/cmd/podman/cleanup.go
index 1a7617d5c..e465a30e6 100644
--- a/cmd/podman/cleanup.go
+++ b/cmd/podman/cleanup.go
@@ -32,10 +32,12 @@ var (
func init() {
cleanupCommand.Command = _cleanupCommand
+ cleanupCommand.SetUsageTemplate(UsageTemplate())
flags := cleanupCommand.Flags()
flags.BoolVarP(&cleanupCommand.All, "all", "a", false, "Cleans up all containers")
flags.BoolVarP(&cleanupCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.BoolVar(&cleanupCommand.Remove, "rm", false, "After cleanup, remove the container entirely")
}
func cleanupCmd(c *cliconfig.CleanupValues) error {
@@ -54,12 +56,25 @@ func cleanupCmd(c *cliconfig.CleanupValues) error {
ctx := getContext()
for _, ctr := range cleanupContainers {
- if err = ctr.Cleanup(ctx); err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
+ hadError := false
+ if c.Remove {
+ if err := runtime.RemoveContainer(ctx, ctr, false, false); err != nil {
+ if lastError != nil {
+ fmt.Fprintln(os.Stderr, lastError)
+ }
+ lastError = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
+ hadError = true
}
- lastError = errors.Wrapf(err, "failed to cleanup container %v", ctr.ID())
} else {
+ if err := ctr.Cleanup(ctx); err != nil {
+ if lastError != nil {
+ fmt.Fprintln(os.Stderr, lastError)
+ }
+ lastError = errors.Wrapf(err, "failed to cleanup container %v", ctr.ID())
+ hadError = true
+ }
+ }
+ if !hadError {
fmt.Println(ctr.ID())
}
}
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index b925d29ff..f38bcaa62 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -135,6 +135,11 @@ type PruneImagesValues struct {
All bool
}
+type PruneContainersValues struct {
+ PodmanCommand
+ Force bool
+}
+
type ImportValues struct {
PodmanCommand
Change []string
@@ -531,6 +536,7 @@ type CleanupValues struct {
PodmanCommand
All bool
Latest bool
+ Remove bool
}
type SystemPruneValues struct {
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index e1eba1f31..baa49d2af 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -6,24 +6,65 @@ import (
"github.com/spf13/cobra"
)
+// Commands that the local client implements
+func getMainCommands() []*cobra.Command {
+ rootCommands := []*cobra.Command{
+ _attachCommand,
+ _commitCommand,
+ _createCommand,
+ _diffCommand,
+ _execCommand,
+ _killCommand,
+ generateCommand.Command,
+ podCommand.Command,
+ _containerKubeCommand,
+ _psCommand,
+ _loadCommand,
+ _loginCommand,
+ _logoutCommand,
+ _logsCommand,
+ _mountCommand,
+ _pauseCommand,
+ _portCommand,
+ _refreshCommand,
+ _restartCommand,
+ _restoreCommand,
+ _rmCommand,
+ _runCommand,
+ _saveCommand,
+ _searchCommand,
+ _signCommand,
+ _startCommand,
+ _statsCommand,
+ _stopCommand,
+ _topCommand,
+ _umountCommand,
+ _unpauseCommand,
+ volumeCommand.Command,
+ _waitCommand,
+ }
+
+ if len(_varlinkCommand.Use) > 0 {
+ rootCommands = append(rootCommands, _varlinkCommand)
+ }
+ return rootCommands
+}
+
+// Commands that the local client implements
func getImageSubCommands() []*cobra.Command {
return []*cobra.Command{
- _buildCommand,
- _importCommand,
_loadCommand,
- _pullCommand,
- _rmiCommand,
_saveCommand,
_signCommand,
}
}
+// Commands that the local client implements
func getContainerSubCommands() []*cobra.Command {
return []*cobra.Command{
_attachCommand,
_checkpointCommand,
_cleanupCommand,
- _containerExistsCommand,
_commitCommand,
_createCommand,
_diffCommand,
@@ -40,7 +81,7 @@ func getContainerSubCommands() []*cobra.Command {
_restartCommand,
_restoreCommand,
_rmCommand,
- _runCommmand,
+ _runCommand,
_runlabelCommand,
_startCommand,
_statsCommand,
@@ -52,6 +93,7 @@ func getContainerSubCommands() []*cobra.Command {
}
}
+// Commands that the local client implements
func getPodSubCommands() []*cobra.Command {
return []*cobra.Command{
_podCreateCommand,
@@ -70,6 +112,7 @@ func getPodSubCommands() []*cobra.Command {
}
}
+// Commands that the local client implements
func getVolumeSubCommands() []*cobra.Command {
return []*cobra.Command{
_volumeCreateCommand,
@@ -80,18 +123,21 @@ func getVolumeSubCommands() []*cobra.Command {
}
}
+// Commands that the local client implements
func getGenerateSubCommands() []*cobra.Command {
return []*cobra.Command{
_containerKubeCommand,
}
}
+// Commands that the local client implements
func getPlaySubCommands() []*cobra.Command {
return []*cobra.Command{
_playKubeCommand,
}
}
+// Commands that the local client implements
func getTrustSubCommands() []*cobra.Command {
return []*cobra.Command{
_setTrustCommand,
@@ -99,9 +145,9 @@ func getTrustSubCommands() []*cobra.Command {
}
}
+// Commands that the local client implements
func getSystemSubCommands() []*cobra.Command {
return []*cobra.Command{
- _infoCommand,
_pruneSystemCommand,
}
}
diff --git a/cmd/podman/commands_remoteclient.go b/cmd/podman/commands_remoteclient.go
index 80083eab9..7bdba1c19 100644
--- a/cmd/podman/commands_remoteclient.go
+++ b/cmd/podman/commands_remoteclient.go
@@ -6,43 +6,57 @@ import (
"github.com/spf13/cobra"
)
-//import "github.com/urfave/cli"
-//
+// commands that only the remoteclient implements
+func getMainCommands() []*cobra.Command {
+ return []*cobra.Command{}
+}
+
+// commands that only the remoteclient implements
func getAppCommands() []*cobra.Command {
return []*cobra.Command{}
}
+// commands that only the remoteclient implements
func getImageSubCommands() []*cobra.Command {
return []*cobra.Command{}
}
+// commands that only the remoteclient implements
func getContainerSubCommands() []*cobra.Command {
return []*cobra.Command{}
}
+// commands that only the remoteclient implements
func getPodSubCommands() []*cobra.Command {
return []*cobra.Command{}
}
+// commands that only the remoteclient implements
func getVolumeSubCommands() []*cobra.Command {
- return []*cobra.Command{}
+ return []*cobra.Command{
+ _volumeCreateCommand,
+ _volumeRmCommand,
+ _volumeLsCommand,
+ _volumeInspectCommand,
+ }
}
+// commands that only the remoteclient implements
func getGenerateSubCommands() []*cobra.Command {
return []*cobra.Command{}
}
+// commands that only the remoteclient implements
func getPlaySubCommands() []*cobra.Command {
return []*cobra.Command{}
}
+// commands that only the remoteclient implements
func getTrustSubCommands() []*cobra.Command {
return []*cobra.Command{}
}
-//func getMainAppFlags() []cli.Flag {
-// return []cli.Flag{}
-//}
+// commands that only the remoteclient implements
func getSystemSubCommands() []*cobra.Command {
return []*cobra.Command{}
}
diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go
index 6fd6b9761..dc53e68d1 100644
--- a/cmd/podman/commit.go
+++ b/cmd/podman/commit.go
@@ -39,6 +39,7 @@ var (
func init() {
commitCommand.Command = _commitCommand
+ commitCommand.SetUsageTemplate(UsageTemplate())
flags := commitCommand.Flags()
flags.StringSliceVarP(&commitCommand.Change, "change", "c", []string{}, fmt.Sprintf("Apply the following possible instructions to the created image (default []): %s", strings.Join(libpod.ChangeCmds, " | ")))
flags.StringVarP(&commitCommand.Format, "format", "f", "oci", "`Format` of the image manifest and metadata")
@@ -47,7 +48,6 @@ func init() {
flags.BoolVarP(&commitCommand.Pause, "pause", "p", false, "Pause container during commit")
flags.BoolVarP(&commitCommand.Quiet, "quiet", "q", false, "Suppress output")
- rootCmd.AddCommand(commitCommand.Command)
}
func commitCmd(c *cliconfig.CommitValues) error {
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index 5fbdfce50..417e938b7 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -500,3 +500,27 @@ func scrubServer(server string) string {
server = strings.TrimPrefix(server, "https://")
return strings.TrimPrefix(server, "http://")
}
+
+// UsageTemplate returns the usage template for podman commands
+// This blocks the desplaying of the global options. The main podman
+// command should not use this.
+func UsageTemplate() string {
+ return `Usage:{{if .Runnable}}
+ {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
+
+ {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
+
+Aliases:
+ {{.NameAndAliases}}{{end}}{{if .HasExample}}
+
+Examples:
+{{.Example}}{{end}}{{if .HasAvailableSubCommands}}
+
+Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
+ {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
+
+Flags:
+{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
+{{end}}
+`
+}
diff --git a/cmd/podman/common_test.go b/cmd/podman/common_test.go
index 042568d7e..a24173003 100644
--- a/cmd/podman/common_test.go
+++ b/cmd/podman/common_test.go
@@ -3,34 +3,8 @@ package main
import (
"os/user"
"testing"
-
- "flag"
-
- "github.com/urfave/cli"
)
-func TestGetStore(t *testing.T) {
- t.Skip("FIX THIS!")
-
- //cmd/podman/common_test.go:27: cannot use c (type *cli.Context) as type *libkpod.Config in argument to getStore
-
- // Make sure the tests are running as root
- skipTestIfNotRoot(t)
-
- set := flag.NewFlagSet("test", 0)
- globalSet := flag.NewFlagSet("test", 0)
- globalSet.String("root", "", "path to the root directory in which data, including images, is stored")
- globalCtx := cli.NewContext(nil, globalSet, nil)
- command := cli.Command{Name: "imagesCommand"}
- c := cli.NewContext(nil, set, globalCtx)
- c.Command = command
-
- //_, err := getStore(c)
- //if err != nil {
- //t.Error(err)
- //}
-}
-
func skipTestIfNotRoot(t *testing.T) {
u, err := user.Current()
if err != nil {
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index 969cb2dc8..d2450fdd3 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -15,7 +15,14 @@ var containerCommand = cliconfig.PodmanCommand{
},
}
+// Commands that are universally implemented.
+var containerCommands = []*cobra.Command{
+ _containerExistsCommand,
+}
+
func init() {
+ containerCommand.AddCommand(containerCommands...)
containerCommand.AddCommand(getContainerSubCommands()...)
+ containerCommand.SetUsageTemplate(UsageTemplate())
rootCmd.AddCommand(containerCommand.Command)
}
diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go
index 3f9b46035..bae578e1d 100644
--- a/cmd/podman/containers_prune.go
+++ b/cmd/podman/containers_prune.go
@@ -13,13 +13,12 @@ import (
)
var (
- pruneContainersCommand cliconfig.ContainersPrune
+ pruneContainersCommand cliconfig.PruneContainersValues
pruneContainersDescription = `
podman container prune
Removes all exited containers
`
-
_pruneContainersCommand = &cobra.Command{
Use: "prune",
Short: "Remove all stopped containers",
@@ -34,9 +33,12 @@ var (
func init() {
pruneContainersCommand.Command = _pruneContainersCommand
+ pruneContainersCommand.SetUsageTemplate(UsageTemplate())
+ flags := pruneContainersCommand.Flags()
+ flags.BoolVarP(&pruneContainersCommand.Force, "force", "f", false, "Force removal of a running container. The default is false")
}
-func pruneContainers(runtime *adapter.LocalRuntime, ctx context.Context, maxWorkers int, force bool) error {
+func pruneContainers(runtime *adapter.LocalRuntime, ctx context.Context, maxWorkers int, force, volumes bool) error {
var deleteFuncs []shared.ParallelWorkerInput
filter := func(c *libpod.Container) bool {
@@ -56,7 +58,7 @@ func pruneContainers(runtime *adapter.LocalRuntime, ctx context.Context, maxWork
for _, container := range delContainers {
con := container
f := func() error {
- return runtime.RemoveContainer(ctx, con, force)
+ return runtime.RemoveContainer(ctx, con, force, volumes)
}
deleteFuncs = append(deleteFuncs, shared.ParallelWorkerInput{
@@ -69,7 +71,7 @@ func pruneContainers(runtime *adapter.LocalRuntime, ctx context.Context, maxWork
return printParallelOutput(deleteErrors, errCount)
}
-func pruneContainersCmd(c *cliconfig.ContainersPrune) error {
+func pruneContainersCmd(c *cliconfig.PruneContainersValues) error {
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
@@ -82,5 +84,5 @@ func pruneContainersCmd(c *cliconfig.ContainersPrune) error {
}
logrus.Debugf("Setting maximum workers to %d", maxWorkers)
- return pruneContainers(runtime, getContext(), maxWorkers, c.Bool("force"))
+ return pruneContainers(runtime, getContext(), maxWorkers, c.Bool("force"), c.Bool("volumes"))
}
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 2f8742052..392163424 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -60,12 +60,12 @@ var (
func init() {
createCommand.PodmanCommand.Command = _createCommand
+ createCommand.SetUsageTemplate(UsageTemplate())
getCreateFlags(&createCommand.PodmanCommand)
flags := createCommand.Flags()
flags.SetInterspersed(true)
- rootCmd.AddCommand(createCommand.Command)
}
func createCmd(c *cliconfig.CreateValues) error {
@@ -646,9 +646,10 @@ func parseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
}
var ImageVolumes map[string]struct{}
- if data != nil {
+ if data != nil && c.String("image-volume") != "ignore" {
ImageVolumes = data.Config.Volumes
}
+
var imageVolType = map[string]string{
"bind": "",
"tmpfs": "",
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 04a659ab6..7d4cc1b58 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -52,6 +52,7 @@ var (
func init() {
diffCommand.Command = _diffCommand
+ diffCommand.SetUsageTemplate(UsageTemplate())
flags := diffCommand.Flags()
flags.BoolVar(&diffCommand.Archive, "archive", true, "Save the diff as a tar archive")
@@ -59,9 +60,8 @@ func init() {
flags.MarkHidden("archive")
- rootCmd.AddCommand(diffCommand.Command)
-
}
+
func formatJSON(output []diffOutputParams) (diffJSONOutput, error) {
jsonStruct := diffJSONOutput{}
for _, output := range output {
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index b4f66bc03..74808768e 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -35,6 +35,7 @@ var (
func init() {
execCommand.Command = _execCommand
+ execCommand.SetUsageTemplate(UsageTemplate())
flags := execCommand.Flags()
flags.SetInterspersed(false)
flags.StringSliceVarP(&execCommand.Env, "env", "e", []string{}, "Set environment variables")
@@ -46,7 +47,6 @@ func init() {
flags.StringVarP(&execCommand.Workdir, "workdir", "w", "", "Working directory inside the container")
- rootCmd.AddCommand(execCommand.Command)
}
func execCmd(c *cliconfig.ExecValues) error {
diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go
index a21e8fcf8..15ddaec06 100644
--- a/cmd/podman/exists.go
+++ b/cmd/podman/exists.go
@@ -72,8 +72,11 @@ var (
func init() {
imageExistsCommand.Command = _imageExistsCommand
+ imageExistsCommand.SetUsageTemplate(UsageTemplate())
containerExistsCommand.Command = _containerExistsCommand
+ containerExistsCommand.SetUsageTemplate(UsageTemplate())
podExistsCommand.Command = _podExistsCommand
+ podExistsCommand.SetUsageTemplate(UsageTemplate())
}
func imageExistsCmd(c *cliconfig.ImageExistsValues) error {
diff --git a/cmd/podman/export.go b/cmd/podman/export.go
index bd9e38b0c..2ce8186a1 100644
--- a/cmd/podman/export.go
+++ b/cmd/podman/export.go
@@ -31,9 +31,9 @@ var (
func init() {
exportCommand.Command = _exportCommand
+ exportCommand.SetUsageTemplate(UsageTemplate())
flags := exportCommand.Flags()
flags.StringVarP(&exportCommand.Output, "output", "o", "/dev/stdout", "Write to a file, default is STDOUT")
- rootCmd.AddCommand(exportCommand.Command)
}
// exportCmd saves a container to a tarball on disk
diff --git a/cmd/podman/generate.go b/cmd/podman/generate.go
index a5e15fdd6..66cb7a465 100644
--- a/cmd/podman/generate.go
+++ b/cmd/podman/generate.go
@@ -17,5 +17,5 @@ var generateCommand = cliconfig.PodmanCommand{
func init() {
generateCommand.AddCommand(getGenerateSubCommands()...)
- rootCmd.AddCommand(generateCommand.Command)
+ generateCommand.SetUsageTemplate(UsageTemplate())
}
diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go
index 8e3432d12..ddb2daa34 100644
--- a/cmd/podman/generate_kube.go
+++ b/cmd/podman/generate_kube.go
@@ -31,6 +31,7 @@ var (
func init() {
containerKubeCommand.Command = _containerKubeCommand
+ containerKubeCommand.SetUsageTemplate(UsageTemplate())
flags := containerKubeCommand.Flags()
flags.BoolVarP(&containerKubeCommand.Service, "service", "s", false, "Generate YAML for kubernetes service object")
}
diff --git a/cmd/podman/history.go b/cmd/podman/history.go
index 97e501947..6791257d9 100644
--- a/cmd/podman/history.go
+++ b/cmd/podman/history.go
@@ -53,6 +53,7 @@ var (
func init() {
historyCommand.Command = _historyCommand
+ historyCommand.SetUsageTemplate(UsageTemplate())
flags := historyCommand.Flags()
flags.StringVar(&historyCommand.Format, "format", "", "Change the output to JSON or a Go template")
flags.BoolVarP(&historyCommand.Human, "human", "H", true, "Display sizes and dates in human readable format")
@@ -60,9 +61,8 @@ func init() {
flags.BoolVar(&historyCommand.NoTrunc, "no-trunc", false, "Do not truncate the output")
flags.BoolVarP(&historyCommand.Quiet, "quiet", "q", false, "Display the numeric IDs only")
- rootCmd.AddCommand(historyCommand.Command)
-
}
+
func historyCmd(c *cliconfig.HistoryValues) error {
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
diff --git a/cmd/podman/image.go b/cmd/podman/image.go
index ac7ff4944..4f9c7cd6a 100644
--- a/cmd/podman/image.go
+++ b/cmd/podman/image.go
@@ -18,18 +18,21 @@ var (
//imageSubCommands are implemented both in local and remote clients
var imageSubCommands = []*cobra.Command{
+ _buildCommand,
_historyCommand,
_imageExistsCommand,
- _inspectCommand,
_imagesCommand,
+ _importCommand,
+ _inspectCommand,
_pruneImagesCommand,
+ _pullCommand,
_pushCommand,
_rmiCommand,
_tagCommand,
}
func init() {
+ imageCommand.SetUsageTemplate(UsageTemplate())
imageCommand.AddCommand(imageSubCommands...)
imageCommand.AddCommand(getImageSubCommands()...)
- rootCmd.AddCommand(imageCommand.Command)
}
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 6f5a3e9f1..b269f6440 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -102,6 +102,7 @@ var (
func init() {
imagesCommand.Command = _imagesCommand
+ imagesCommand.SetUsageTemplate(UsageTemplate())
flags := imagesCommand.Flags()
flags.BoolVarP(&imagesCommand.All, "all", "a", false, "Show all images (default hides intermediate images)")
flags.BoolVar(&imagesCommand.Digests, "digests", false, "Show digests")
@@ -114,8 +115,6 @@ func init() {
flags.BoolVarP(&imagesCommand.Quiet, "quiet", "q", false, "Display only image IDs")
flags.StringVar(&imagesCommand.Sort, "sort", "created", "Sort by created, id, repository, size, or tag")
- rootCmd.AddCommand(imagesCommand.Command)
-
}
func imagesCmd(c *cliconfig.ImagesValues) error {
@@ -248,8 +247,12 @@ func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerIma
}
// get all specified repo:tag pairs and print them separately
+ repopairs, err := image.ReposToMap(img.Names())
+ if err != nil {
+ logrus.Errorf("error finding tag/digest for %s", img.ID())
+ }
outer:
- for repo, tags := range image.ReposToMap(img.Names()) {
+ for repo, tags := range repopairs {
for _, tag := range tags {
size, err := img.Size(ctx)
var sizeStr string
diff --git a/cmd/podman/images_prune.go b/cmd/podman/images_prune.go
index ba99c5bde..cc0dcb99a 100644
--- a/cmd/podman/images_prune.go
+++ b/cmd/podman/images_prune.go
@@ -30,6 +30,7 @@ var (
func init() {
pruneImagesCommand.Command = _pruneImagesCommand
+ pruneImagesCommand.SetUsageTemplate(UsageTemplate())
flags := pruneImagesCommand.Flags()
flags.BoolVarP(&pruneImagesCommand.All, "all", "a", false, "Remove all unused images, not just dangling ones")
}
diff --git a/cmd/podman/import.go b/cmd/podman/import.go
index 52d144eb3..32f79757b 100644
--- a/cmd/podman/import.go
+++ b/cmd/podman/import.go
@@ -31,12 +31,12 @@ var (
func init() {
importCommand.Command = _importCommand
+ importCommand.SetUsageTemplate(UsageTemplate())
flags := importCommand.Flags()
flags.StringSliceVarP(&importCommand.Change, "change", "c", []string{}, "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR")
flags.StringVarP(&importCommand.Message, "message", "m", "", "Set commit message for imported image")
flags.BoolVarP(&importCommand.Quiet, "quiet", "q", false, "Suppress output")
- rootCmd.AddCommand(importCommand.Command)
}
func importCmd(c *cliconfig.ImportValues) error {
diff --git a/cmd/podman/info.go b/cmd/podman/info.go
index 0896e16a4..d60b8f84f 100644
--- a/cmd/podman/info.go
+++ b/cmd/podman/info.go
@@ -32,12 +32,12 @@ var (
func init() {
infoCommand.Command = _infoCommand
+ infoCommand.SetUsageTemplate(UsageTemplate())
flags := infoCommand.Flags()
flags.BoolVarP(&infoCommand.Debug, "debug", "D", false, "Display additional debug information")
flags.StringVarP(&infoCommand.Format, "format", "f", "", "Change the output format to JSON or a Go template")
- rootCmd.AddCommand(infoCommand.Command)
}
func infoCmd(c *cliconfig.InfoValues) error {
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index b2979c6ae..a29eb790e 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -40,13 +40,13 @@ var (
func init() {
inspectCommand.Command = _inspectCommand
+ inspectCommand.SetUsageTemplate(UsageTemplate())
flags := inspectCommand.Flags()
flags.StringVarP(&inspectCommand.TypeObject, "type", "t", inspectAll, "Return JSON for specified type, (e.g image, container or task)")
flags.StringVarP(&inspectCommand.Format, "format", "f", "", "Change the output format to a Go template")
flags.BoolVarP(&inspectCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of if the type is a container")
flags.BoolVarP(&inspectCommand.Size, "size", "s", false, "Display total file size if the type is container")
- rootCmd.AddCommand(inspectCommand.Command)
}
func inspectCmd(c *cliconfig.InspectValues) error {
diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go
index 04c0fd531..d922cf721 100644
--- a/cmd/podman/kill.go
+++ b/cmd/podman/kill.go
@@ -34,13 +34,13 @@ var (
func init() {
killCommand.Command = _killCommand
+ killCommand.SetUsageTemplate(UsageTemplate())
flags := killCommand.Flags()
flags.BoolVarP(&killCommand.All, "all", "a", false, "Signal all running containers")
flags.StringVarP(&killCommand.Signal, "signal", "s", "KILL", "Signal to send to the container")
flags.BoolVarP(&killCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- rootCmd.AddCommand(killCommand.Command)
}
// killCmd kills one or more containers with a signal
diff --git a/cmd/podman/load.go b/cmd/podman/load.go
index 90268ca8f..34a51cd0d 100644
--- a/cmd/podman/load.go
+++ b/cmd/podman/load.go
@@ -34,12 +34,12 @@ var (
func init() {
loadCommand.Command = _loadCommand
+ loadCommand.SetUsageTemplate(UsageTemplate())
flags := loadCommand.Flags()
flags.StringVarP(&loadCommand.Input, "input", "i", "/dev/stdin", "Read from archive file, default is STDIN")
flags.BoolVarP(&loadCommand.Quiet, "quiet", "q", false, "Suppress the output")
flags.StringVar(&loadCommand.SignaturePolicy, "signature-policy", "", "Pathname of signature policy file (not usually used)")
- rootCmd.AddCommand(loadCommand.Command)
}
// loadCmd gets the image/file to be loaded from the command line
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index 5ab0713e5..0bd58ff78 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -35,6 +35,7 @@ var (
func init() {
loginCommand.Command = _loginCommand
+ loginCommand.SetUsageTemplate(UsageTemplate())
flags := loginCommand.Flags()
flags.StringVar(&loginCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override")
@@ -44,7 +45,6 @@ func init() {
flags.BoolVar(&loginCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
flags.StringVarP(&loginCommand.Username, "username", "u", "", "Username for registry")
- rootCmd.AddCommand(loginCommand.Command)
}
// loginCmd uses the authentication package to store a user's authenticated credentials
diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go
index 02bde7857..5fecf814e 100644
--- a/cmd/podman/logout.go
+++ b/cmd/podman/logout.go
@@ -28,11 +28,11 @@ var (
func init() {
logoutCommand.Command = _logoutCommand
+ logoutCommand.SetUsageTemplate(UsageTemplate())
flags := logoutCommand.Flags()
flags.BoolVarP(&logoutCommand.All, "all", "a", false, "Remove the cached credentials for all registries in the auth file")
flags.StringVar(&logoutCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override")
- rootCmd.AddCommand(logoutCommand.Command)
}
// logoutCmd uses the authentication package to remove the authenticated of a registry
diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go
index 83f900e63..6962a1f6d 100644
--- a/cmd/podman/logs.go
+++ b/cmd/podman/logs.go
@@ -32,6 +32,7 @@ var (
func init() {
logsCommand.Command = _logsCommand
+ logsCommand.SetUsageTemplate(UsageTemplate())
flags := logsCommand.Flags()
flags.BoolVar(&logsCommand.Details, "details", false, "Show extra details provided to the logs")
flags.BoolVarP(&logsCommand.Follow, "follow", "f", false, "Follow log output. The default is false")
@@ -43,7 +44,6 @@ func init() {
flags.SetInterspersed(false)
- rootCmd.AddCommand(logsCommand.Command)
}
func logsCmd(c *cliconfig.LogsValues) error {
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 32ecaede7..f9820c075 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -27,6 +27,26 @@ var (
exitCode = 125
)
+// Commands that the remote and local client have
+// implemented.
+var mainCommands = []*cobra.Command{
+ _buildCommand,
+ _exportCommand,
+ _historyCommand,
+ _imagesCommand,
+ _importCommand,
+ _infoCommand,
+ _inspectCommand,
+ _killCommand,
+ _pullCommand,
+ _pushCommand,
+ _rmiCommand,
+ _tagCommand,
+ _versionCommand,
+ imageCommand.Command,
+ systemCommand.Command,
+}
+
var cmdsNotRequiringRootless = map[*cobra.Command]bool{
_versionCommand: true,
_createCommand: true,
@@ -40,7 +60,7 @@ var cmdsNotRequiringRootless = map[*cobra.Command]bool{
_killCommand: true,
_pauseCommand: true,
_restartCommand: true,
- _runCommmand: true,
+ _runCommand: true,
_unpauseCommand: true,
_searchCommand: true,
_statsCommand: true,
@@ -92,6 +112,8 @@ func init() {
rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Syslog, "syslog", false, "Output logging information to syslog as well as the console")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.TmpDir, "tmpdir", "", "Path to the tmp directory")
+ rootCmd.AddCommand(mainCommands...)
+ rootCmd.AddCommand(getMainCommands()...)
}
func initConfig() {
@@ -185,7 +207,7 @@ func main() {
exitCode = status.ExitStatus()
}
}
- fmt.Fprintln(os.Stderr, err.Error())
+ fmt.Fprintln(os.Stderr, "Error:", err.Error())
}
} else {
// The exitCode modified from 125, indicates an application
diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go
index 36ca8bcfb..ce7c22d60 100644
--- a/cmd/podman/mount.go
+++ b/cmd/podman/mount.go
@@ -39,13 +39,13 @@ var (
func init() {
mountCommand.Command = _mountCommand
+ mountCommand.SetUsageTemplate(UsageTemplate())
flags := mountCommand.Flags()
flags.BoolVarP(&mountCommand.All, "all", "a", false, "Mount all containers")
flags.StringVar(&mountCommand.Format, "format", "", "Change the output format to Go template")
flags.BoolVarP(&mountCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&mountCommand.NoTrunc, "notruncate", false, "Do not truncate output")
- rootCmd.AddCommand(mountCommand.Command)
}
// jsonMountPoint stores info about each container
diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go
index 466a3b136..a840cbe49 100644
--- a/cmd/podman/pause.go
+++ b/cmd/podman/pause.go
@@ -34,10 +34,10 @@ var (
func init() {
pauseCommand.Command = _pauseCommand
+ pauseCommand.SetUsageTemplate(UsageTemplate())
flags := pauseCommand.Flags()
flags.BoolVarP(&pauseCommand.All, "all", "a", false, "Pause all running containers")
- rootCmd.AddCommand(pauseCommand.Command)
}
func pauseCmd(c *cliconfig.PauseValues) error {
diff --git a/cmd/podman/play.go b/cmd/podman/play.go
index ff8320a6b..495a1f170 100644
--- a/cmd/podman/play.go
+++ b/cmd/podman/play.go
@@ -5,19 +5,18 @@ import (
"github.com/spf13/cobra"
)
-var playCommand cliconfig.PodmanCommand
-
-func init() {
- var playDescription = "Play a pod and its containers from a structured file."
- playCommand.Command = &cobra.Command{
+var (
+ playCommand cliconfig.PodmanCommand
+ playDescription = "Play a pod and its containers from a structured file."
+ _playCommand = &cobra.Command{
Use: "play",
Short: "Play a pod",
Long: playDescription,
}
-
-}
+)
func init() {
+ playCommand.Command = _playCommand
+ playCommand.SetUsageTemplate(UsageTemplate())
playCommand.AddCommand(getPlaySubCommands()...)
- rootCmd.AddCommand(playCommand.Command)
}
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
index b314c1278..4ecd30cd4 100644
--- a/cmd/podman/play_kube.go
+++ b/cmd/podman/play_kube.go
@@ -43,6 +43,7 @@ var (
func init() {
playKubeCommand.Command = _playKubeCommand
+ playKubeCommand.SetUsageTemplate(UsageTemplate())
flags := playKubeCommand.Flags()
flags.StringVar(&playKubeCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&playKubeCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go
index 4104c39c7..e988875ab 100644
--- a/cmd/podman/pod.go
+++ b/cmd/podman/pod.go
@@ -20,5 +20,5 @@ var podCommand = cliconfig.PodmanCommand{
func init() {
podCommand.AddCommand(getPodSubCommands()...)
- rootCmd.AddCommand(podCommand.Command)
+ podCommand.SetUsageTemplate(UsageTemplate())
}
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index 35e58df31..0a0b86aab 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -38,6 +38,7 @@ var (
func init() {
podCreateCommand.Command = _podCreateCommand
+ podCreateCommand.SetUsageTemplate(UsageTemplate())
flags := podCreateCommand.Flags()
flags.SetInterspersed(false)
diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go
index f4c357e96..a0b691642 100644
--- a/cmd/podman/pod_inspect.go
+++ b/cmd/podman/pod_inspect.go
@@ -29,6 +29,7 @@ var (
func init() {
podInspectCommand.Command = _podInspectCommand
+ podInspectCommand.SetUsageTemplate(UsageTemplate())
flags := podInspectCommand.Flags()
flags.BoolVarP(&podInspectCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go
index 43411a988..febc820cd 100644
--- a/cmd/podman/pod_kill.go
+++ b/cmd/podman/pod_kill.go
@@ -30,6 +30,7 @@ var (
func init() {
podKillCommand.Command = _podKillCommand
+ podKillCommand.SetUsageTemplate(UsageTemplate())
flags := podKillCommand.Flags()
flags.BoolVarP(&podKillCommand.All, "all", "a", false, "Kill all containers in all pods")
flags.BoolVarP(&podKillCommand.Latest, "latest", "l", false, "Act on the latest pod podman is aware of")
diff --git a/cmd/podman/pod_pause.go b/cmd/podman/pod_pause.go
index a54783d88..2059727ae 100644
--- a/cmd/podman/pod_pause.go
+++ b/cmd/podman/pod_pause.go
@@ -27,6 +27,7 @@ var (
func init() {
podPauseCommand.Command = _podPauseCommand
+ podPauseCommand.SetUsageTemplate(UsageTemplate())
flags := podPauseCommand.Flags()
flags.BoolVarP(&podPauseCommand.All, "all", "a", false, "Pause all running pods")
flags.BoolVarP(&podPauseCommand.Latest, "latest", "l", false, "Act on the latest pod podman is aware of")
diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go
index 991e294bf..49af91a1e 100644
--- a/cmd/podman/pod_ps.go
+++ b/cmd/podman/pod_ps.go
@@ -131,6 +131,7 @@ var (
func init() {
podPsCommand.Command = _podPsCommand
+ podPsCommand.SetUsageTemplate(UsageTemplate())
flags := podPsCommand.Flags()
flags.BoolVar(&podPsCommand.CtrNames, "ctr-names", false, "Display the container names")
flags.BoolVar(&podPsCommand.CtrIDs, "ctr-ids", false, "Display the container UUIDs. If no-trunc is not set they will be truncated")
diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go
index 4d05205ea..f75d84956 100644
--- a/cmd/podman/pod_restart.go
+++ b/cmd/podman/pod_restart.go
@@ -28,6 +28,7 @@ var (
func init() {
podRestartCommand.Command = _podRestartCommand
+ podRestartCommand.SetUsageTemplate(UsageTemplate())
flags := podRestartCommand.Flags()
flags.BoolVarP(&podRestartCommand.All, "all", "a", false, "Restart all running pods")
flags.BoolVarP(&podRestartCommand.Latest, "latest", "l", false, "Restart the latest pod podman is aware of")
diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go
index 445a641df..389f44a20 100644
--- a/cmd/podman/pod_rm.go
+++ b/cmd/podman/pod_rm.go
@@ -32,6 +32,7 @@ If --force is specified, all containers will be stopped, then removed.
func init() {
podRmCommand.Command = _podRmCommand
+ podRmCommand.SetUsageTemplate(UsageTemplate())
flags := podRmCommand.Flags()
flags.BoolVarP(&podRmCommand.All, "all", "a", false, "Remove all running pods")
flags.BoolVarP(&podRmCommand.Force, "force", "f", false, "Force removal of a running pod by first stopping all containers, then removing all containers in the pod. The default is false")
diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go
index 8b35d3e04..829fe2107 100644
--- a/cmd/podman/pod_start.go
+++ b/cmd/podman/pod_start.go
@@ -32,6 +32,7 @@ var (
func init() {
podStartCommand.Command = _podStartCommand
+ podStartCommand.SetUsageTemplate(UsageTemplate())
flags := podStartCommand.Flags()
flags.BoolVarP(&podStartCommand.All, "all", "a", false, "Start all pods")
flags.BoolVarP(&podStartCommand.Latest, "latest", "l", false, "Start the latest pod podman is aware of")
diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go
index 02dee68ac..7afab6be9 100644
--- a/cmd/podman/pod_stats.go
+++ b/cmd/podman/pod_stats.go
@@ -38,6 +38,7 @@ var (
func init() {
podStatsCommand.Command = _podStatsCommand
+ podStatsCommand.SetUsageTemplate(UsageTemplate())
flags := podStatsCommand.Flags()
flags.BoolVarP(&podStatsCommand.All, "all", "a", false, "Provide stats for all running pods")
flags.StringVar(&podStatsCommand.Format, "format", "", "Pretty-print container statistics to JSON or using a Go template")
diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go
index 63bd0f5cb..80082045d 100644
--- a/cmd/podman/pod_stop.go
+++ b/cmd/podman/pod_stop.go
@@ -33,6 +33,7 @@ var (
func init() {
podStopCommand.Command = _podStopCommand
+ podStopCommand.SetUsageTemplate(UsageTemplate())
flags := podStopCommand.Flags()
flags.BoolVarP(&podStopCommand.All, "all", "a", false, "Stop all running pods")
flags.BoolVarP(&podStopCommand.Latest, "latest", "l", false, "Stop the latest pod podman is aware of")
diff --git a/cmd/podman/pod_top.go b/cmd/podman/pod_top.go
index f1db2fac5..411c782bd 100644
--- a/cmd/podman/pod_top.go
+++ b/cmd/podman/pod_top.go
@@ -39,6 +39,7 @@ the latest pod.
func init() {
podTopCommand.Command = _podTopCommand
+ podTopCommand.SetUsageTemplate(UsageTemplate())
flags := podTopCommand.Flags()
flags.BoolVarP(&podTopCommand.Latest, "latest,", "l", false, "Act on the latest pod podman is aware of")
flags.BoolVar(&podTopCommand.ListDescriptors, "list-descriptors", false, "")
diff --git a/cmd/podman/pod_unpause.go b/cmd/podman/pod_unpause.go
index 17b771d4a..a917919c3 100644
--- a/cmd/podman/pod_unpause.go
+++ b/cmd/podman/pod_unpause.go
@@ -28,6 +28,7 @@ var (
func init() {
podUnpauseCommand.Command = _podUnpauseCommand
+ podUnpauseCommand.SetUsageTemplate(UsageTemplate())
flags := podUnpauseCommand.Flags()
flags.BoolVarP(&podUnpauseCommand.All, "all", "a", false, "Unpause all running pods")
flags.BoolVarP(&podUnpauseCommand.Latest, "latest", "l", false, "Unpause the latest pod podman is aware of")
diff --git a/cmd/podman/port.go b/cmd/podman/port.go
index 488ef2ffe..be84da065 100644
--- a/cmd/podman/port.go
+++ b/cmd/podman/port.go
@@ -34,12 +34,12 @@ var (
func init() {
portCommand.Command = _portCommand
+ portCommand.SetUsageTemplate(UsageTemplate())
flags := portCommand.Flags()
flags.BoolVarP(&portCommand.All, "all", "a", false, "Display port information for all containers")
flags.BoolVarP(&portCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- rootCmd.AddCommand(portCommand.Command)
}
func portCmd(c *cliconfig.PortValues) error {
@@ -125,8 +125,13 @@ func portCmd(c *cliconfig.PortValues) error {
if c.All {
fmt.Println(con.ID())
}
+
+ portmappings, err := con.PortMappings()
+ if err != nil {
+ return err
+ }
// Iterate mappings
- for _, v := range con.Config().PortMappings {
+ for _, v := range portmappings {
hostIP := v.HostIP
// Set host IP to 0.0.0.0 if blank
if hostIP == "" {
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 002975b87..949f78a34 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -172,6 +172,7 @@ var (
func init() {
psCommand.Command = _psCommand
+ psCommand.SetUsageTemplate(UsageTemplate())
flags := psCommand.Flags()
flags.BoolVarP(&psCommand.All, "all", "a", false, "Show all the containers, default is only running containers")
flags.StringSliceVarP(&psCommand.Filter, "filter", "f", []string{}, "Filter output based on conditions given")
@@ -187,9 +188,8 @@ func init() {
flags.StringVar(&psCommand.Sort, "sort", "created", "Sort output by command, created, id, image, names, runningfor, size, or status")
flags.BoolVar(&psCommand.Sync, "sync", false, "Sync container state with OCI runtime")
- rootCmd.AddCommand(psCommand.Command)
-
}
+
func psCmd(c *cliconfig.PsValues) error {
var (
filterFuncs []libpod.ContainerFilter
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index d70719164..6d9d1a278 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -40,6 +40,7 @@ specified, the image with the 'latest' tag (if it exists) is pulled
func init() {
pullCommand.Command = _pullCommand
+ pullCommand.SetUsageTemplate(UsageTemplate())
flags := pullCommand.Flags()
flags.StringVar(&pullCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&pullCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
@@ -48,7 +49,6 @@ func init() {
flags.StringVar(&pullCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.BoolVar(&pullCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
- rootCmd.AddCommand(pullCommand.Command)
}
// pullCmd gets the data from the command line and calls pullImage
diff --git a/cmd/podman/push.go b/cmd/podman/push.go
index a1ee00a65..bbe8a4027 100644
--- a/cmd/podman/push.go
+++ b/cmd/podman/push.go
@@ -2,8 +2,6 @@ package main
import (
"fmt"
- "github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/spf13/cobra"
"io"
"os"
"strings"
@@ -11,11 +9,13 @@ import (
"github.com/containers/image/directory"
"github.com/containers/image/manifest"
"github.com/containers/image/types"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/util"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
+ "github.com/spf13/cobra"
)
var (
@@ -40,6 +40,7 @@ var (
func init() {
pushCommand.Command = _pushCommand
+ pushCommand.SetUsageTemplate(UsageTemplate())
flags := pushCommand.Flags()
flags.MarkHidden("signature-policy")
flags.StringVar(&pushCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override")
@@ -52,7 +53,6 @@ func init() {
flags.StringVar(&pushCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.StringVar(&pushCommand.SignBy, "sign-by", "", "Add a signature at the destination using the specified key")
flags.BoolVar(&pushCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
- rootCmd.AddCommand(pushCommand.Command)
}
func pushCmd(c *cliconfig.PushValues) error {
@@ -93,7 +93,7 @@ func pushCmd(c *cliconfig.PushValues) error {
registryCreds = creds
}
- runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
@@ -131,12 +131,7 @@ func pushCmd(c *cliconfig.PushValues) error {
SignBy: signBy,
}
- newImage, err := runtime.ImageRuntime().NewFromLocal(srcName)
- if err != nil {
- return err
- }
-
authfile := getAuthFile(c.Authfile)
- return newImage.PushImageToHeuristicDestination(getContext(), destName, manifestType, authfile, c.SignaturePolicy, writer, c.Compress, so, &dockerRegistryOptions, nil)
+ return runtime.Push(getContext(), srcName, destName, manifestType, authfile, c.SignaturePolicy, writer, c.Compress, so, &dockerRegistryOptions, nil)
}
diff --git a/cmd/podman/refresh.go b/cmd/podman/refresh.go
index 3890188b4..641748452 100644
--- a/cmd/podman/refresh.go
+++ b/cmd/podman/refresh.go
@@ -27,7 +27,7 @@ var (
func init() {
refreshCommand.Command = _refreshCommand
- rootCmd.AddCommand(refreshCommand.Command)
+ refreshCommand.SetUsageTemplate(UsageTemplate())
}
func refreshCmd(c *cliconfig.RefreshValues) error {
diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go
index f94e745ed..235107b5c 100644
--- a/cmd/podman/restart.go
+++ b/cmd/podman/restart.go
@@ -32,6 +32,7 @@ var (
func init() {
restartCommand.Command = _restartCommand
+ restartCommand.SetUsageTemplate(UsageTemplate())
flags := restartCommand.Flags()
flags.BoolVarP(&restartCommand.All, "all", "a", false, "Restart all non-running containers")
flags.BoolVarP(&restartCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
@@ -39,7 +40,6 @@ func init() {
flags.UintVarP(&restartCommand.Timeout, "timeout", "t", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
flags.UintVar(&restartCommand.Timeout, "time", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
- rootCmd.AddCommand(restartCommand.Command)
}
func restartCmd(c *cliconfig.RestartValues) error {
diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go
index daee635f0..556cdb774 100644
--- a/cmd/podman/restore.go
+++ b/cmd/podman/restore.go
@@ -35,6 +35,7 @@ var (
func init() {
restoreCommand.Command = _restoreCommand
+ restoreCommand.SetUsageTemplate(UsageTemplate())
flags := restoreCommand.Flags()
flags.BoolVarP(&restoreCommand.All, "all", "a", false, "Restore all checkpointed containers")
flags.BoolVarP(&restoreCommand.Keep, "keep", "k", false, "Keep all temporary checkpoint files")
@@ -42,7 +43,6 @@ func init() {
// TODO: add ContainerStateCheckpointed
flags.BoolVar(&restoreCommand.TcpEstablished, "tcp-established", false, "Checkpoint a container with established TCP connections")
- rootCmd.AddCommand(restoreCommand.Command)
}
func restoreCmd(c *cliconfig.RestoreValues) error {
diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go
index bb9a913c9..d170e5357 100644
--- a/cmd/podman/rm.go
+++ b/cmd/podman/rm.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
+ "github.com/containers/libpod/libpod"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -33,13 +34,12 @@ Running containers will not be removed without the -f option.
func init() {
rmCommand.Command = _rmCommand
+ rmCommand.SetUsageTemplate(UsageTemplate())
flags := rmCommand.Flags()
flags.BoolVarP(&rmCommand.All, "all", "a", false, "Remove all containers")
flags.BoolVarP(&rmCommand.Force, "force", "f", false, "Force removal of a running container. The default is false")
flags.BoolVarP(&rmCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- flags.BoolVarP(&rmCommand.Volumes, "volumes", "v", false, "Remove the volumes associated with the container (Not implemented yet)")
-
- rootCmd.AddCommand(rmCommand.Command)
+ flags.BoolVarP(&rmCommand.Volumes, "volumes", "v", false, "Remove the volumes associated with the container")
}
// saveCmd saves the image to either docker-archive or oci
@@ -61,16 +61,24 @@ func rmCmd(c *cliconfig.RmValues) error {
delContainers, err := getAllOrLatestContainers(&c.PodmanCommand, runtime, -1, "all")
if err != nil {
+ if c.Force && len(c.InputArgs) > 0 {
+ if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ err = nil
+ }
+ runtime.RemoveContainersFromStorage(c.InputArgs)
+ }
if len(delContainers) == 0 {
return err
}
- fmt.Println(err.Error())
+ if err != nil {
+ fmt.Println(err.Error())
+ }
}
for _, container := range delContainers {
con := container
f := func() error {
- return runtime.RemoveContainer(ctx, con, c.Force)
+ return runtime.RemoveContainer(ctx, con, c.Force, c.Volumes)
}
deleteFuncs = append(deleteFuncs, shared.ParallelWorkerInput{
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index 70f58e844..c5bd1e190 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -29,11 +29,10 @@ var (
func init() {
rmiCommand.Command = _rmiCommand
+ rmiCommand.SetUsageTemplate(UsageTemplate())
flags := rmiCommand.Flags()
flags.BoolVarP(&rmiCommand.All, "all", "a", false, "Remove all images")
flags.BoolVarP(&rmiCommand.Force, "force", "f", false, "Force Removal of the image")
-
- rootCmd.AddCommand(rmiCommand.Command)
}
func rmiCmd(c *cliconfig.RmiValues) error {
diff --git a/cmd/podman/run.go b/cmd/podman/run.go
index 76b29cb84..64f8b6856 100644
--- a/cmd/podman/run.go
+++ b/cmd/podman/run.go
@@ -18,30 +18,29 @@ import (
)
var (
- runCommmand cliconfig.RunValues
+ runCommand cliconfig.RunValues
runDescription = "Runs a command in a new container from the given image"
- _runCommmand = &cobra.Command{
+ _runCommand = &cobra.Command{
Use: "run",
Short: "Run a command in a new container",
Long: runDescription,
RunE: func(cmd *cobra.Command, args []string) error {
- runCommmand.InputArgs = args
- runCommmand.GlobalFlags = MainGlobalOpts
- return runCmd(&runCommmand)
+ runCommand.InputArgs = args
+ runCommand.GlobalFlags = MainGlobalOpts
+ return runCmd(&runCommand)
},
Example: "IMAGE [COMMAND [ARG...]]",
}
)
func init() {
- runCommmand.Command = _runCommmand
- flags := runCommmand.Flags()
+ runCommand.Command = _runCommand
+ runCommand.SetUsageTemplate(UsageTemplate())
+ flags := runCommand.Flags()
flags.SetInterspersed(false)
flags.Bool("sig-proxy", true, "Proxy received signals to the process (default true)")
- getCreateFlags(&runCommmand.PodmanCommand)
-
- rootCmd.AddCommand(runCommmand.Command)
+ getCreateFlags(&runCommand.PodmanCommand)
}
func runCmd(c *cliconfig.RunValues) error {
@@ -119,13 +118,21 @@ func runCmd(c *cliconfig.RunValues) error {
}
}
if err := startAttachCtr(ctr, outputStream, errorStream, inputStream, c.String("detach-keys"), c.Bool("sig-proxy"), true); err != nil {
+ // We've manually detached from the container
+ // Do not perform cleanup, or wait for container exit code
+ // Just exit immediately
+ if errors.Cause(err) == libpod.ErrDetach {
+ exitCode = 0
+ return nil
+ }
+
// This means the command did not exist
exitCode = 127
if strings.Index(err.Error(), "permission denied") > -1 {
exitCode = 126
}
if c.IsSet("rm") {
- if deleteError := runtime.RemoveContainer(ctx, ctr, true); deleteError != nil {
+ if deleteError := runtime.RemoveContainer(ctx, ctr, true, false); deleteError != nil {
logrus.Errorf("unable to remove container %s after failing to start and attach to it", ctr.ID())
}
}
@@ -148,28 +155,12 @@ func runCmd(c *cliconfig.RunValues) error {
exitCode = int(ecode)
}
- if createConfig.Rm {
- return runtime.RemoveContainer(ctx, ctr, true)
- }
-
- if err := ctr.Cleanup(ctx); err != nil {
- // If the container has been removed already, no need to error on cleanup
- // Also, if it was restarted, don't error either
- if errors.Cause(err) == libpod.ErrNoSuchCtr ||
- errors.Cause(err) == libpod.ErrCtrRemoved ||
- errors.Cause(err) == libpod.ErrCtrStateInvalid {
- return nil
- }
-
- return err
- }
-
return nil
}
// Read a container's exit file
func readExitFile(runtimeTmp, ctrID string) (int, error) {
- exitFile := filepath.Join(runtimeTmp, "exits", ctrID)
+ exitFile := filepath.Join(runtimeTmp, "exits", fmt.Sprintf("%s-old", ctrID))
logrus.Debugf("Attempting to read container %s exit code from file %s", ctrID, exitFile)
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index ff8a282d3..f1c61ebda 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -37,6 +37,7 @@ Executes a command as described by a container image label.
func init() {
runlabelCommand.Command = _runlabelCommand
+ runlabelCommand.SetUsageTemplate(UsageTemplate())
flags := runlabelCommand.Flags()
flags.StringVar(&runlabelCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&runlabelCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
diff --git a/cmd/podman/save.go b/cmd/podman/save.go
index 766561f1a..1ae1bc872 100644
--- a/cmd/podman/save.go
+++ b/cmd/podman/save.go
@@ -47,13 +47,12 @@ var (
func init() {
saveCommand.Command = _saveCommand
+ saveCommand.SetUsageTemplate(UsageTemplate())
flags := saveCommand.Flags()
flags.BoolVar(&saveCommand.Compress, "compress", false, "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)")
flags.StringVar(&saveCommand.Format, "format", "", "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-dir (directory with v2s2 manifest type)")
flags.StringVarP(&saveCommand.Output, "output", "o", "/dev/stdout", "Write to a file, default is STDOUT")
flags.BoolVarP(&saveCommand.Quiet, "quiet", "q", false, "Suppress the output")
-
- rootCmd.AddCommand(saveCommand.Command)
}
// saveCmd saves the image to either docker-archive or oci
diff --git a/cmd/podman/search.go b/cmd/podman/search.go
index b15da1f6d..2febee689 100644
--- a/cmd/podman/search.go
+++ b/cmd/podman/search.go
@@ -43,6 +43,7 @@ var (
func init() {
searchCommand.Command = _searchCommand
+ searchCommand.SetUsageTemplate(UsageTemplate())
flags := searchCommand.Flags()
flags.StringVar(&searchCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringSliceVarP(&searchCommand.Filter, "filter", "f", []string{}, "Filter output based on conditions provided (default [])")
@@ -50,8 +51,6 @@ func init() {
flags.IntVar(&searchCommand.Limit, "limit", 0, "Limit the number of results")
flags.BoolVar(&searchCommand.NoTrunc, "no-trunc", false, "Do not truncate the output")
flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
-
- rootCmd.AddCommand(searchCommand.Command)
}
type searchParams struct {
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
index c74d8fdce..81811e0f2 100644
--- a/cmd/podman/shared/container.go
+++ b/cmd/podman/shared/container.go
@@ -213,11 +213,16 @@ func NewBatchContainer(ctr *libpod.Container, opts PsOptions) (PsContainerOutput
}
}
+ ports, err := ctr.PortMappings()
+ if err != nil {
+ logrus.Errorf("unable to lookup namespace container for %s", ctr.ID())
+ }
+
pso.ID = cid
pso.Image = imageName
pso.Command = command
pso.Created = created
- pso.Ports = portsToString(ctr.PortMappings())
+ pso.Ports = portsToString(ports)
pso.Names = ctr.Name()
pso.IsInfra = ctr.IsInfra()
pso.Status = status
diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go
index a87c12556..ac0d985f5 100644
--- a/cmd/podman/sign.go
+++ b/cmd/podman/sign.go
@@ -38,12 +38,11 @@ var (
func init() {
signCommand.Command = _signCommand
+ signCommand.SetUsageTemplate(UsageTemplate())
flags := signCommand.Flags()
flags.StringVarP(&signCommand.Directory, "directory", "d", "", "Define an alternate directory to store signatures")
flags.StringVar(&signCommand.SignBy, "sign-by", "", "Name of the signing key")
- rootCmd.AddCommand(signCommand.Command)
-
}
// SignatureStoreDir defines default directory to store signatures
diff --git a/cmd/podman/start.go b/cmd/podman/start.go
index 483ab4081..3a606d662 100644
--- a/cmd/podman/start.go
+++ b/cmd/podman/start.go
@@ -36,14 +36,13 @@ var (
func init() {
startCommand.Command = _startCommand
+ startCommand.SetUsageTemplate(UsageTemplate())
flags := startCommand.Flags()
flags.BoolVarP(&startCommand.Attach, "attach", "a", false, "Attach container's STDOUT and STDERR")
flags.StringVar(&startCommand.DetachKeys, "detach-keys", "", "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
flags.BoolVarP(&startCommand.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
flags.BoolVarP(&startCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&startCommand.SigProxy, "sig-proxy", true, "Proxy received signals to the process (default true if attaching, false otherwise)")
-
- rootCmd.AddCommand(startCommand.Command)
}
func startCmd(c *cliconfig.StartValues) error {
@@ -109,6 +108,13 @@ func startCmd(c *cliconfig.StartValues) error {
// attach to the container and also start it not already running
err = startAttachCtr(ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, sigProxy, !ctrRunning)
+ if errors.Cause(err) == libpod.ErrDetach {
+ // User manually detached
+ // Exit cleanly immediately
+ exitCode = 0
+ return nil
+ }
+
if ctrRunning {
return err
}
@@ -138,7 +144,7 @@ func startCmd(c *cliconfig.StartValues) error {
logrus.Errorf("unable to detect if container %s should be deleted", ctr.ID())
}
if createArtifact.Rm {
- if rmErr := runtime.RemoveContainer(ctx, ctr, true); rmErr != nil {
+ if rmErr := runtime.RemoveContainer(ctx, ctr, true, false); rmErr != nil {
logrus.Errorf("unable to remove container %s after it failed to start", ctr.ID())
}
}
diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go
index 8c79ed290..af9bbad0e 100644
--- a/cmd/podman/stats.go
+++ b/cmd/podman/stats.go
@@ -47,14 +47,13 @@ var (
func init() {
statsCommand.Command = _statsCommand
+ statsCommand.SetUsageTemplate(UsageTemplate())
flags := statsCommand.Flags()
flags.BoolVarP(&statsCommand.All, "all", "a", false, "Show all containers. Only running containers are shown by default. The default is false")
flags.StringVar(&statsCommand.Format, "format", "", "Pretty-print container statistics to JSON or using a Go template")
flags.BoolVarP(&statsCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.BoolVar(&statsCommand.NoReset, "no-reset", false, "Disable resetting the screen between intervals")
flags.BoolVar(&statsCommand.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result, default setting is false")
-
- rootCmd.AddCommand(statsCommand.Command)
}
func statsCmd(c *cliconfig.StatsValues) error {
diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go
index e2c16fe20..134d8a069 100644
--- a/cmd/podman/stop.go
+++ b/cmd/podman/stop.go
@@ -37,13 +37,12 @@ var (
func init() {
stopCommand.Command = _stopCommand
+ stopCommand.SetUsageTemplate(UsageTemplate())
flags := stopCommand.Flags()
flags.BoolVarP(&stopCommand.All, "all", "a", false, "Stop all running containers")
flags.BoolVarP(&stopCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.UintVar(&stopCommand.Timeout, "time", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
flags.UintVarP(&stopCommand.Timeout, "timeout", "t", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container")
-
- rootCmd.AddCommand(stopCommand.Command)
}
func stopCmd(c *cliconfig.StopValues) error {
diff --git a/cmd/podman/system.go b/cmd/podman/system.go
index f6b28fee1..741b79da5 100644
--- a/cmd/podman/system.go
+++ b/cmd/podman/system.go
@@ -17,7 +17,12 @@ var (
}
)
+var systemCommands = []*cobra.Command{
+ _infoCommand,
+}
+
func init() {
+ systemCommand.AddCommand(systemCommands...)
systemCommand.AddCommand(getSystemSubCommands()...)
- rootCmd.AddCommand(systemCommand.Command)
+ systemCommand.SetUsageTemplate(UsageTemplate())
}
diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go
index c918fbe3b..a91d7bf0a 100644
--- a/cmd/podman/system_prune.go
+++ b/cmd/podman/system_prune.go
@@ -34,8 +34,8 @@ var (
)
func init() {
-
pruneSystemCommand.Command = _pruneSystemCommand
+ pruneSystemCommand.SetUsageTemplate(UsageTemplate())
flags := pruneSystemCommand.Flags()
flags.BoolVarP(&pruneSystemCommand.All, "all", "a", false, "Remove all unused data")
flags.BoolVarP(&pruneSystemCommand.Force, "force", "f", false, "Do not prompt for confirmation")
@@ -76,7 +76,7 @@ Are you sure you want to continue? [y/N] `, volumeString)
ctx := getContext()
fmt.Println("Deleted Containers")
- lasterr := pruneContainers(runtime, ctx, shared.Parallelize("rm"), false)
+ lasterr := pruneContainers(runtime, ctx, shared.Parallelize("rm"), false, false)
if c.Bool("volumes") {
fmt.Println("Deleted Volumes")
err := volumePrune(runtime, getContext())
diff --git a/cmd/podman/tag.go b/cmd/podman/tag.go
index 2c7cf4abb..135c2f7a0 100644
--- a/cmd/podman/tag.go
+++ b/cmd/podman/tag.go
@@ -26,8 +26,7 @@ var (
func init() {
tagCommand.Command = _tagCommand
- rootCmd.AddCommand(tagCommand.Command)
-
+ tagCommand.SetUsageTemplate(UsageTemplate())
}
func tagCmd(c *cliconfig.TagValues) error {
diff --git a/cmd/podman/top.go b/cmd/podman/top.go
index a03830ee5..51b813e5a 100644
--- a/cmd/podman/top.go
+++ b/cmd/podman/top.go
@@ -48,12 +48,11 @@ the latest container.
func init() {
topCommand.Command = _topCommand
+ topCommand.SetUsageTemplate(UsageTemplate())
flags := topCommand.Flags()
flags.BoolVar(&topCommand.ListDescriptors, "list-descriptors", false, "")
flags.MarkHidden("list-descriptors")
flags.BoolVarP(&topCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
-
- rootCmd.AddCommand(topCommand.Command)
}
func topCmd(c *cliconfig.TopValues) error {
diff --git a/cmd/podman/trust.go b/cmd/podman/trust.go
index 6304586c3..8b02dcdc6 100644
--- a/cmd/podman/trust.go
+++ b/cmd/podman/trust.go
@@ -16,6 +16,7 @@ var (
)
func init() {
+ trustCommand.SetUsageTemplate(UsageTemplate())
trustCommand.AddCommand(getTrustSubCommands()...)
imageCommand.AddCommand(trustCommand.Command)
}
diff --git a/cmd/podman/trust_set_show.go b/cmd/podman/trust_set_show.go
index cd9438220..f3d1cadce 100644
--- a/cmd/podman/trust_set_show.go
+++ b/cmd/podman/trust_set_show.go
@@ -49,9 +49,10 @@ var (
)
func init() {
-
setTrustCommand.Command = _setTrustCommand
+ setTrustCommand.SetUsageTemplate(UsageTemplate())
showTrustCommand.Command = _showTrustCommand
+ showTrustCommand.SetUsageTemplate(UsageTemplate())
setFlags := setTrustCommand.Flags()
setFlags.StringVar(&setTrustCommand.PolicyPath, "policypath", "", "")
setFlags.MarkHidden("policypath")
diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go
index 4622e8276..20ea410c2 100644
--- a/cmd/podman/umount.go
+++ b/cmd/podman/umount.go
@@ -37,12 +37,11 @@ An unmount can be forced with the --force flag.
func init() {
umountCommand.Command = _umountCommand
+ umountCommand.SetUsageTemplate(UsageTemplate())
flags := umountCommand.Flags()
flags.BoolVarP(&umountCommand.All, "all", "a", false, "Umount all of the currently mounted containers")
flags.BoolVarP(&umountCommand.Force, "force", "f", false, "Force the complete umount all of the currently mounted containers")
flags.BoolVarP(&umountCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
-
- rootCmd.AddCommand(umountCommand.Command)
}
func umountCmd(c *cliconfig.UmountValues) error {
diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go
index fb3a7b57a..c8f85cfd3 100644
--- a/cmd/podman/unpause.go
+++ b/cmd/podman/unpause.go
@@ -35,10 +35,9 @@ var (
func init() {
unpauseCommand.Command = _unpauseCommand
+ unpauseCommand.SetUsageTemplate(UsageTemplate())
flags := unpauseCommand.Flags()
flags.BoolVarP(&unpauseCommand.All, "all", "a", false, "Unpause all paused containers")
-
- rootCmd.AddCommand(unpauseCommand.Command)
}
func unpauseCmd(c *cliconfig.UnpauseValues) error {
diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go
index 2b76e034e..ce54cfa85 100644
--- a/cmd/podman/varlink.go
+++ b/cmd/podman/varlink.go
@@ -1,4 +1,4 @@
-// +build varlink
+// +build varlink,!remoteclient
package main
@@ -38,10 +38,9 @@ var (
func init() {
varlinkCommand.Command = _varlinkCommand
+ varlinkCommand.SetUsageTemplate(UsageTemplate())
flags := varlinkCommand.Flags()
flags.Int64VarP(&varlinkCommand.Timeout, "timeout", "t", 1000, "Time until the varlink session expires in milliseconds. Use 0 to disable the timeout")
-
- rootCmd.AddCommand(varlinkCommand.Command)
}
func varlinkCmd(c *cliconfig.VarlinkValues) error {
@@ -84,7 +83,7 @@ func varlinkCmd(c *cliconfig.VarlinkValues) error {
logrus.Infof("varlink service expired (use --timeout to increase session time beyond %d ms, 0 means never timeout)", c.Int64("timeout"))
return nil
default:
- return errors.Errorf("unable to start varlink service")
+ return errors.Wrapf(err, "unable to start varlink service")
}
}
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 101232b0c..3b7a11fc3 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -2,15 +2,13 @@
# in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in the upstream libpod repository.
interface io.podman
-
-# Version is the structure returned by GetVersion
-type Version (
- version: string,
- go_version: string,
- git_commit: string,
- built: int,
- os_arch: string,
- remote_api_version: int
+type Volume (
+ name: string,
+ labels: [string]string,
+ mountPoint: string,
+ driver: string,
+ options: [string]string,
+ scope: string
)
type NotImplemented (
@@ -20,6 +18,7 @@ type NotImplemented (
type StringResponse (
message: string
)
+
# ContainerChanges describes the return struct for ListContainerChanges
type ContainerChanges (
changed: []string,
@@ -27,14 +26,25 @@ type ContainerChanges (
deleted: []string
)
-# ImageInList describes the structure that is returned in
-# ListImages.
-type ImageInList (
+type VolumeCreateOpts (
+ volumeName: string,
+ driver: string,
+ labels: [string]string,
+ options: [string]string
+)
+
+type VolumeRemoveOpts (
+ volumes: []string,
+ all: bool,
+ force: bool
+)
+
+type Image (
id: string,
parentId: string,
repoTags: []string,
repoDigests: []string,
- created: string,
+ created: string, # as RFC3339
size: int,
virtualSize: int,
containers: int,
@@ -45,16 +55,15 @@ type ImageInList (
# ImageHistory describes the returned structure from ImageHistory.
type ImageHistory (
id: string,
- created: string,
+ created: string, # as RFC3339
createdBy: string,
tags: []string,
size: int,
comment: string
)
-# ImageSearch is the returned structure for SearchImage. It is returned
-# in array form.
-type ImageSearch (
+# Represents a single search result from SearchImages
+type ImageSearchResult (
description: string,
is_official: bool,
is_automated: bool,
@@ -62,13 +71,12 @@ type ImageSearch (
star_count: int
)
-# ListContainerData is the returned struct for an individual container
-type ListContainerData (
+type Container (
id: string,
image: string,
imageid: string,
command: []string,
- createdat: string,
+ createdat: string, # as RFC3339
runningfor: string,
status: string,
ports: []ContainerPortMappings,
@@ -303,37 +311,54 @@ type IDMap (
size: int
)
+# BuildOptions are are used to describe describe physical attributes of the build
+type BuildOptions (
+ addHosts: []string,
+ cgroupParent: string,
+ cpuPeriod: int,
+ cpuQuota: int,
+ cpuShares: int,
+ cpusetCpus: string,
+ cpusetMems: string,
+ memory: int,
+ memorySwap: int,
+ shmSize: string,
+ ulimit: []string,
+ volume: []string
+)
+
# BuildInfo is used to describe user input for building images
type BuildInfo (
- # paths to one or more dockerfiles
- dockerfile: []string,
- tags: []string,
- add_hosts: []string,
- cgroup_parent: string,
- cpu_period: int,
- cpu_quota: int,
- cpu_shares: int,
- cpuset_cpus: string,
- cpuset_mems: string,
- memory: string,
- memory_swap: string,
- security_opts: []string,
- shm_size: string,
- ulimit: []string,
- volume: []string,
- squash: bool,
- pull: bool,
- pull_always: bool,
- force_rm: bool,
- rm: bool,
- label: []string,
+ additionalTags: []string,
annotations: []string,
- build_args: [string]string,
- image_format: string
+ buildArgs: [string]string,
+ buildOptions: BuildOptions,
+ cniConfigDir: string,
+ cniPluginDir: string,
+ compression: string,
+ contextDir: string,
+ defaultsMountFilePath: string,
+ dockerfiles: []string,
+ err: string,
+ forceRmIntermediateCtrs: bool,
+ iidfile: string,
+ label: []string,
+ layers: bool,
+ nocache: bool,
+ out: string,
+ output: string,
+ outputFormat: string,
+ pullPolicy: string,
+ quiet: bool,
+ remoteIntermediateCtrs: bool,
+ reportWriter: string,
+ runtimeArgs: []string,
+ signaturePolicyPath: string,
+ squash: bool
)
-# BuildResponse is used to describe the responses for building images
-type BuildResponse (
+# MoreResponse is a struct for when responses from varlink requires longer output
+type MoreResponse (
logs: []string,
id: string
)
@@ -393,34 +418,29 @@ type Runlabel(
opts: [string]string
)
-# Ping provides a response for developers to ensure their varlink setup is working.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.Ping
-# {
-# "ping": {
-# "message": "OK"
-# }
-# }
-# ~~~
-method Ping() -> (ping: StringResponse)
-
-# GetVersion returns a Version structure describing the libpod setup on their
-# system.
-method GetVersion() -> (version: Version)
+# GetVersion returns version and build information of the podman service
+method GetVersion() -> (
+ version: string,
+ go_version: string,
+ git_commit: string,
+ built: string, # as RFC3339
+ os_arch: string,
+ remote_api_version: int
+)
# GetInfo returns a [PodmanInfo](#PodmanInfo) struct that describes podman and its host such as storage stats,
# build information of Podman, and system-wide registries.
method GetInfo() -> (info: PodmanInfo)
-# ListContainers returns a list of containers in no particular order. There are
-# returned as an array of ListContainerData structs. See also [GetContainer](#GetContainer).
-method ListContainers() -> (containers: []ListContainerData)
+# ListContainers returns information about all containers.
+# See also [GetContainer](#GetContainer).
+method ListContainers() -> (containers: []Container)
-# GetContainer takes a name or ID of a container and returns single ListContainerData
-# structure. A [ContainerNotFound](#ContainerNotFound) error will be returned if the container cannot be found.
-# See also [ListContainers](ListContainers) and [InspectContainer](#InspectContainer).
-method GetContainer(name: string) -> (container: ListContainerData)
+# GetContainer returns information about a single container. If a container
+# with the given id doesn't exist, a [ContainerNotFound](#ContainerNotFound)
+# error will be returned. See also [ListContainers](ListContainers) and
+# [InspectContainer](#InspectContainer).
+method GetContainer(id: string) -> (container: Container)
# CreateContainer creates a new container from an image. It uses a [Create](#Create) type for input. The minimum
# input required for CreateContainer is an image name. If the image name is not found, an [ImageNotFound](#ImageNotFound)
@@ -508,7 +528,7 @@ method ExportContainer(name: string, path: string) -> (tarfile: string)
method GetContainerStats(name: string) -> (container: ContainerStats)
# This method has not be implemented yet.
-method ResizeContainerTty() -> (notimplemented: NotImplemented)
+# method ResizeContainerTty() -> (notimplemented: NotImplemented)
# StartContainer starts a created or stopped container. It takes the name or ID of container. It returns
# the container ID once started. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound)
@@ -540,10 +560,10 @@ method RestartContainer(name: string, timeout: int) -> (container: string)
method KillContainer(name: string, signal: int) -> (container: string)
# This method has not be implemented yet.
-method UpdateContainer() -> (notimplemented: NotImplemented)
+# method UpdateContainer() -> (notimplemented: NotImplemented)
# This method has not be implemented yet.
-method RenameContainer() -> (notimplemented: NotImplemented)
+# method RenameContainer() -> (notimplemented: NotImplemented)
# PauseContainer takes the name or ID of container and pauses it. If the container cannot be found,
# a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise the ID of the container is returned.
@@ -556,7 +576,7 @@ method PauseContainer(name: string) -> (container: string)
method UnpauseContainer(name: string) -> (container: string)
# This method has not be implemented yet.
-method AttachToContainer() -> (notimplemented: NotImplemented)
+# method AttachToContainer() -> (notimplemented: NotImplemented)
# GetAttachSockets takes the name or ID of an existing container. It returns file paths for two sockets needed
# to properly communicate with a container. The first is the actual I/O socket that the container uses. The
@@ -580,7 +600,7 @@ method GetAttachSockets(name: string) -> (sockets: Sockets)
# a [ContainerNotFound](#ContainerNotFound) error is returned.
method WaitContainer(name: string) -> (exitcode: int)
-# RemoveContainer takes requires the name or ID of container as well a boolean representing whether a running
+# RemoveContainer takes requires the name or ID of container as well a boolean representing whether a running and a boolean indicating whether to remove builtin volumes
# container can be stopped and removed. Upon successful removal of the container, its ID is returned. If the
# container cannot be found by name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned.
# #### Example
@@ -590,7 +610,7 @@ method WaitContainer(name: string) -> (exitcode: int)
# "container": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20"
# }
# ~~~
-method RemoveContainer(name: string, force: bool) -> (container: string)
+method RemoveContainer(name: string, force: bool, removeVolumes: bool) -> (container: string)
# DeleteStoppedContainers will delete all containers that are not running. It will return a list the deleted
# container IDs. See also [RemoveContainer](RemoveContainer).
@@ -608,21 +628,21 @@ method RemoveContainer(name: string, force: bool) -> (container: string)
# ~~~
method DeleteStoppedContainers() -> (containers: []string)
-# ListImages returns an array of ImageInList structures which provide basic information about
-# an image currently in storage. See also [InspectImage](InspectImage).
-method ListImages() -> (images: []ImageInList)
+# ListImages returns information about the images that are currently in storage.
+# See also [InspectImage](InspectImage).
+method ListImages() -> (images: []Image)
-# GetImage returns a single image in an [ImageInList](#ImageInList) struct. You must supply an image name as a string.
-# If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be returned.
-method GetImage(name: string) -> (image: ImageInList)
+# GetImage returns information about a single image in storage.
+# If the image caGetImage returns be found, [ImageNotFound](#ImageNotFound) will be returned.
+method GetImage(id: string) -> (image: Image)
# BuildImage takes a [BuildInfo](#BuildInfo) structure and builds an image. At a minimum, you must provide the
-# 'dockerfile' and 'tags' options in the BuildInfo structure. It will return a [BuildResponse](#BuildResponse) structure
+# 'dockerfile' and 'tags' options in the BuildInfo structure. It will return a [MoreResponse](#MoreResponse) structure
# that contains the build logs and resulting image ID.
-method BuildImage(build: BuildInfo) -> (image: BuildResponse)
+method BuildImage(build: BuildInfo) -> (image: MoreResponse)
# This function is not implemented yet.
-method CreateImage() -> (notimplemented: NotImplemented)
+# method CreateImage() -> (notimplemented: NotImplemented)
# InspectImage takes the name or ID of an image and returns a string respresentation of data associated with the
#image. You must serialize the string into JSON to use it further. An [ImageNotFound](#ImageNotFound) error will
@@ -637,8 +657,8 @@ method HistoryImage(name: string) -> (history: []ImageHistory)
# PushImage takes three input arguments: the name or ID of an image, the fully-qualified destination name of the image,
# and a boolean as to whether tls-verify should be used (with false disabling TLS, not affecting the default behavior).
# It will return an [ImageNotFound](#ImageNotFound) error if
-# the image cannot be found in local storage; otherwise the ID of the image will be returned on success.
-method PushImage(name: string, tag: string, tlsverify: bool, signaturePolicy: string, creds: string, certDir: string, compress: bool, format: string, removeSignatures: bool, signBy: string) -> (image: string)
+# the image cannot be found in local storage; otherwise it will return a [MoreResponse](#MoreResponse)
+method PushImage(name: string, tag: string, tlsverify: bool, signaturePolicy: string, creds: string, certDir: string, compress: bool, format: string, removeSignatures: bool, signBy: string) -> (reply: MoreResponse)
# TagImage takes the name or ID of an image in local storage as well as the desired tag name. If the image cannot
# be found, an [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of the image is returned on success.
@@ -656,10 +676,10 @@ method TagImage(name: string, tagged: string) -> (image: string)
# ~~~
method RemoveImage(name: string, force: bool) -> (image: string)
-# SearchImage takes the string of an image name and a limit of searches from each registries to be returned. SearchImage
-# will then use a glob-like match to find the image you are searching for. The images are returned in an array of
-# ImageSearch structures which contain information about the image as well as its fully-qualified name.
-method SearchImage(name: string, limit: int) -> (images: []ImageSearch)
+# SearchImages searches available registries for images that contain the
+# contents of "query" in their name. If "limit" is given, limits the amount of
+# search results per registry.
+method SearchImages(query: string, limit: ?int) -> (results: []ImageSearchResult)
# DeleteUnusedImages deletes any images not associated with a container. The IDs of the deleted images are returned
# in a string array.
@@ -913,10 +933,10 @@ method UnpausePod(name: string) -> (pod: string)
method RemovePod(name: string, force: bool) -> (pod: string)
# This method has not be implemented yet.
-method WaitPod() -> (notimplemented: NotImplemented)
+# method WaitPod() -> (notimplemented: NotImplemented)
# This method has not been implemented yet.
-method TopPod() -> (notimplemented: NotImplemented)
+# method TopPod() -> (notimplemented: NotImplemented)
# GetPodStats takes the name or ID of a pod and returns a pod name and slice of ContainerStats structure which
# contains attributes like memory and cpu usage. If the pod cannot be found, a [PodNotFound](#PodNotFound)
@@ -1020,19 +1040,19 @@ method UnmountContainer(name: string, force: bool) -> ()
method ImagesPrune(all: bool) -> (pruned: []string)
# This function is not implemented yet.
-method ListContainerPorts(name: string) -> (notimplemented: NotImplemented)
+# method ListContainerPorts(name: string) -> (notimplemented: NotImplemented)
# GenerateKube generates a Kubernetes v1 Pod description of a Podman container or pod
# and its containers. The description is in YAML. See also [ReplayKube](ReplayKube).
-method GenerateKube() -> (notimplemented: NotImplemented)
+# method GenerateKube() -> (notimplemented: NotImplemented)
# GenerateKubeService generates a Kubernetes v1 Service description of a Podman container or pod
# and its containers. The description is in YAML. See also [GenerateKube](GenerateKube).
-method GenerateKubeService() -> (notimplemented: NotImplemented)
+# method GenerateKubeService() -> (notimplemented: NotImplemented)
# ReplayKube recreates a pod and its containers based on a Kubernetes v1 Pod description (in YAML)
# like that created by GenerateKube. See also [GenerateKube](GenerateKube).
-method ReplayKube() -> (notimplemented: NotImplemented)
+# method ReplayKube() -> (notimplemented: NotImplemented)
# ContainerConfig returns a container's config in string form. This call is for
# development of Podman only and generally should not be used.
@@ -1053,11 +1073,17 @@ method ContainerStateData(name: string) -> (config: string)
method SendFile(type: string, length: int) -> (file_handle: string)
method ReceiveFile(path: string, delete: bool) -> (len: int)
+method VolumeCreate(options: VolumeCreateOpts) -> (volumeName: string)
+
+method VolumeRemove(options: VolumeRemoveOpts) -> (volumeNames: []string)
+
+method GetVolumes(args: []string, all: bool) -> (volumes: []Volume)
+
# ImageNotFound means the image could not be found by the provided name or ID in local storage.
-error ImageNotFound (name: string)
+error ImageNotFound (id: string)
# ContainerNotFound means the container could not be found by the provided name or ID in local storage.
-error ContainerNotFound (name: string)
+error ContainerNotFound (id: string)
# NoContainerRunning means none of the containers requested are running in a command that requires a running container.
error NoContainerRunning ()
diff --git a/cmd/podman/varlink_dummy.go b/cmd/podman/varlink_dummy.go
index 8d7a7e8ca..430511d72 100644
--- a/cmd/podman/varlink_dummy.go
+++ b/cmd/podman/varlink_dummy.go
@@ -2,8 +2,10 @@
package main
-import (
- "github.com/containers/libpod/cmd/podman/cliconfig"
-)
+import "github.com/spf13/cobra"
-var varlinkCommand *cliconfig.PodmanCommand
+var (
+ _varlinkCommand = &cobra.Command{
+ Use: "",
+ }
+)
diff --git a/cmd/podman/version.go b/cmd/podman/version.go
index 0e7cd43d5..c65ba94f9 100644
--- a/cmd/podman/version.go
+++ b/cmd/podman/version.go
@@ -28,9 +28,9 @@ var (
func init() {
versionCommand.Command = _versionCommand
+ versionCommand.SetUsageTemplate(UsageTemplate())
flags := versionCommand.Flags()
flags.StringVarP(&versionCommand.Format, "format", "f", "", "Change the output format to JSON or a Go template")
- rootCmd.AddCommand(versionCommand.Command)
}
// versionCmd gets and prints version info for version command
diff --git a/cmd/podman/volume.go b/cmd/podman/volume.go
index bae778e52..36798a19e 100644
--- a/cmd/podman/volume.go
+++ b/cmd/podman/volume.go
@@ -19,5 +19,5 @@ var volumeCommand = cliconfig.PodmanCommand{
func init() {
volumeCommand.AddCommand(getVolumeSubCommands()...)
- rootCmd.AddCommand(volumeCommand.Command)
+ volumeCommand.SetUsageTemplate(UsageTemplate())
}
diff --git a/cmd/podman/volume_create.go b/cmd/podman/volume_create.go
index e0ff4c341..fe5d69e0b 100644
--- a/cmd/podman/volume_create.go
+++ b/cmd/podman/volume_create.go
@@ -4,8 +4,7 @@ import (
"fmt"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -33,6 +32,7 @@ be created at.`
func init() {
volumeCreateCommand.Command = _volumeCreateCommand
+ volumeCreateCommand.SetUsageTemplate(UsageTemplate())
flags := volumeCreateCommand.Flags()
flags.StringVar(&volumeCreateCommand.Driver, "driver", "", "Specify volume driver name (default local)")
flags.StringSliceVarP(&volumeCreateCommand.Label, "label", "l", []string{}, "Set metadata for a volume (default [])")
@@ -41,13 +41,7 @@ func init() {
}
func volumeCreateCmd(c *cliconfig.VolumeCreateValues) error {
- var (
- options []libpod.VolumeCreateOption
- err error
- volName string
- )
-
- runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
@@ -57,36 +51,19 @@ func volumeCreateCmd(c *cliconfig.VolumeCreateValues) error {
return errors.Errorf("too many arguments, create takes at most 1 argument")
}
- if len(c.InputArgs) > 0 {
- volName = c.InputArgs[0]
- options = append(options, libpod.WithVolumeName(volName))
- }
-
- if c.Flag("driver").Changed {
- options = append(options, libpod.WithVolumeDriver(c.String("driver")))
- }
-
labels, err := getAllLabels([]string{}, c.Label)
if err != nil {
return errors.Wrapf(err, "unable to process labels")
}
- if len(labels) != 0 {
- options = append(options, libpod.WithVolumeLabels(labels))
- }
opts, err := getAllLabels([]string{}, c.Opt)
if err != nil {
return errors.Wrapf(err, "unable to process options")
}
- if len(options) != 0 {
- options = append(options, libpod.WithVolumeOptions(opts))
- }
- vol, err := runtime.NewVolume(getContext(), options...)
- if err != nil {
- return err
+ volumeName, err := runtime.CreateVolume(getContext(), c, labels, opts)
+ if err == nil {
+ fmt.Println(volumeName)
}
- fmt.Printf("%s\n", vol.Name())
-
- return nil
+ return err
}
diff --git a/cmd/podman/volume_inspect.go b/cmd/podman/volume_inspect.go
index 7cb5703da..928ef37d0 100644
--- a/cmd/podman/volume_inspect.go
+++ b/cmd/podman/volume_inspect.go
@@ -2,9 +2,8 @@ package main
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -31,6 +30,7 @@ from JSON to a Go template.
func init() {
volumeInspectCommand.Command = _volumeInspectCommand
+ volumeInspectCommand.SetUsageTemplate(UsageTemplate())
flags := volumeInspectCommand.Flags()
flags.BoolVarP(&volumeInspectCommand.All, "all", "a", false, "Inspect all volumes")
flags.StringVarP(&volumeInspectCommand.Format, "format", "f", "json", "Format volume output using Go template")
@@ -38,22 +38,19 @@ func init() {
}
func volumeInspectCmd(c *cliconfig.VolumeInspectValues) error {
- var err error
+ if (c.All && len(c.InputArgs) > 0) || (!c.All && len(c.InputArgs) < 1) {
+ return errors.New("provide one or more volume names or use --all")
+ }
- runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
defer runtime.Shutdown(false)
- opts := volumeLsOptions{
- Format: c.Format,
- }
-
- vols, lastError := getVolumesFromContext(&c.PodmanCommand, runtime)
- if lastError != nil {
- logrus.Errorf("%q", lastError)
+ vols, err := runtime.InspectVolumes(getContext(), c)
+ if err != nil {
+ return err
}
-
- return generateVolLsOutput(vols, opts, runtime)
+ return generateVolLsOutput(vols, volumeLsOptions{Format: c.Format})
}
diff --git a/cmd/podman/volume_ls.go b/cmd/podman/volume_ls.go
index 78fdfed64..0edadc5ac 100644
--- a/cmd/podman/volume_ls.go
+++ b/cmd/podman/volume_ls.go
@@ -6,8 +6,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/formats"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -62,6 +61,7 @@ and the output format can be changed to JSON or a user specified Go template.
func init() {
volumeLsCommand.Command = _volumeLsCommand
+ volumeLsCommand.SetUsageTemplate(UsageTemplate())
flags := volumeLsCommand.Flags()
flags.StringVarP(&volumeLsCommand.Filter, "filter", "f", "", "Filter volume output")
@@ -70,7 +70,7 @@ func init() {
}
func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
- runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
@@ -86,7 +86,7 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
opts.Format = genVolLsFormat(c)
// Get the filter functions based on any filters set
- var filterFuncs []libpod.VolumeFilter
+ var filterFuncs []adapter.VolumeFilter
if c.Filter != "" {
filters := strings.Split(c.Filter, ",")
for _, f := range filters {
@@ -94,7 +94,7 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
if len(filterSplit) < 2 {
return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
}
- generatedFunc, err := generateVolumeFilterFuncs(filterSplit[0], filterSplit[1], runtime)
+ generatedFunc, err := generateVolumeFilterFuncs(filterSplit[0], filterSplit[1])
if err != nil {
return errors.Wrapf(err, "invalid filter")
}
@@ -102,13 +102,12 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
}
}
- volumes, err := runtime.GetAllVolumes()
+ volumes, err := runtime.Volumes(getContext())
if err != nil {
return err
}
-
// Get the volumes that match the filter
- volsFiltered := make([]*libpod.Volume, 0, len(volumes))
+ volsFiltered := make([]*adapter.Volume, 0, len(volumes))
for _, vol := range volumes {
include := true
for _, filter := range filterFuncs {
@@ -119,7 +118,7 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
volsFiltered = append(volsFiltered, vol)
}
}
- return generateVolLsOutput(volsFiltered, opts, runtime)
+ return generateVolLsOutput(volsFiltered, opts)
}
// generate the template based on conditions given
@@ -205,7 +204,7 @@ func getVolTemplateOutput(lsParams []volumeLsJSONParams, opts volumeLsOptions) (
}
// getVolJSONParams returns the volumes in JSON format
-func getVolJSONParams(volumes []*libpod.Volume, opts volumeLsOptions, runtime *libpod.Runtime) ([]volumeLsJSONParams, error) {
+func getVolJSONParams(volumes []*adapter.Volume) []volumeLsJSONParams {
var lsOutput []volumeLsJSONParams
for _, volume := range volumes {
@@ -220,25 +219,19 @@ func getVolJSONParams(volumes []*libpod.Volume, opts volumeLsOptions, runtime *l
lsOutput = append(lsOutput, params)
}
- return lsOutput, nil
+ return lsOutput
}
// generateVolLsOutput generates the output based on the format, JSON or Go Template, and prints it out
-func generateVolLsOutput(volumes []*libpod.Volume, opts volumeLsOptions, runtime *libpod.Runtime) error {
+func generateVolLsOutput(volumes []*adapter.Volume, opts volumeLsOptions) error {
if len(volumes) == 0 && opts.Format != formats.JSONString {
return nil
}
- lsOutput, err := getVolJSONParams(volumes, opts, runtime)
- if err != nil {
- return err
- }
+ lsOutput := getVolJSONParams(volumes)
var out formats.Writer
switch opts.Format {
case formats.JSONString:
- if err != nil {
- return errors.Wrapf(err, "unable to create JSON for volume output")
- }
out = formats.JSONStructArray{Output: volLsToGeneric([]volumeLsTemplateParams{}, lsOutput)}
default:
lsOutput, err := getVolTemplateOutput(lsOutput, opts)
@@ -251,18 +244,18 @@ func generateVolLsOutput(volumes []*libpod.Volume, opts volumeLsOptions, runtime
}
// generateVolumeFilterFuncs returns the true if the volume matches the filter set, otherwise it returns false.
-func generateVolumeFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) (func(volume *libpod.Volume) bool, error) {
+func generateVolumeFilterFuncs(filter, filterValue string) (func(volume *adapter.Volume) bool, error) {
switch filter {
case "name":
- return func(v *libpod.Volume) bool {
+ return func(v *adapter.Volume) bool {
return strings.Contains(v.Name(), filterValue)
}, nil
case "driver":
- return func(v *libpod.Volume) bool {
+ return func(v *adapter.Volume) bool {
return v.Driver() == filterValue
}, nil
case "scope":
- return func(v *libpod.Volume) bool {
+ return func(v *adapter.Volume) bool {
return v.Scope() == filterValue
}, nil
case "label":
@@ -273,7 +266,7 @@ func generateVolumeFilterFuncs(filter, filterValue string, runtime *libpod.Runti
} else {
filterValue = ""
}
- return func(v *libpod.Volume) bool {
+ return func(v *adapter.Volume) bool {
for labelKey, labelValue := range v.Labels() {
if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
return true
@@ -289,7 +282,7 @@ func generateVolumeFilterFuncs(filter, filterValue string, runtime *libpod.Runti
} else {
filterValue = ""
}
- return func(v *libpod.Volume) bool {
+ return func(v *adapter.Volume) bool {
for labelKey, labelValue := range v.Options() {
if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
return true
diff --git a/cmd/podman/volume_prune.go b/cmd/podman/volume_prune.go
index 29dc6ead4..74228fa5b 100644
--- a/cmd/podman/volume_prune.go
+++ b/cmd/podman/volume_prune.go
@@ -37,6 +37,7 @@ using force.
func init() {
volumePruneCommand.Command = _volumePruneCommand
+ volumePruneCommand.SetUsageTemplate(UsageTemplate())
flags := volumePruneCommand.Flags()
flags.BoolVarP(&volumePruneCommand.Force, "force", "f", false, "Do not prompt for confirmation")
diff --git a/cmd/podman/volume_rm.go b/cmd/podman/volume_rm.go
index b02a06ed9..f301749e9 100644
--- a/cmd/podman/volume_rm.go
+++ b/cmd/podman/volume_rm.go
@@ -4,9 +4,8 @@ import (
"fmt"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -35,6 +34,7 @@ not being used by any containers. To remove the volumes anyways, use the
func init() {
volumeRmCommand.Command = _volumeRmCommand
+ volumeRmCommand.SetUsageTemplate(UsageTemplate())
flags := volumeRmCommand.Flags()
flags.BoolVarP(&volumeRmCommand.All, "all", "a", false, "Remove all volumes")
flags.BoolVarP(&volumeRmCommand.Force, "force", "f", false, "Remove a volume by force, even if it is being used by a container")
@@ -43,25 +43,28 @@ func init() {
func volumeRmCmd(c *cliconfig.VolumeRmValues) error {
var err error
- runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+ if (len(c.InputArgs) > 0 && c.All) || (len(c.InputArgs) < 1 && !c.All) {
+ return errors.New("choose either one or more volumes or all")
+ }
+
+ runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
defer runtime.Shutdown(false)
-
- ctx := getContext()
-
- vols, lastError := getVolumesFromContext(&c.PodmanCommand, runtime)
- for _, vol := range vols {
- err = runtime.RemoveVolume(ctx, vol, c.Force, false)
- if err != nil {
- if lastError != nil {
- logrus.Errorf("%q", lastError)
- }
- lastError = errors.Wrapf(err, "failed to remove volume %q", vol.Name())
- } else {
- fmt.Println(vol.Name())
+ deletedVolumeNames, err := runtime.RemoveVolumes(getContext(), c)
+ if err != nil {
+ if len(deletedVolumeNames) > 0 {
+ printDeleteVolumes(deletedVolumeNames)
+ return err
}
}
- return lastError
+ printDeleteVolumes(deletedVolumeNames)
+ return err
+}
+
+func printDeleteVolumes(volumes []string) {
+ for _, v := range volumes {
+ fmt.Println(v)
+ }
}
diff --git a/cmd/podman/wait.go b/cmd/podman/wait.go
index fa195b7ce..616c8feb5 100644
--- a/cmd/podman/wait.go
+++ b/cmd/podman/wait.go
@@ -34,11 +34,10 @@ var (
func init() {
waitCommand.Command = _waitCommand
+ waitCommand.SetUsageTemplate(UsageTemplate())
flags := waitCommand.Flags()
flags.UintVarP(&waitCommand.Interval, "interval", "i", 250, "Milliseconds to wait before polling for completion")
flags.BoolVarP(&waitCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
-
- rootCmd.AddCommand(waitCommand.Command)
}
func waitCmd(c *cliconfig.WaitValues) error {
diff --git a/commands.md b/commands.md
index 41318ccbb..3fd27ad5d 100644
--- a/commands.md
+++ b/commands.md
@@ -73,6 +73,7 @@
| [podman-unpause(1)](/docs/podman-unpause.1.md) | Unpause one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/141292)|
| [podman-varlink(1)](/docs/podman-varlink.1.md) | Run the varlink backend ||
| [podman-version(1)](/docs/podman-version.1.md) | Display the version information |[![...](/docs/play.png)](https://asciinema.org/a/mfrn61pjZT9Fc8L4NbfdSqfgu)|
+| [podman-volume(1)](/docs/podman-volume.1.md) | Manage Volumes ||
| [podman-volume-create(1)](/docs/podman-volume-create.1.md) | Create a volume ||
| [podman-volume-inspect(1)](/docs/podman-volume-inspect.1.md) | Get detailed information on one or more volumes ||
| [podman-volume-ls(1)](/docs/podman-volume-ls.1.md) | List all the available volumes ||
diff --git a/completions/bash/podman b/completions/bash/podman
index 9df87aef4..d367b8237 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -1691,6 +1691,7 @@ _podman_container_run() {
--oom-score-adj
--pid
--pids-limit
+ --pod
--publish -p
--runtime
--rootfs
diff --git a/contrib/perftest/main.go b/contrib/perftest/main.go
index 6a6725ab9..c0a91209f 100644
--- a/contrib/perftest/main.go
+++ b/contrib/perftest/main.go
@@ -218,7 +218,7 @@ func runSingleThreadedStressTest(ctx context.Context, client *libpod.Runtime, im
//Delete Container
deleteStartTime := time.Now()
- err = client.RemoveContainer(ctx, ctr, true)
+ err = client.RemoveContainer(ctx, ctr, true, false)
if err != nil {
return nil, err
}
diff --git a/docs/podman-rm.1.md b/docs/podman-rm.1.md
index 4fcb0b6c5..f4513c2be 100644
--- a/docs/podman-rm.1.md
+++ b/docs/podman-rm.1.md
@@ -17,7 +17,9 @@ Remove all containers. Can be used in conjunction with -f as well.
**--force, f**
-Force the removal of a running and paused containers
+Force the removal of running and paused containers. Forcing a containers removal also
+removes containers from container storage even if the container is not known to podman.
+Containers could have been created by a different container engine.
**--latest, -l**
diff --git a/docs/podman.1.md b/docs/podman.1.md
index 51ef00383..760f27310 100644
--- a/docs/podman.1.md
+++ b/docs/podman.1.md
@@ -168,6 +168,7 @@ the exit codes follow the `chroot` standard, see below:
| [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem. |
| [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. |
| [podman-version(1)](podman-version.1.md) | Display the Podman version information. |
+| [podman-volume(1)](podman-volume.1.md) | Manage Volumes. |
| [podman-wait(1)](podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes. |
## FILES
diff --git a/hack/get_ci_vm.sh b/hack/get_ci_vm.sh
index b058b4273..3c2d193af 100755
--- a/hack/get_ci_vm.sh
+++ b/hack/get_ci_vm.sh
@@ -17,8 +17,14 @@ MEMORY="4Gb"
DISK="200"
PROJECT="libpod-218412"
GOSRC="/var/tmp/go/src/github.com/containers/libpod"
+GCLOUD_IMAGE=${GCLOUD_IMAGE:-quay.io/cevich/gcloud_centos:latest}
+GCLOUD_SUDO=${GCLOUD_SUDO-sudo}
+
+# Shared tmp directory between container and us
+TMPDIR=$(mktemp -d --tmpdir $(basename $0)_tmpdir_XXXXXX)
+
# Command shortcuts save some typing
-PGCLOUD="sudo podman run -it --rm -e AS_ID=$UID -e AS_USER=$USER --security-opt label=disable -v /home/$USER:$HOME -v /tmp:/tmp:ro quay.io/cevich/gcloud_centos:latest --configuration=libpod --project=$PROJECT"
+PGCLOUD="$GCLOUD_SUDO podman run -it --rm -e AS_ID=$UID -e AS_USER=$USER --security-opt label=disable -v /home/$USER:$HOME -v $TMPDIR:/tmp $GCLOUD_IMAGE --configuration=libpod --project=$PROJECT"
SCP_CMD="$PGCLOUD compute scp"
LIBPODROOT=$(realpath "$(dirname $0)/../")
@@ -39,19 +45,20 @@ showrun() {
fi
}
-TEMPFILE=$(mktemp -p '' $(basename $0)_XXXXX.tar.bz2)
cleanup() {
set +e
wait
- rm -f "$TEMPFILE"
+
+ # set GCLOUD_DEBUG to leave tmpdir behind for postmortem
+ test -z "$GCLOUD_DEBUG" && rm -rf $TMPDIR
}
trap cleanup EXIT
delvm() {
- cleanup
echo -e "\n"
echo -e "\n${YEL}Offering to Delete $VMNAME ${RED}(Might take a minute or two)${NOR}"
showrun $CLEANUP_CMD # prompts for Yes/No
+ cleanup
}
image_hints() {
@@ -128,16 +135,16 @@ parse_args $@
cd $LIBPODROOT
# Attempt to determine if named 'libpod' gcloud configuration exists
-showrun $PGCLOUD info > $TEMPFILE
-if egrep -q "Account:.*None" "$TEMPFILE"
+showrun $PGCLOUD info > $TMPDIR/gcloud-info
+if egrep -q "Account:.*None" $TMPDIR/gcloud-info
then
echo -e "\n${YEL}WARNING: Can't find gcloud configuration for libpod, running init.${NOR}"
echo -e " ${RED}Please choose "#1: Re-initialize" and "login" if asked.${NOR}"
showrun $PGCLOUD init --project=$PROJECT --console-only --skip-diagnostics
# Verify it worked (account name == someone@example.com)
- $PGCLOUD info > $TEMPFILE
- if egrep -q "Account:.*None" "$TEMPFILE"
+ $PGCLOUD info > $TMPDIR/gcloud-info-after-init
+ if egrep -q "Account:.*None" $TMPDIR/gcloud-info-after-init
then
echo -e "${RED}ERROR: Could not initialize libpod configuration in gcloud.${NOR}"
exit 5
@@ -150,8 +157,10 @@ then
fi
# Couldn't make rsync work with gcloud's ssh wrapper :(
+TARBALL_BASENAME=$VMNAME.tar.bz2
+TARBALL=/tmp/$TARBALL_BASENAME
echo -e "\n${YEL}Packing up repository into a tarball $VMNAME.${NOR}"
-showrun --background tar cjf $TEMPFILE --warning=no-file-changed -C $LIBPODROOT .
+showrun --background tar cjf $TMPDIR/$TARBALL_BASENAME --warning=no-file-changed -C $LIBPODROOT .
trap delvm INT # Allow deleting VM if CTRL-C during create
# This fails if VM already exists: permit this usage to re-init
@@ -186,13 +195,13 @@ showrun $SSH_CMD --command "mkdir -p $GOSRC"
echo -e "\n${YEL}Transfering tarball to $VMNAME.${NOR}"
wait
-showrun $SCP_CMD $TEMPFILE root@$VMNAME:$TEMPFILE
+showrun $SCP_CMD $TARBALL root@$VMNAME:$TARBALL
echo -e "\n${YEL}Unpacking tarball into $GOSRC on $VMNAME.${NOR}"
-showrun $SSH_CMD --command "tar xjf $TEMPFILE -C $GOSRC"
+showrun $SSH_CMD --command "tar xjf $TARBALL -C $GOSRC"
echo -e "\n${YEL}Removing tarball on $VMNAME.${NOR}"
-showrun $SSH_CMD --command "rm -f $TEMPFILE"
+showrun $SSH_CMD --command "rm -f $TARBALL"
echo -e "\n${YEL}Executing environment setup${NOR}"
[[ "$1" == "-p" ]] && echo -e "${RED}Using package-based dependencies.${NOR}"
diff --git a/libpod/adapter/runtime.go b/libpod/adapter/runtime.go
index 46771b5b6..3146cf5db 100644
--- a/libpod/adapter/runtime.go
+++ b/libpod/adapter/runtime.go
@@ -4,18 +4,22 @@ package adapter
import (
"context"
- "github.com/pkg/errors"
"io"
"io/ioutil"
"os"
"strconv"
+ "github.com/containers/buildah"
+ "github.com/containers/buildah/imagebuildah"
+ "github.com/containers/buildah/pkg/parse"
+ "github.com/containers/image/docker/reference"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/rootless"
+ "github.com/pkg/errors"
)
// LocalRuntime describes a typical libpod runtime
@@ -34,6 +38,14 @@ type Container struct {
*libpod.Container
}
+// Volume ...
+type Volume struct {
+ *libpod.Volume
+}
+
+// VolumeFilter is for filtering volumes on the client
+type VolumeFilter func(*Volume) bool
+
// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it
func GetRuntime(c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
runtime, err := libpodruntime.GetRuntime(c)
@@ -155,3 +167,141 @@ func (r *LocalRuntime) Export(name string, path string) error {
func (r *LocalRuntime) Import(ctx context.Context, source, reference string, changes []string, history string, quiet bool) (string, error) {
return r.Runtime.Import(ctx, source, reference, changes, history, quiet)
}
+
+// CreateVolume is a wrapper to create volumes
+func (r *LocalRuntime) CreateVolume(ctx context.Context, c *cliconfig.VolumeCreateValues, labels, opts map[string]string) (string, error) {
+ var (
+ options []libpod.VolumeCreateOption
+ volName string
+ )
+
+ if len(c.InputArgs) > 0 {
+ volName = c.InputArgs[0]
+ options = append(options, libpod.WithVolumeName(volName))
+ }
+
+ if c.Flag("driver").Changed {
+ options = append(options, libpod.WithVolumeDriver(c.Driver))
+ }
+
+ if len(labels) != 0 {
+ options = append(options, libpod.WithVolumeLabels(labels))
+ }
+
+ if len(options) != 0 {
+ options = append(options, libpod.WithVolumeOptions(opts))
+ }
+ newVolume, err := r.NewVolume(ctx, options...)
+ if err != nil {
+ return "", err
+ }
+ return newVolume.Name(), nil
+}
+
+// RemoveVolumes is a wrapper to remove volumes
+func (r *LocalRuntime) RemoveVolumes(ctx context.Context, c *cliconfig.VolumeRmValues) ([]string, error) {
+ return r.Runtime.RemoveVolumes(ctx, c.InputArgs, c.All, c.Force)
+}
+
+// Push is a wrapper to push an image to a registry
+func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
+ newImage, err := r.ImageRuntime().NewFromLocal(srcName)
+ if err != nil {
+ return err
+ }
+ return newImage.PushImageToHeuristicDestination(ctx, destination, manifestMIMEType, authfile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, nil)
+}
+
+// InspectVolumes returns a slice of volumes based on an arg list or --all
+func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeInspectValues) ([]*Volume, error) {
+ var (
+ volumes []*libpod.Volume
+ err error
+ )
+
+ if c.All {
+ volumes, err = r.GetAllVolumes()
+ } else {
+ for _, v := range c.InputArgs {
+ vol, err := r.GetVolume(v)
+ if err != nil {
+ return nil, err
+ }
+ volumes = append(volumes, vol)
+ }
+ }
+ if err != nil {
+ return nil, err
+ }
+ return libpodVolumeToVolume(volumes), nil
+}
+
+// Volumes returns a slice of localruntime volumes
+func (r *LocalRuntime) Volumes(ctx context.Context) ([]*Volume, error) {
+ vols, err := r.GetAllVolumes()
+ if err != nil {
+ return nil, err
+ }
+ return libpodVolumeToVolume(vols), nil
+}
+
+// libpodVolumeToVolume converts a slice of libpod volumes to a slice
+// of localruntime volumes (same as libpod)
+func libpodVolumeToVolume(volumes []*libpod.Volume) []*Volume {
+ var vols []*Volume
+ for _, v := range volumes {
+ newVol := Volume{
+ v,
+ }
+ vols = append(vols, &newVol)
+ }
+ return vols
+}
+
+// Build is the wrapper to build images
+func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, options imagebuildah.BuildOptions, dockerfiles []string) error {
+ namespaceOptions, networkPolicy, err := parse.NamespaceOptions(c.PodmanCommand.Command)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing namespace-related options")
+ }
+ usernsOption, idmappingOptions, err := parse.IDMappingOptions(c.PodmanCommand.Command)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing ID mapping options")
+ }
+ namespaceOptions.AddOrReplace(usernsOption...)
+
+ systemContext, err := parse.SystemContextFromOptions(c.PodmanCommand.Command)
+ if err != nil {
+ return errors.Wrapf(err, "error building system context")
+ }
+
+ authfile := c.Authfile
+ if len(c.Authfile) == 0 {
+ authfile = os.Getenv("REGISTRY_AUTH_FILE")
+ }
+
+ systemContext.AuthFilePath = authfile
+ commonOpts, err := parse.CommonBuildOptions(c.PodmanCommand.Command)
+ if err != nil {
+ return err
+ }
+
+ options.NamespaceOptions = namespaceOptions
+ options.ConfigureNetwork = networkPolicy
+ options.IDMappingOptions = idmappingOptions
+ options.CommonBuildOpts = commonOpts
+ options.SystemContext = systemContext
+
+ if c.Flag("runtime").Changed {
+ options.Runtime = r.GetOCIRuntimePath()
+ }
+ if c.Quiet {
+ options.ReportWriter = ioutil.Discard
+ }
+
+ if rootless.IsRootless() {
+ options.Isolation = buildah.IsolationOCIRootless
+ }
+
+ return r.Runtime.Build(ctx, options, dockerfiles...)
+}
diff --git a/libpod/adapter/runtime_remote.go b/libpod/adapter/runtime_remote.go
index f754aaee6..a96676ee2 100644
--- a/libpod/adapter/runtime_remote.go
+++ b/libpod/adapter/runtime_remote.go
@@ -7,18 +7,22 @@ import (
"context"
"encoding/json"
"fmt"
- "github.com/pkg/errors"
"io"
+ "io/ioutil"
"os"
"strings"
"time"
+ "github.com/containers/buildah/imagebuildah"
+ "github.com/containers/image/docker/reference"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
+ "github.com/containers/storage/pkg/archive"
"github.com/opencontainers/go-digest"
+ "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/varlink/go/varlink"
)
@@ -91,6 +95,18 @@ type remoteContainer struct {
state *libpod.ContainerState
}
+type VolumeFilter func(*Volume) bool
+
+// Volume is embed for libpod volumes
+type Volume struct {
+ remoteVolume
+}
+
+type remoteVolume struct {
+ Runtime *LocalRuntime
+ config *libpod.VolumeConfig
+}
+
// GetImages returns a slice of containerimages over a varlink connection
func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) {
var newImages []*ContainerImage
@@ -112,8 +128,8 @@ func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) {
return newImages, nil
}
-func imageInListToContainerImage(i iopodman.ImageInList, name string, runtime *LocalRuntime) (*ContainerImage, error) {
- created, err := splitStringDate(i.Created)
+func imageInListToContainerImage(i iopodman.Image, name string, runtime *LocalRuntime) (*ContainerImage, error) {
+ created, err := time.ParseInLocation(time.RFC3339, i.Created, time.UTC)
if err != nil {
return nil, err
}
@@ -182,12 +198,6 @@ func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authf
return newImage, nil
}
-func splitStringDate(d string) (time.Time, error) {
- fields := strings.Fields(d)
- t := fmt.Sprintf("%sT%sZ", fields[0], fields[1])
- return time.ParseInLocation(time.RFC3339Nano, t, time.UTC)
-}
-
// IsParent goes through the layers in the store and checks if i.TopLayer is
// the parent of any other layer in store. Double check that image with that
// layer exists as well.
@@ -251,7 +261,7 @@ func (ci *ContainerImage) History(ctx context.Context) ([]*image.History, error)
return nil, err
}
for _, h := range reply {
- created, err := splitStringDate(h.Created)
+ created, err := time.ParseInLocation(time.RFC3339, h.Created, time.UTC)
if err != nil {
return nil, err
}
@@ -369,6 +379,108 @@ func (r *LocalRuntime) Export(name string, path string) error {
// Import implements the remote calls required to import a container image to the store
func (r *LocalRuntime) Import(ctx context.Context, source, reference string, changes []string, history string, quiet bool) (string, error) {
// First we send the file to the host
+ tempFile, err := r.SendFileOverVarlink(source)
+ if err != nil {
+ return "", err
+ }
+ return iopodman.ImportImage().Call(r.Conn, strings.TrimRight(tempFile, ":"), reference, history, changes, true)
+}
+
+func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, options imagebuildah.BuildOptions, dockerfiles []string) error {
+ buildOptions := iopodman.BuildOptions{
+ AddHosts: options.CommonBuildOpts.AddHost,
+ CgroupParent: options.CommonBuildOpts.CgroupParent,
+ CpuPeriod: int64(options.CommonBuildOpts.CPUPeriod),
+ CpuQuota: options.CommonBuildOpts.CPUQuota,
+ CpuShares: int64(options.CommonBuildOpts.CPUShares),
+ CpusetCpus: options.CommonBuildOpts.CPUSetMems,
+ CpusetMems: options.CommonBuildOpts.CPUSetMems,
+ Memory: options.CommonBuildOpts.Memory,
+ MemorySwap: options.CommonBuildOpts.MemorySwap,
+ ShmSize: options.CommonBuildOpts.ShmSize,
+ Ulimit: options.CommonBuildOpts.Ulimit,
+ Volume: options.CommonBuildOpts.Volumes,
+ }
+
+ buildinfo := iopodman.BuildInfo{
+ AdditionalTags: options.AdditionalTags,
+ Annotations: options.Annotations,
+ BuildArgs: options.Args,
+ BuildOptions: buildOptions,
+ CniConfigDir: options.CNIConfigDir,
+ CniPluginDir: options.CNIPluginPath,
+ Compression: string(options.Compression),
+ DefaultsMountFilePath: options.DefaultMountsFilePath,
+ Dockerfiles: dockerfiles,
+ //Err: string(options.Err),
+ ForceRmIntermediateCtrs: options.ForceRmIntermediateCtrs,
+ Iidfile: options.IIDFile,
+ Label: options.Labels,
+ Layers: options.Layers,
+ Nocache: options.NoCache,
+ //Out:
+ Output: options.Output,
+ OutputFormat: options.OutputFormat,
+ PullPolicy: options.PullPolicy.String(),
+ Quiet: options.Quiet,
+ RemoteIntermediateCtrs: options.RemoveIntermediateCtrs,
+ //ReportWriter:
+ RuntimeArgs: options.RuntimeArgs,
+ SignaturePolicyPath: options.SignaturePolicyPath,
+ Squash: options.Squash,
+ }
+ // tar the file
+ logrus.Debugf("creating tarball of context dir %s", options.ContextDirectory)
+ input, err := archive.Tar(options.ContextDirectory, archive.Uncompressed)
+ if err != nil {
+ return errors.Wrapf(err, "unable to create tarball of context dir %s", options.ContextDirectory)
+ }
+
+ // Write the tarball to the fs
+ // TODO we might considering sending this without writing to the fs for the sake of performance
+ // under given conditions like memory availability.
+ outputFile, err := ioutil.TempFile("", "varlink_tar_send")
+ if err != nil {
+ return err
+ }
+ defer outputFile.Close()
+ logrus.Debugf("writing context dir tarball to %s", outputFile.Name())
+
+ _, err = io.Copy(outputFile, input)
+ if err != nil {
+ return err
+ }
+
+ logrus.Debugf("completed writing context dir tarball %s", outputFile.Name())
+ // Send the context dir tarball over varlink.
+ tempFile, err := r.SendFileOverVarlink(outputFile.Name())
+ if err != nil {
+ return err
+ }
+ buildinfo.ContextDir = strings.Replace(tempFile, ":", "", -1)
+
+ reply, err := iopodman.BuildImage().Send(r.Conn, varlink.More, buildinfo)
+ if err != nil {
+ return err
+ }
+
+ for {
+ responses, flags, err := reply()
+ if err != nil {
+ return err
+ }
+ for _, line := range responses.Logs {
+ fmt.Print(line)
+ }
+ if flags&varlink.Continues == 0 {
+ break
+ }
+ }
+ return err
+}
+
+// SendFileOverVarlink sends a file over varlink in an upgraded connection
+func (r *LocalRuntime) SendFileOverVarlink(source string) (string, error) {
fs, err := os.Open(source)
if err != nil {
return "", err
@@ -378,6 +490,7 @@ func (r *LocalRuntime) Import(ctx context.Context, source, reference string, cha
if err != nil {
return "", err
}
+ logrus.Debugf("sending %s over varlink connection", source)
reply, err := iopodman.SendFile().Send(r.Conn, varlink.Upgrade, "", int64(fileInfo.Size()))
if err != nil {
return "", err
@@ -392,6 +505,7 @@ func (r *LocalRuntime) Import(ctx context.Context, source, reference string, cha
if err != nil {
return "", err
}
+ logrus.Debugf("file transfer complete for %s", source)
r.Conn.Writer.Flush()
// All was sent, wait for the ACK from the server
@@ -405,7 +519,8 @@ func (r *LocalRuntime) Import(ctx context.Context, source, reference string, cha
return "", err
}
- return iopodman.ImportImage().Call(r.Conn, strings.TrimRight(tempFile, ":"), reference, history, changes, true)
+
+ return tempFile, nil
}
// GetAllVolumes retrieves all the volumes
@@ -429,6 +544,101 @@ func (r *LocalRuntime) GetContainers(filters ...libpod.ContainerFilter) ([]*libp
// RemoveContainer removes the given container
// If force is specified, the container will be stopped first
// Otherwise, RemoveContainer will return an error if the container is running
-func (r *LocalRuntime) RemoveContainer(ctx context.Context, c *libpod.Container, force bool) error {
+func (r *LocalRuntime) RemoveContainer(ctx context.Context, c *libpod.Container, force, volumes bool) error {
return libpod.ErrNotImplemented
}
+
+// CreateVolume creates a volume over a varlink connection for the remote client
+func (r *LocalRuntime) CreateVolume(ctx context.Context, c *cliconfig.VolumeCreateValues, labels, opts map[string]string) (string, error) {
+ cvOpts := iopodman.VolumeCreateOpts{
+ Options: opts,
+ Labels: labels,
+ }
+ if len(c.InputArgs) > 0 {
+ cvOpts.VolumeName = c.InputArgs[0]
+ }
+
+ if c.Flag("driver").Changed {
+ cvOpts.Driver = c.Driver
+ }
+
+ return iopodman.VolumeCreate().Call(r.Conn, cvOpts)
+}
+
+// RemoveVolumes removes volumes over a varlink connection for the remote client
+func (r *LocalRuntime) RemoveVolumes(ctx context.Context, c *cliconfig.VolumeRmValues) ([]string, error) {
+ rmOpts := iopodman.VolumeRemoveOpts{
+ All: c.All,
+ Force: c.Force,
+ Volumes: c.InputArgs,
+ }
+ return iopodman.VolumeRemove().Call(r.Conn, rmOpts)
+}
+
+func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
+
+ tls := true
+ if dockerRegistryOptions.DockerInsecureSkipTLSVerify == types.OptionalBoolTrue {
+ tls = false
+ }
+ reply, err := iopodman.PushImage().Send(r.Conn, varlink.More, srcName, destination, tls, signaturePolicyPath, "", dockerRegistryOptions.DockerCertPath, forceCompress, manifestMIMEType, signingOptions.RemoveSignatures, signingOptions.SignBy)
+ if err != nil {
+ return err
+ }
+ for {
+ responses, flags, err := reply()
+ if err != nil {
+ return err
+ }
+ for _, line := range responses.Logs {
+ fmt.Print(line)
+ }
+ if flags&varlink.Continues == 0 {
+ break
+ }
+ }
+
+ return err
+}
+
+// InspectVolumes returns a slice of volumes based on an arg list or --all
+func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeInspectValues) ([]*Volume, error) {
+ reply, err := iopodman.GetVolumes().Call(r.Conn, c.InputArgs, c.All)
+ if err != nil {
+ return nil, err
+ }
+ return varlinkVolumeToVolume(r, reply), nil
+}
+
+//Volumes returns a slice of adapter.volumes based on information about libpod
+// volumes over a varlink connection
+func (r *LocalRuntime) Volumes(ctx context.Context) ([]*Volume, error) {
+ reply, err := iopodman.GetVolumes().Call(r.Conn, []string{}, true)
+ if err != nil {
+ return nil, err
+ }
+ return varlinkVolumeToVolume(r, reply), nil
+}
+
+func varlinkVolumeToVolume(r *LocalRuntime, volumes []iopodman.Volume) []*Volume {
+ var vols []*Volume
+ for _, v := range volumes {
+ volumeConfig := libpod.VolumeConfig{
+ Name: v.Name,
+ Labels: v.Labels,
+ MountPoint: v.MountPoint,
+ Driver: v.Driver,
+ Options: v.Options,
+ Scope: v.Scope,
+ }
+ n := remoteVolume{
+ Runtime: r,
+ config: &volumeConfig,
+ }
+ newVol := Volume{
+ n,
+ }
+ vols = append(vols, &newVol)
+ }
+ return vols
+}
diff --git a/libpod/adapter/volumes_remote.go b/libpod/adapter/volumes_remote.go
new file mode 100644
index 000000000..beacd943a
--- /dev/null
+++ b/libpod/adapter/volumes_remote.go
@@ -0,0 +1,33 @@
+// +build remoteclient
+
+package adapter
+
+// Name returns the name of the volume
+func (v *Volume) Name() string {
+ return v.config.Name
+}
+
+//Labels returns the labels for a volume
+func (v *Volume) Labels() map[string]string {
+ return v.config.Labels
+}
+
+// Driver returns the driver for the volume
+func (v *Volume) Driver() string {
+ return v.config.Driver
+}
+
+// Options returns the options a volume was created with
+func (v *Volume) Options() map[string]string {
+ return v.config.Options
+}
+
+// MountPath returns the path the volume is mounted to
+func (v *Volume) MountPoint() string {
+ return v.config.MountPoint
+}
+
+// Scope returns the scope for an adapter.volume
+func (v *Volume) Scope() string {
+ return v.config.Scope
+}
diff --git a/libpod/container.go b/libpod/container.go
index b0589be3b..75f4a4a4f 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -358,8 +358,7 @@ type ContainerConfig struct {
ExitCommand []string `json:"exitCommand,omitempty"`
// LocalVolumes are the built-in volumes we get from the --volumes-from flag
// It picks up the built-in volumes of the container used by --volumes-from
- LocalVolumes []string
-
+ LocalVolumes []spec.Mount
// IsInfra is a bool indicating whether this container is an infra container used for
// sharing kernel namespaces in a pod
IsInfra bool `json:"pause"`
@@ -557,8 +556,16 @@ func (c *Container) NewNetNS() bool {
// PortMappings returns the ports that will be mapped into a container if
// a new network namespace is created
// If NewNetNS() is false, this value is unused
-func (c *Container) PortMappings() []ocicni.PortMapping {
- return c.config.PortMappings
+func (c *Container) PortMappings() ([]ocicni.PortMapping, error) {
+ // First check if the container belongs to a network namespace (like a pod)
+ if len(c.config.NetNsCtr) > 0 {
+ netNsCtr, err := c.runtime.LookupContainer(c.config.NetNsCtr)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to lookup network namespace for container %s", c.ID())
+ }
+ return netNsCtr.PortMappings()
+ }
+ return c.config.PortMappings, nil
}
// DNSServers returns DNS servers that will be used in the container's
diff --git a/libpod/container_attach_linux.go b/libpod/container_attach_linux.go
index 1d6f0bd96..3ff6ddc76 100644
--- a/libpod/container_attach_linux.go
+++ b/libpod/container_attach_linux.go
@@ -109,8 +109,8 @@ func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSi
case err := <-receiveStdoutError:
return err
case err := <-stdinDone:
- if _, ok := err.(utils.DetachError); ok {
- return nil
+ if err == ErrDetach {
+ return err
}
if streams.AttachOutput || streams.AttachError {
return <-receiveStdoutError
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index b0dcc853e..b2ebad777 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -10,21 +10,16 @@ import (
"path/filepath"
"strconv"
"strings"
- "syscall"
"time"
- "github.com/containers/buildah/imagebuildah"
"github.com/containers/libpod/pkg/ctime"
"github.com/containers/libpod/pkg/hooks"
"github.com/containers/libpod/pkg/hooks/exec"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/archive"
- "github.com/containers/storage/pkg/chrootarchive"
"github.com/containers/storage/pkg/mount"
- "github.com/opencontainers/runc/libcontainer/user"
spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -489,9 +484,20 @@ func (c *Container) removeConmonFiles() error {
return errors.Wrapf(err, "error removing container %s OOM file", c.ID())
}
+ // Instead of outright deleting the exit file, rename it (if it exists).
+ // We want to retain it so we can get the exit code of containers which
+ // are removed (at least until we have a workable events system)
exitFile := filepath.Join(c.runtime.ociRuntime.exitsDir, c.ID())
- if err := os.Remove(exitFile); err != nil && !os.IsNotExist(err) {
- return errors.Wrapf(err, "error removing container %s exit file", c.ID())
+ oldExitFile := filepath.Join(c.runtime.ociRuntime.exitsDir, fmt.Sprintf("%s-old", c.ID()))
+ if _, err := os.Stat(exitFile); err != nil {
+ if !os.IsNotExist(err) {
+ return errors.Wrapf(err, "error running stat on container %s exit file", c.ID())
+ }
+ } else if err == nil {
+ // Rename should replace the old exit file (if it exists)
+ if err := os.Rename(exitFile, oldExitFile); err != nil {
+ return errors.Wrapf(err, "error renaming container %s exit file", c.ID())
+ }
}
return nil
@@ -1042,113 +1048,6 @@ func (c *Container) writeStringToRundir(destFile, output string) (string, error)
return filepath.Join(c.state.DestinationRunDir, destFile), nil
}
-func (c *Container) addLocalVolumes(ctx context.Context, g *generate.Generator, execUser *user.ExecUser) error {
- var uid, gid int
- mountPoint := c.state.Mountpoint
- if !c.state.Mounted {
- return errors.Wrapf(ErrInternal, "container is not mounted")
- }
- newImage, err := c.runtime.imageRuntime.NewFromLocal(c.config.RootfsImageID)
- if err != nil {
- return err
- }
- imageData, err := newImage.Inspect(ctx)
- if err != nil {
- return err
- }
- // Add the built-in volumes of the container passed in to --volumes-from
- for _, vol := range c.config.LocalVolumes {
- if imageData.Config.Volumes == nil {
- imageData.Config.Volumes = map[string]struct{}{
- vol: {},
- }
- } else {
- imageData.Config.Volumes[vol] = struct{}{}
- }
- }
-
- if c.config.User != "" {
- if execUser == nil {
- return errors.Wrapf(ErrInternal, "nil pointer passed to addLocalVolumes for execUser")
- }
- uid = execUser.Uid
- gid = execUser.Gid
- }
-
- for k := range imageData.Config.Volumes {
- mount := spec.Mount{
- Destination: k,
- Type: "bind",
- Options: []string{"private", "bind", "rw"},
- }
- if MountExists(g.Mounts(), k) {
- continue
- }
- volumePath := filepath.Join(c.config.StaticDir, "volumes", k)
-
- // Ensure the symlinks are resolved
- resolvedSymlink, err := imagebuildah.ResolveSymLink(mountPoint, k)
- if err != nil {
- return errors.Wrapf(ErrCtrStateInvalid, "cannot resolve %s in %s for container %s", k, mountPoint, c.ID())
- }
- var srcPath string
- if resolvedSymlink != "" {
- srcPath = filepath.Join(mountPoint, resolvedSymlink)
- } else {
- srcPath = filepath.Join(mountPoint, k)
- }
-
- if _, err := os.Stat(srcPath); os.IsNotExist(err) {
- logrus.Infof("Volume image mount point %s does not exist in root FS, need to create it", k)
- if err = os.MkdirAll(srcPath, 0755); err != nil {
- return errors.Wrapf(err, "error creating directory %q for volume %q in container %q", volumePath, k, c.ID())
- }
-
- if err = os.Chown(srcPath, uid, gid); err != nil {
- return errors.Wrapf(err, "error chowning directory %q for volume %q in container %q", srcPath, k, c.ID())
- }
- }
-
- if _, err := os.Stat(volumePath); os.IsNotExist(err) {
- if err = os.MkdirAll(volumePath, 0755); err != nil {
- return errors.Wrapf(err, "error creating directory %q for volume %q in container %q", volumePath, k, c.ID())
- }
-
- if err = os.Chown(volumePath, uid, gid); err != nil {
- return errors.Wrapf(err, "error chowning directory %q for volume %q in container %q", volumePath, k, c.ID())
- }
-
- if err = label.Relabel(volumePath, c.config.MountLabel, false); err != nil {
- return errors.Wrapf(err, "error relabeling directory %q for volume %q in container %q", volumePath, k, c.ID())
- }
- if err = chrootarchive.NewArchiver(nil).CopyWithTar(srcPath, volumePath); err != nil && !os.IsNotExist(err) {
- return errors.Wrapf(err, "error populating directory %q for volume %q in container %q using contents of %q", volumePath, k, c.ID(), srcPath)
- }
-
- // Set the volume path with the same owner and permission of source path
- sstat, _ := os.Stat(srcPath)
- st, ok := sstat.Sys().(*syscall.Stat_t)
- if !ok {
- return fmt.Errorf("could not convert to syscall.Stat_t")
- }
- uid := int(st.Uid)
- gid := int(st.Gid)
-
- if err := os.Lchown(volumePath, uid, gid); err != nil {
- return err
- }
- if os.Chmod(volumePath, sstat.Mode()); err != nil {
- return err
- }
-
- }
-
- mount.Source = volumePath
- g.AddMount(mount)
- }
- return nil
-}
-
// Save OCI spec to disk, replacing any existing specs for the container
func (c *Container) saveSpec(spec *spec.Spec) error {
// If the OCI spec already exists, we need to replace it
@@ -1292,3 +1191,30 @@ func getExcludedCGroups() (excludes []string) {
excludes = []string{"rdma"}
return
}
+
+// namedVolumes returns named volumes for the container
+func (c *Container) namedVolumes() ([]string, error) {
+ var volumes []string
+ for _, vol := range c.config.Spec.Mounts {
+ if strings.HasPrefix(vol.Source, c.runtime.config.VolumePath) {
+ volume := strings.TrimPrefix(vol.Source, c.runtime.config.VolumePath+"/")
+ split := strings.Split(volume, "/")
+ volume = split[0]
+ if _, err := c.runtime.state.Volume(volume); err == nil {
+ volumes = append(volumes, volume)
+ }
+ }
+ }
+ return volumes, nil
+}
+
+// this should be from chrootarchive.
+func (c *Container) copyWithTarFromImage(src, dest string) error {
+ mountpoint, err := c.mount()
+ if err != nil {
+ return err
+ }
+ a := archive.NewDefaultArchiver()
+ source := filepath.Join(mountpoint, src)
+ return a.CopyWithTar(source, dest)
+}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index bcdfdaee3..65cb47c8c 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -235,13 +235,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
}
- // Bind builtin image volumes
- if c.config.Rootfs == "" && c.config.ImageVolumes {
- if err := c.addLocalVolumes(ctx, &g, execUser); err != nil {
- return nil, errors.Wrapf(err, "error mounting image volumes")
- }
- }
-
if c.config.User != "" {
// User and Group must go together
g.SetProcessUID(uint32(execUser.Uid))
diff --git a/libpod/errors.go b/libpod/errors.go
index d6614141c..dd82d0796 100644
--- a/libpod/errors.go
+++ b/libpod/errors.go
@@ -2,15 +2,21 @@ package libpod
import (
"errors"
+
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/utils"
)
var (
// ErrNoSuchCtr indicates the requested container does not exist
- ErrNoSuchCtr = errors.New("no such container")
+ ErrNoSuchCtr = image.ErrNoSuchCtr
+
// ErrNoSuchPod indicates the requested pod does not exist
- ErrNoSuchPod = errors.New("no such pod")
+ ErrNoSuchPod = image.ErrNoSuchPod
+
// ErrNoSuchImage indicates the requested image does not exist
- ErrNoSuchImage = errors.New("no such image")
+ ErrNoSuchImage = image.ErrNoSuchImage
+
// ErrNoSuchVolume indicates the requested volume does not exist
ErrNoSuchVolume = errors.New("no such volume")
@@ -51,6 +57,10 @@ var (
// ErrInternal indicates an internal library error
ErrInternal = errors.New("internal libpod error")
+ // ErrDetach indicates that an attach session was manually detached by
+ // the user.
+ ErrDetach = utils.ErrDetach
+
// ErrRuntimeStopped indicates that the runtime has already been shut
// down and no further operations can be performed on it
ErrRuntimeStopped = errors.New("runtime has already been stopped")
diff --git a/libpod/image/utils.go b/libpod/image/utils.go
index ad027f32a..3585428ad 100644
--- a/libpod/image/utils.go
+++ b/libpod/image/utils.go
@@ -87,22 +87,29 @@ func hasTransport(image string) bool {
// ReposToMap parses the specified repotags and returns a map with repositories
// as keys and the corresponding arrays of tags as values.
-func ReposToMap(repotags []string) map[string][]string {
+func ReposToMap(repotags []string) (map[string][]string, error) {
// map format is repo -> tag
repos := make(map[string][]string)
for _, repo := range repotags {
var repository, tag string
if len(repo) > 0 {
- li := strings.LastIndex(repo, ":")
- repository = repo[0:li]
- tag = repo[li+1:]
+ named, err := reference.ParseNormalizedNamed(repo)
+ repository = named.Name()
+ if err != nil {
+ return nil, err
+ }
+ if ref, ok := named.(reference.NamedTagged); ok {
+ tag = ref.Tag()
+ } else if ref, ok := named.(reference.Canonical); ok {
+ tag = ref.Digest().String()
+ }
}
repos[repository] = append(repos[repository], tag)
}
if len(repos) == 0 {
repos["<none>"] = []string{"<none>"}
}
- return repos
+ return repos, nil
}
// GetAdditionalTags returns a list of reference.NamedTagged for the
diff --git a/libpod/kube.go b/libpod/kube.go
index 16cebf99b..484127870 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -228,7 +228,11 @@ func containerToV1Container(c *Container) (v1.Container, error) {
return kubeContainer, nil
}
- ports, err := ocicniPortMappingToContainerPort(c.PortMappings())
+ portmappings, err := c.PortMappings()
+ if err != nil {
+ return kubeContainer, err
+ }
+ ports, err := ocicniPortMappingToContainerPort(portmappings)
if err != nil {
return kubeContainer, nil
}
diff --git a/libpod/options.go b/libpod/options.go
index d965c058e..06737776b 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
"github.com/cri-o/ocicni/pkg/ocicni"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
@@ -1058,7 +1059,7 @@ func WithUserVolumes(volumes []string) CtrCreateOption {
// from a container passed in to the --volumes-from flag.
// This stores the built-in volume information in the Config so we can
// add them when creating the container.
-func WithLocalVolumes(volumes []string) CtrCreateOption {
+func WithLocalVolumes(volumes []spec.Mount) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 9afdef7b6..185090cf7 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -10,7 +10,9 @@ import (
"strings"
"time"
+ "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/storage"
"github.com/containers/storage/pkg/stringid"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
@@ -175,9 +177,12 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
if err != nil {
newVol, err := r.newVolume(ctx, WithVolumeName(vol.Source))
if err != nil {
- logrus.Errorf("error creating named volume %q: %v", vol.Source, err)
+ return nil, errors.Wrapf(err, "error creating named volume %q", vol.Source)
}
ctr.config.Spec.Mounts[i].Source = newVol.MountPoint()
+ if err := ctr.copyWithTarFromImage(ctr.config.Spec.Mounts[i].Destination, ctr.config.Spec.Mounts[i].Source); err != nil && !os.IsNotExist(err) {
+ return nil, errors.Wrapf(err, "Failed to copy content into new volume mount %q", vol.Source)
+ }
continue
}
ctr.config.Spec.Mounts[i].Source = volInfo.MountPoint()
@@ -223,17 +228,19 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
// RemoveContainer removes the given container
// If force is specified, the container will be stopped first
+// If removeVolume is specified, named volumes used by the container will
+// be removed also if and only if the container is the sole user
// Otherwise, RemoveContainer will return an error if the container is running
-func (r *Runtime) RemoveContainer(ctx context.Context, c *Container, force bool) error {
+func (r *Runtime) RemoveContainer(ctx context.Context, c *Container, force bool, removeVolume bool) error {
r.lock.Lock()
defer r.lock.Unlock()
- return r.removeContainer(ctx, c, force)
+ return r.removeContainer(ctx, c, force, removeVolume)
}
// Internal function to remove a container
// Locks the container, but does not lock the runtime
-func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool) error {
+func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, removeVolume bool) error {
if !c.valid {
if ok, _ := r.state.HasContainer(c.ID()); !ok {
// Container probably already removed
@@ -246,6 +253,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool)
// To avoid races around removing a container and the pod it is in
var pod *Pod
var err error
+ runtime := c.runtime
if c.config.Pod != "" {
pod, err = r.state.Pod(c.config.Pod)
if err != nil {
@@ -331,6 +339,13 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool)
return errors.Wrapf(ErrCtrExists, "container %s has dependent containers which must be removed before it: %s", c.ID(), depsStr)
}
+ var volumes []string
+ if removeVolume {
+ volumes, err = c.namedVolumes()
+ if err != nil {
+ logrus.Errorf("unable to retrieve builtin volumes for container %v: %v", c.ID(), err)
+ }
+ }
var cleanupErr error
// Remove the container from the state
if c.config.Pod != "" {
@@ -395,6 +410,14 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool)
}
}
+ for _, v := range volumes {
+ if volume, err := runtime.state.Volume(v); err == nil {
+ if err := runtime.removeVolume(ctx, volume, false, true); err != nil && err != ErrNoSuchVolume && err != ErrVolumeBeingUsed {
+ logrus.Errorf("cleanup volume (%s): %v", v, err)
+ }
+ }
+ }
+
return cleanupErr
}
@@ -564,3 +587,16 @@ func (r *Runtime) Export(name string, path string) error {
return ctr.Export(path)
}
+
+// RemoveContainersFromStorage attempt to remove containers from storage that do not exist in libpod database
+func (r *Runtime) RemoveContainersFromStorage(ctrs []string) {
+ for _, i := range ctrs {
+ // if the container does not exist in database, attempt to remove it from storage
+ if _, err := r.LookupContainer(i); err != nil && errors.Cause(err) == image.ErrNoSuchCtr {
+ r.storageService.UnmountContainerImage(i, true)
+ if err := r.storageService.DeleteContainer(i); err != nil && errors.Cause(err) != storage.ErrContainerUnknown {
+ logrus.Errorf("Failed to remove container %q from storage: %s", i, err)
+ }
+ }
+ }
+}
diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go
index c20aa77a3..1e9689362 100644
--- a/libpod/runtime_img.go
+++ b/libpod/runtime_img.go
@@ -43,7 +43,7 @@ func (r *Runtime) RemoveImage(ctx context.Context, img *image.Image, force bool)
if len(imageCtrs) > 0 && len(img.Names()) <= 1 {
if force {
for _, ctr := range imageCtrs {
- if err := r.removeContainer(ctx, ctr, true); err != nil {
+ if err := r.removeContainer(ctx, ctr, true, false); err != nil {
return "", errors.Wrapf(err, "error removing image %s: container %s using image could not be removed", img.ID(), ctr.ID())
}
}
diff --git a/libpod/runtime_volume.go b/libpod/runtime_volume.go
index 3921758ee..485f64bf1 100644
--- a/libpod/runtime_volume.go
+++ b/libpod/runtime_volume.go
@@ -2,6 +2,9 @@ package libpod
import (
"context"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "strings"
)
// Contains the public Runtime API for volumes
@@ -38,6 +41,38 @@ func (r *Runtime) RemoveVolume(ctx context.Context, v *Volume, force, prune bool
return r.removeVolume(ctx, v, force, prune)
}
+// RemoveVolumes removes a slice of volumes or all with a force bool
+func (r *Runtime) RemoveVolumes(ctx context.Context, volumes []string, all, force bool) ([]string, error) {
+ var (
+ vols []*Volume
+ err error
+ deletedVols []string
+ )
+ if all {
+ vols, err = r.Volumes()
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to get all volumes")
+ }
+ } else {
+ for _, i := range volumes {
+ vol, err := r.GetVolume(i)
+ if err != nil {
+ return nil, err
+ }
+ vols = append(vols, vol)
+ }
+ }
+
+ for _, vol := range vols {
+ if err := r.RemoveVolume(ctx, vol, force, false); err != nil {
+ return deletedVols, err
+ }
+ logrus.Debugf("removed volume %s", vol.Name())
+ deletedVols = append(deletedVols, vol.Name())
+ }
+ return deletedVols, nil
+}
+
// GetVolume retrieves a volume by its name
func (r *Runtime) GetVolume(name string) (*Volume, error) {
r.lock.RLock()
@@ -47,7 +82,21 @@ func (r *Runtime) GetVolume(name string) (*Volume, error) {
return nil, ErrRuntimeStopped
}
- return r.state.Volume(name)
+ vol, err := r.state.Volume(name)
+ if err == nil {
+ return vol, err
+ }
+
+ vols, err := r.GetAllVolumes()
+ if err != nil {
+ return nil, err
+ }
+ for _, v := range vols {
+ if strings.HasPrefix(v.Name(), name) {
+ return v, nil
+ }
+ }
+ return nil, errors.Errorf("unable to find volume %s", name)
}
// HasVolume checks to see if a volume with the given name exists
diff --git a/libpod/volume_internal.go b/libpod/volume_internal.go
index 800e6d106..0de8a2350 100644
--- a/libpod/volume_internal.go
+++ b/libpod/volume_internal.go
@@ -5,10 +5,6 @@ import (
"path/filepath"
)
-// VolumePath is the path under which all volumes that are created using the
-// local driver will be created
-// const VolumePath = "/var/lib/containers/storage/volumes"
-
// Creates a new volume
func newVolume(runtime *Runtime) (*Volume, error) {
volume := new(Volume)
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index f6c77d61c..8da44a2f0 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -13,6 +13,7 @@ import (
"github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
+ "github.com/containers/storage/pkg/stringid"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-connections/nat"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -134,8 +135,8 @@ type CreateConfig struct {
SeccompProfilePath string //SecurityOpts
SecurityOpts []string
Rootfs string
- LocalVolumes []string //Keeps track of the built-in volumes of container used in the --volumes-from flag
- Syslog bool // Whether to enable syslog on exit commands
+ LocalVolumes []spec.Mount //Keeps track of the built-in volumes of container used in the --volumes-from flag
+ Syslog bool // Whether to enable syslog on exit commands
}
func u32Ptr(i int64) *uint32 { u := uint32(i); return &u }
@@ -216,7 +217,7 @@ func (c *CreateConfig) initFSMounts() []spec.Mount {
//GetVolumeMounts takes user provided input for bind mounts and creates Mount structs
func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, error) {
- var m []spec.Mount
+ m := c.LocalVolumes
for _, i := range c.Volumes {
var options []string
spliti := strings.Split(i, ":")
@@ -234,22 +235,31 @@ func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, e
logrus.Debugf("User mount %s:%s options %v", spliti[0], spliti[1], options)
}
- // volumes from image config
- if c.ImageVolumeType != "tmpfs" {
+ if c.ImageVolumeType == "ignore" {
return m, nil
}
+
for vol := range c.BuiltinImgVolumes {
if libpod.MountExists(specMounts, vol) {
continue
}
+
mount := spec.Mount{
Destination: vol,
- Type: string(TypeTmpfs),
- Source: string(TypeTmpfs),
- Options: []string{"rprivate", "rw", "noexec", "nosuid", "nodev", "tmpcopyup"},
+ Type: c.ImageVolumeType,
+ Options: []string{"rprivate", "rw", "nodev"},
+ }
+ if c.ImageVolumeType == "tmpfs" {
+ mount.Source = "tmpfs"
+ mount.Options = append(mount.Options, "tmpcopyup")
+ } else {
+ // This will cause a new local Volume to be created on your system
+ mount.Source = stringid.GenerateNonCryptoID()
+ mount.Options = append(mount.Options, "bind")
}
m = append(m, mount)
}
+
return m, nil
}
@@ -257,6 +267,11 @@ func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, e
// and adds it to c.Volumes of the current container.
func (c *CreateConfig) GetVolumesFrom() error {
var options string
+
+ if rootless.SkipStorageSetup() {
+ return nil
+ }
+
for _, vol := range c.VolumesFrom {
splitVol := strings.SplitN(vol, ":", 2)
if len(splitVol) == 2 {
@@ -266,6 +281,10 @@ func (c *CreateConfig) GetVolumesFrom() error {
if err != nil {
return errors.Wrapf(err, "error looking up container %q", splitVol[0])
}
+ inspect, err := ctr.Inspect(false)
+ if err != nil {
+ return errors.Wrapf(err, "error inspecting %q", splitVol[0])
+ }
var createArtifact CreateConfig
artifact, err := ctr.GetArtifact("create-config")
if err != nil {
@@ -274,9 +293,13 @@ func (c *CreateConfig) GetVolumesFrom() error {
if err := json.Unmarshal(artifact, &createArtifact); err != nil {
return err
}
-
for key := range createArtifact.BuiltinImgVolumes {
- c.LocalVolumes = append(c.LocalVolumes, key)
+ for _, m := range inspect.Mounts {
+ if m.Destination == key {
+ c.LocalVolumes = append(c.LocalVolumes, m)
+ break
+ }
+ }
}
for _, i := range createArtifact.Volumes {
@@ -340,7 +363,13 @@ func (c *CreateConfig) createExitCommand() []string {
if c.Syslog {
command = append(command, "--syslog")
}
- return append(command, []string{"container", "cleanup"}...)
+ command = append(command, []string{"container", "cleanup"}...)
+
+ if c.Rm {
+ command = append(command, "--rm")
+ }
+
+ return command
}
// GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions
@@ -518,11 +547,9 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime, pod *l
if c.CgroupParent != "" {
options = append(options, libpod.WithCgroupParent(c.CgroupParent))
}
- // For a rootless container always cleanup the storage/network as they
- // run in a different namespace thus not reusable when we restart.
- if c.Detach || rootless.IsRootless() {
- options = append(options, libpod.WithExitCommand(c.createExitCommand()))
- }
+
+ // Always use a cleanup process to clean up Podman after termination
+ options = append(options, libpod.WithExitCommand(c.createExitCommand()))
return options, nil
}
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 52f431881..db8a3d5bb 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -259,8 +259,8 @@ func GetRootlessStorageOpts() (storage.StoreOptions, error) {
return opts, nil
}
-// GetRootlessVolumeInfo returns where all the name volumes will be created in rootless mode
-func GetRootlessVolumeInfo() (string, error) {
+// GetRootlessVolumePath returns where all the name volumes will be created in rootless mode
+func GetRootlessVolumePath() (string, error) {
dataDir, _, err := GetRootlessDirInfo()
if err != nil {
return "", err
@@ -307,15 +307,13 @@ func GetDefaultStoreOptions() (storage.StoreOptions, string, error) {
err error
)
storageOpts := storage.DefaultStoreOptions
- volumePath := "/var/lib/containers/storage"
-
+ volumePath := filepath.Join(storageOpts.GraphRoot, "volumes")
if rootless.IsRootless() {
storageOpts, err = GetRootlessStorageOpts()
if err != nil {
return storageOpts, volumePath, err
}
-
- volumePath, err = GetRootlessVolumeInfo()
+ volumePath, err = GetRootlessVolumePath()
if err != nil {
return storageOpts, volumePath, err
}
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index 737e2dd96..8a52efa61 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -21,7 +21,7 @@ import (
// ListContainers ...
func (i *LibpodAPI) ListContainers(call iopodman.VarlinkCall) error {
var (
- listContainers []iopodman.ListContainerData
+ listContainers []iopodman.Container
)
containers, err := i.Runtime.GetAllContainers()
@@ -44,10 +44,10 @@ func (i *LibpodAPI) ListContainers(call iopodman.VarlinkCall) error {
}
// GetContainer ...
-func (i *LibpodAPI) GetContainer(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
+func (i *LibpodAPI) GetContainer(call iopodman.VarlinkCall, id string) error {
+ ctr, err := i.Runtime.LookupContainer(id)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(id)
}
opts := shared.PsOptions{
Namespace: true,
@@ -247,11 +247,6 @@ func (i *LibpodAPI) GetContainerStats(call iopodman.VarlinkCall, name string) er
return call.ReplyGetContainerStats(cs)
}
-// ResizeContainerTty ...
-func (i *LibpodAPI) ResizeContainerTty(call iopodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("ResizeContainerTty")
-}
-
// StartContainer ...
func (i *LibpodAPI) StartContainer(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
@@ -324,16 +319,6 @@ func (i *LibpodAPI) KillContainer(call iopodman.VarlinkCall, name string, signal
return call.ReplyKillContainer(ctr.ID())
}
-// UpdateContainer ...
-func (i *LibpodAPI) UpdateContainer(call iopodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("UpdateContainer")
-}
-
-// RenameContainer ...
-func (i *LibpodAPI) RenameContainer(call iopodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("RenameContainer")
-}
-
// PauseContainer ...
func (i *LibpodAPI) PauseContainer(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
@@ -358,12 +343,6 @@ func (i *LibpodAPI) UnpauseContainer(call iopodman.VarlinkCall, name string) err
return call.ReplyUnpauseContainer(ctr.ID())
}
-// AttachToContainer ...
-// TODO: DO we also want a different one for websocket?
-func (i *LibpodAPI) AttachToContainer(call iopodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("AttachToContainer")
-}
-
// WaitContainer ...
func (i *LibpodAPI) WaitContainer(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
@@ -379,13 +358,13 @@ func (i *LibpodAPI) WaitContainer(call iopodman.VarlinkCall, name string) error
}
// RemoveContainer ...
-func (i *LibpodAPI) RemoveContainer(call iopodman.VarlinkCall, name string, force bool) error {
+func (i *LibpodAPI) RemoveContainer(call iopodman.VarlinkCall, name string, force bool, removeVolumes bool) error {
ctx := getContext()
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
return call.ReplyContainerNotFound(name)
}
- if err := i.Runtime.RemoveContainer(ctx, ctr, force); err != nil {
+ if err := i.Runtime.RemoveContainer(ctx, ctr, force, removeVolumes); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
return call.ReplyRemoveContainer(ctr.ID())
@@ -406,7 +385,7 @@ func (i *LibpodAPI) DeleteStoppedContainers(call iopodman.VarlinkCall) error {
return call.ReplyErrorOccurred(err.Error())
}
if state != libpod.ContainerStateRunning {
- if err := i.Runtime.RemoveContainer(ctx, ctr, false); err != nil {
+ if err := i.Runtime.RemoveContainer(ctx, ctr, false, false); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
deletedContainers = append(deletedContainers, ctr.ID())
diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go
index f1835a189..6b53b22c6 100644
--- a/pkg/varlinkapi/containers_create.go
+++ b/pkg/varlinkapi/containers_create.go
@@ -131,9 +131,14 @@ func varlinkCreateToCreateConfig(ctx context.Context, create iopodman.Create, ru
}
imageID := data.ID
+ var ImageVolumes map[string]struct{}
+ if data != nil && create.Image_volume_type != "ignore" {
+ ImageVolumes = data.Config.Volumes
+ }
+
config := &cc.CreateConfig{
Runtime: runtime,
- BuiltinImgVolumes: data.Config.Volumes,
+ BuiltinImgVolumes: ImageVolumes,
ConmonPidFile: create.Conmon_pidfile,
ImageVolumeType: create.Image_volume_type,
CapAdd: create.Cap_add,
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 5e0889645..534419f6f 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/ioutil"
"os"
"path/filepath"
"strings"
@@ -24,10 +25,11 @@ import (
sysreg "github.com/containers/libpod/pkg/registries"
"github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
- "github.com/docker/go-units"
+ "github.com/containers/storage/pkg/archive"
"github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// ListImages lists all the images in the store
@@ -37,7 +39,7 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
if err != nil {
return call.ReplyErrorOccurred(fmt.Sprintf("unable to get list of images %q", err))
}
- var imageList []iopodman.ImageInList
+ var imageList []iopodman.Image
for _, image := range images {
labels, _ := image.Labels(getContext())
containers, _ := image.Containers()
@@ -52,12 +54,12 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
return call.ReplyErrorOccurred(err.Error())
}
- i := iopodman.ImageInList{
+ i := iopodman.Image{
Id: image.ID(),
ParentId: image.Parent,
RepoTags: image.Names(),
RepoDigests: repoDigests,
- Created: image.Created().String(),
+ Created: image.Created().Format(time.RFC3339),
Size: int64(*size),
VirtualSize: image.VirtualSize,
Containers: int64(len(containers)),
@@ -69,11 +71,11 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
return call.ReplyListImages(imageList)
}
-// GetImage returns a single image in the form of a ImageInList
-func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error {
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
+// GetImage returns a single image in the form of a Image
+func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, id string) error {
+ newImage, err := i.Runtime.ImageRuntime().NewFromLocal(id)
if err != nil {
- return call.ReplyImageNotFound(err.Error())
+ return call.ReplyImageNotFound(id)
}
labels, err := newImage.Labels(getContext())
if err != nil {
@@ -92,12 +94,12 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error {
return err
}
- il := iopodman.ImageInList{
+ il := iopodman.Image{
Id: newImage.ID(),
ParentId: newImage.Parent,
RepoTags: newImage.Names(),
RepoDigests: repoDigests,
- Created: newImage.Created().String(),
+ Created: newImage.Created().Format(time.RFC3339),
Size: int64(*size),
VirtualSize: newImage.VirtualSize,
Containers: int64(len(containers)),
@@ -109,83 +111,46 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error {
// BuildImage ...
func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildInfo) error {
var (
- memoryLimit int64
- memorySwap int64
- namespace []buildah.NamespaceOption
- err error
+ namespace []buildah.NamespaceOption
+ err error
)
systemContext := types.SystemContext{}
- dockerfiles := config.Dockerfile
- contextDir := ""
-
- for i := range dockerfiles {
- if strings.HasPrefix(dockerfiles[i], "http://") ||
- strings.HasPrefix(dockerfiles[i], "https://") ||
- strings.HasPrefix(dockerfiles[i], "git://") ||
- strings.HasPrefix(dockerfiles[i], "github.com/") {
- continue
- }
- absFile, err := filepath.Abs(dockerfiles[i])
- if err != nil {
- return errors.Wrapf(err, "error determining path to file %q", dockerfiles[i])
- }
- contextDir = filepath.Dir(absFile)
- dockerfiles[i], err = filepath.Rel(contextDir, absFile)
- if err != nil {
- return errors.Wrapf(err, "error determining path to file %q", dockerfiles[i])
- }
- break
- }
+ contextDir := config.ContextDir
- pullPolicy := imagebuildah.PullNever
- if config.Pull {
- pullPolicy = imagebuildah.PullIfMissing
- }
-
- if config.Pull_always {
- pullPolicy = imagebuildah.PullAlways
- }
- manifestType := "oci" //nolint
- if config.Image_format != "" {
- manifestType = config.Image_format
- }
-
- if strings.HasPrefix(manifestType, "oci") {
- manifestType = buildah.OCIv1ImageManifest
- } else if strings.HasPrefix(manifestType, "docker") {
- manifestType = buildah.Dockerv2ImageManifest
- } else {
- return call.ReplyErrorOccurred(fmt.Sprintf("unrecognized image type %q", manifestType))
+ newContextDir, err := ioutil.TempDir("", "buildTarball")
+ if err != nil {
+ call.ReplyErrorOccurred("unable to create tempdir")
}
+ logrus.Debugf("created new context dir at %s", newContextDir)
- if config.Memory != "" {
- memoryLimit, err = units.RAMInBytes(config.Memory)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
+ reader, err := os.Open(contextDir)
+ if err != nil {
+ logrus.Errorf("failed to open the context dir tar file %s", contextDir)
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to open context dir tar file %s", contextDir))
}
-
- if config.Memory_swap != "" {
- memorySwap, err = units.RAMInBytes(config.Memory_swap)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
+ defer reader.Close()
+ if err := archive.Untar(reader, newContextDir, &archive.TarOptions{}); err != nil {
+ logrus.Errorf("fail to untar the context dir tarball (%s) to the context dir (%s)", contextDir, newContextDir)
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to untar context dir %s", contextDir))
}
+ logrus.Debugf("untar of %s successful", contextDir)
+ // All output (stdout, stderr) is captured in output as well
output := bytes.NewBuffer([]byte{})
+
commonOpts := &buildah.CommonBuildOptions{
- AddHost: config.Add_hosts,
- CgroupParent: config.Cgroup_parent,
- CPUPeriod: uint64(config.Cpu_period),
- CPUQuota: config.Cpu_quota,
- CPUSetCPUs: config.Cpuset_cpus,
- CPUSetMems: config.Cpuset_mems,
- Memory: memoryLimit,
- MemorySwap: memorySwap,
- ShmSize: config.Shm_size,
- Ulimit: config.Ulimit,
- Volumes: config.Volume,
+ AddHost: config.BuildOptions.AddHosts,
+ CgroupParent: config.BuildOptions.CgroupParent,
+ CPUPeriod: uint64(config.BuildOptions.CpuPeriod),
+ CPUQuota: config.BuildOptions.CpuQuota,
+ CPUSetCPUs: config.BuildOptions.CpusetCpus,
+ CPUSetMems: config.BuildOptions.CpusetMems,
+ Memory: config.BuildOptions.Memory,
+ MemorySwap: config.BuildOptions.MemorySwap,
+ ShmSize: config.BuildOptions.ShmSize,
+ Ulimit: config.BuildOptions.Ulimit,
+ Volumes: config.BuildOptions.Volume,
}
hostNetwork := buildah.NamespaceOption{
@@ -196,37 +161,68 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
namespace = append(namespace, hostNetwork)
options := imagebuildah.BuildOptions{
- ContextDirectory: contextDir,
- PullPolicy: pullPolicy,
- Compression: imagebuildah.Gzip,
- Quiet: false,
- //SignaturePolicyPath:
- Args: config.Build_args,
- //Output:
- AdditionalTags: config.Tags,
- //Runtime: runtime.
- //RuntimeArgs: ,
- OutputFormat: manifestType,
- SystemContext: &systemContext,
- CommonBuildOpts: commonOpts,
- Squash: config.Squash,
- Labels: config.Label,
- Annotations: config.Annotations,
- ReportWriter: output,
- NamespaceOptions: namespace,
+ CommonBuildOpts: commonOpts,
+ AdditionalTags: config.AdditionalTags,
+ Annotations: config.Annotations,
+ Args: config.BuildArgs,
+ CNIConfigDir: config.CniConfigDir,
+ CNIPluginPath: config.CniPluginDir,
+ Compression: stringCompressionToArchiveType(config.Compression),
+ ContextDirectory: newContextDir,
+ DefaultMountsFilePath: config.DefaultsMountFilePath,
+ Err: output,
+ ForceRmIntermediateCtrs: config.ForceRmIntermediateCtrs,
+ IIDFile: config.Iidfile,
+ Labels: config.Label,
+ Layers: config.Layers,
+ NoCache: config.Nocache,
+ Out: output,
+ Output: config.Output,
+ NamespaceOptions: namespace,
+ OutputFormat: config.OutputFormat,
+ PullPolicy: stringPullPolicyToType(config.PullPolicy),
+ Quiet: config.Quiet,
+ RemoveIntermediateCtrs: config.RemoteIntermediateCtrs,
+ ReportWriter: output,
+ RuntimeArgs: config.RuntimeArgs,
+ SignaturePolicyPath: config.SignaturePolicyPath,
+ Squash: config.Squash,
+ SystemContext: &systemContext,
}
if call.WantsMore() {
call.Continues = true
}
- c := build(i.Runtime, options, config.Dockerfile)
+ var newPathDockerFiles []string
+
+ for _, d := range config.Dockerfiles {
+ if strings.HasPrefix(d, "http://") ||
+ strings.HasPrefix(d, "https://") ||
+ strings.HasPrefix(d, "git://") ||
+ strings.HasPrefix(d, "github.com/") {
+ newPathDockerFiles = append(newPathDockerFiles, d)
+ continue
+ }
+ base := filepath.Base(d)
+ newPathDockerFiles = append(newPathDockerFiles, filepath.Join(newContextDir, base))
+ }
+
+ c := build(i.Runtime, options, newPathDockerFiles)
var log []string
done := false
for {
- line, err := output.ReadString('\n')
+ outputLine, err := output.ReadString('\n')
if err == nil {
- log = append(log, line)
+ log = append(log, outputLine)
+ if call.WantsMore() {
+ // we want to reply with what we have
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyBuildImage(br)
+ log = []string{}
+ }
continue
} else if err == io.EOF {
select {
@@ -236,15 +232,10 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
}
done = true
default:
- if !call.WantsMore() {
+ if call.WantsMore() {
time.Sleep(1 * time.Second)
break
}
- br := iopodman.BuildResponse{
- Logs: log,
- }
- call.ReplyBuildImage(br)
- log = []string{}
}
} else {
return call.ReplyErrorOccurred(err.Error())
@@ -254,11 +245,12 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
}
}
call.Continues = false
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(config.Tags[0])
+
+ newImage, err := i.Runtime.ImageRuntime().NewFromLocal(config.Output)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
- br := iopodman.BuildResponse{
+ br := iopodman.MoreResponse{
Logs: log,
Id: newImage.ID(),
}
@@ -276,12 +268,6 @@ func build(runtime *libpod.Runtime, options imagebuildah.BuildOptions, dockerfil
return c
}
-// CreateImage ...
-// TODO With Pull being added, should we skip Create?
-func (i *LibpodAPI) CreateImage(call iopodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("CreateImage")
-}
-
// InspectImage returns an image's inspect information as a string that can be serialized.
// Requires an image ID or name
func (i *LibpodAPI) InspectImage(call iopodman.VarlinkCall, name string) error {
@@ -315,7 +301,7 @@ func (i *LibpodAPI) HistoryImage(call iopodman.VarlinkCall, name string) error {
for _, hist := range history {
imageHistory := iopodman.ImageHistory{
Id: hist.ID,
- Created: hist.Created.String(),
+ Created: hist.Created.Format(time.RFC3339),
CreatedBy: hist.CreatedBy,
Tags: newImage.Names(),
Size: hist.Size,
@@ -332,7 +318,6 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe
registryCreds *types.DockerAuthConfig
manifestType string
)
-
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
return call.ReplyImageNotFound(err.Error())
@@ -372,10 +357,59 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe
SignBy: signBy,
}
- if err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", signaturePolicy, nil, compress, so, &dockerRegistryOptions, nil); err != nil {
- return call.ReplyErrorOccurred(err.Error())
+ if call.WantsMore() {
+ call.Continues = true
+ }
+
+ output := bytes.NewBuffer([]byte{})
+ c := make(chan error)
+ go func() {
+ err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", signaturePolicy, output, compress, so, &dockerRegistryOptions, nil)
+ c <- err
+ close(c)
+ }()
+
+ // TODO When pull output gets fixed for the remote client, we need to look into how we can turn below
+ // into something re-usable. it is in build too
+ var log []string
+ done := false
+ for {
+ line, err := output.ReadString('\n')
+ if err == nil {
+ log = append(log, line)
+ continue
+ } else if err == io.EOF {
+ select {
+ case err := <-c:
+ if err != nil {
+ logrus.Errorf("reading of output during push failed for %s", newImage.ID())
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ done = true
+ default:
+ if !call.WantsMore() {
+ time.Sleep(1 * time.Second)
+ break
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyPushImage(br)
+ log = []string{}
+ }
+ } else {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if done {
+ break
+ }
}
- return call.ReplyPushImage(newImage.ID())
+ call.Continues = false
+
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ return call.ReplyPushImage(br)
}
// TagImage accepts an image name and tag as strings and tags an image in the local store.
@@ -405,17 +439,21 @@ func (i *LibpodAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bo
return call.ReplyRemoveImage(newImage.ID())
}
-// SearchImage searches all registries configured in /etc/containers/registries.conf for an image
+// SearchImages searches all registries configured in /etc/containers/registries.conf for an image
// Requires an image name and a search limit as int
-func (i *LibpodAPI) SearchImage(call iopodman.VarlinkCall, name string, limit int64) error {
+func (i *LibpodAPI) SearchImages(call iopodman.VarlinkCall, query string, limit *int64) error {
sc := image.GetSystemContext("", "", false)
registries, err := sysreg.GetRegistries()
if err != nil {
return call.ReplyErrorOccurred(fmt.Sprintf("unable to get system registries: %q", err))
}
- var imageResults []iopodman.ImageSearch
+ var imageResults []iopodman.ImageSearchResult
for _, reg := range registries {
- results, err := docker.SearchRegistry(getContext(), sc, reg, name, int(limit))
+ var lim = 1000
+ if limit != nil {
+ lim = int(*limit)
+ }
+ results, err := docker.SearchRegistry(getContext(), sc, reg, query, lim)
if err != nil {
// If we are searching multiple registries, don't make something like an
// auth error fatal. Unfortunately we cannot differentiate between auth
@@ -426,7 +464,7 @@ func (i *LibpodAPI) SearchImage(call iopodman.VarlinkCall, name string, limit in
return call.ReplyErrorOccurred(err.Error())
}
for _, result := range results {
- i := iopodman.ImageSearch{
+ i := iopodman.ImageSearchResult{
Description: result.Description,
Is_official: result.IsOfficial,
Is_automated: result.IsAutomated,
@@ -436,7 +474,7 @@ func (i *LibpodAPI) SearchImage(call iopodman.VarlinkCall, name string, limit in
imageResults = append(imageResults, i)
}
}
- return call.ReplySearchImage(imageResults)
+ return call.ReplySearchImages(imageResults)
}
// DeleteUnusedImages deletes any images that do not have containers associated with it.
diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go
index 376502f21..3f32615ec 100644
--- a/pkg/varlinkapi/system.go
+++ b/pkg/varlinkapi/system.go
@@ -3,6 +3,7 @@ package varlinkapi
import (
goruntime "runtime"
"strings"
+ "time"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
@@ -15,22 +16,14 @@ func (i *LibpodAPI) GetVersion(call iopodman.VarlinkCall) error {
return err
}
- return call.ReplyGetVersion(iopodman.Version{
- Remote_api_version: versionInfo.RemoteAPIVersion,
- Version: versionInfo.Version,
- Go_version: versionInfo.GoVersion,
- Git_commit: versionInfo.GitCommit,
- Built: versionInfo.Built,
- Os_arch: versionInfo.OsArch,
- })
-}
-
-// Ping returns a simple string "OK" response for clients to make sure
-// the service is working.
-func (i *LibpodAPI) Ping(call iopodman.VarlinkCall) error {
- return call.ReplyPing(iopodman.StringResponse{
- Message: "OK",
- })
+ return call.ReplyGetVersion(
+ versionInfo.Version,
+ versionInfo.GoVersion,
+ versionInfo.GitCommit,
+ time.Unix(versionInfo.Built, 0).Format(time.RFC3339),
+ versionInfo.OsArch,
+ versionInfo.RemoteAPIVersion,
+ )
}
// GetInfo returns details about the podman host and its stores
diff --git a/pkg/varlinkapi/transfers.go b/pkg/varlinkapi/transfers.go
index 0cb7e5e2e..9a97bc810 100644
--- a/pkg/varlinkapi/transfers.go
+++ b/pkg/varlinkapi/transfers.go
@@ -8,6 +8,7 @@ import (
"os"
"github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/sirupsen/logrus"
)
// SendFile allows a client to send a file to the varlink server
@@ -34,6 +35,7 @@ func (i *LibpodAPI) SendFile(call iopodman.VarlinkCall, ftype string, length int
return err
}
+ logrus.Debugf("successfully received %s", outputFile.Name())
// Send an ACK to the client
call.Call.Writer.WriteString(fmt.Sprintf("%s:", outputFile.Name()))
call.Call.Writer.Flush()
diff --git a/pkg/varlinkapi/util.go b/pkg/varlinkapi/util.go
index a80c8db41..7e487c03a 100644
--- a/pkg/varlinkapi/util.go
+++ b/pkg/varlinkapi/util.go
@@ -3,11 +3,14 @@ package varlinkapi
import (
"context"
"strconv"
+ "strings"
"time"
+ "github.com/containers/buildah"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
+ "github.com/containers/storage/pkg/archive"
)
// getContext returns a non-nil, empty context
@@ -15,7 +18,7 @@ func getContext() context.Context {
return context.TODO()
}
-func makeListContainer(containerID string, batchInfo shared.BatchContainerStruct) iopodman.ListContainerData {
+func makeListContainer(containerID string, batchInfo shared.BatchContainerStruct) iopodman.Container {
var (
mounts []iopodman.ContainerMount
ports []iopodman.ContainerPortMappings
@@ -56,12 +59,12 @@ func makeListContainer(containerID string, batchInfo shared.BatchContainerStruct
Ipc: ns.IPC,
}
- lc := iopodman.ListContainerData{
+ lc := iopodman.Container{
Id: containerID,
Image: batchInfo.ConConfig.RootfsImageName,
Imageid: batchInfo.ConConfig.RootfsImageID,
Command: batchInfo.ConConfig.Spec.Process.Args,
- Createdat: batchInfo.ConConfig.CreatedTime.String(),
+ Createdat: batchInfo.ConConfig.CreatedTime.Format(time.RFC3339),
Runningfor: time.Since(batchInfo.ConConfig.CreatedTime).String(),
Status: batchInfo.ConState.String(),
Ports: ports,
@@ -107,7 +110,7 @@ func makeListPod(pod *libpod.Pod, batchInfo shared.PsOptions) (iopodman.ListPodD
listPodsContainers = append(listPodsContainers, makeListPodContainers(ctr.ID(), batchInfo))
}
listPod := iopodman.ListPodData{
- Createdat: pod.CreatedTime().String(),
+ Createdat: pod.CreatedTime().Format(time.RFC3339),
Id: pod.ID(),
Name: pod.Name(),
Status: status,
@@ -133,3 +136,27 @@ func handlePodCall(call iopodman.VarlinkCall, pod *libpod.Pod, ctrErrs map[strin
return nil
}
+
+func stringCompressionToArchiveType(s string) archive.Compression {
+ switch strings.ToUpper(s) {
+ case "BZIP2":
+ return archive.Bzip2
+ case "GZIP":
+ return archive.Gzip
+ case "XZ":
+ return archive.Xz
+ }
+ return archive.Uncompressed
+}
+
+func stringPullPolicyToType(s string) buildah.PullPolicy {
+ switch strings.ToUpper(s) {
+ case "PULLIFMISSING":
+ return buildah.PullIfMissing
+ case "PULLALWAYS":
+ return buildah.PullAlways
+ case "PULLNEVER":
+ return buildah.PullNever
+ }
+ return buildah.PullIfMissing
+}
diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go
new file mode 100644
index 000000000..d41b07065
--- /dev/null
+++ b/pkg/varlinkapi/volumes.go
@@ -0,0 +1,74 @@
+package varlinkapi
+
+import (
+ "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/libpod"
+)
+
+// VolumeCreate creates a libpod volume based on input from a varlink connection
+func (i *LibpodAPI) VolumeCreate(call iopodman.VarlinkCall, options iopodman.VolumeCreateOpts) error {
+ var volumeOptions []libpod.VolumeCreateOption
+
+ if len(options.VolumeName) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeName(options.VolumeName))
+ }
+ if len(options.Driver) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeDriver(options.Driver))
+ }
+ if len(options.Labels) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(options.Labels))
+ }
+ if len(options.Options) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeOptions(options.Options))
+ }
+ newVolume, err := i.Runtime.NewVolume(getContext(), volumeOptions...)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ return call.ReplyVolumeCreate(newVolume.Name())
+}
+
+// VolumeRemove removes volumes by options.All or options.Volumes
+func (i *LibpodAPI) VolumeRemove(call iopodman.VarlinkCall, options iopodman.VolumeRemoveOpts) error {
+ deletedVolumes, err := i.Runtime.RemoveVolumes(getContext(), options.Volumes, options.All, options.Force)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ return call.ReplyVolumeRemove(deletedVolumes)
+}
+
+// GetVolumes returns all the volumes known to the remote system
+func (i *LibpodAPI) GetVolumes(call iopodman.VarlinkCall, args []string, all bool) error {
+ var (
+ err error
+ reply []*libpod.Volume
+ volumes []iopodman.Volume
+ )
+ if all {
+ reply, err = i.Runtime.GetAllVolumes()
+ } else {
+ for _, v := range args {
+ vol, err := i.Runtime.GetVolume(v)
+ if err != nil {
+ return err
+ }
+ reply = append(reply, vol)
+ }
+ }
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ // Build the iopodman.volume struct for the return
+ for _, v := range reply {
+ newVol := iopodman.Volume{
+ Driver: v.Driver(),
+ Labels: v.Labels(),
+ MountPoint: v.MountPoint(),
+ Name: v.Name(),
+ Options: v.Options(),
+ Scope: v.Scope(),
+ }
+ volumes = append(volumes, newVol)
+ }
+ return call.ReplyGetVolumes(volumes)
+}
diff --git a/test/bin2img/bin2img.go b/test/bin2img/bin2img.go
deleted file mode 100644
index ed493dcc1..000000000
--- a/test/bin2img/bin2img.go
+++ /dev/null
@@ -1,229 +0,0 @@
-package main
-
-import (
- "archive/tar"
- "bytes"
- "context"
- "encoding/json"
- "io"
- "os"
- "runtime"
-
- "github.com/containers/image/pkg/blobinfocache"
- "github.com/containers/image/storage"
- "github.com/containers/image/types"
- sstorage "github.com/containers/storage"
- "github.com/containers/storage/pkg/reexec"
- digest "github.com/opencontainers/go-digest"
- specs "github.com/opencontainers/image-spec/specs-go"
- "github.com/opencontainers/image-spec/specs-go/v1"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
-)
-
-func main() {
- if reexec.Init() {
- return
- }
-
- app := cli.NewApp()
- app.Name = "bin2img"
- app.Usage = "barebones image builder"
- app.Version = "0.0.1"
-
- app.Flags = []cli.Flag{
- cli.BoolFlag{
- Name: "debug",
- Usage: "turn on debug logging",
- },
- cli.StringFlag{
- Name: "root",
- Usage: "graph root directory",
- },
- cli.StringFlag{
- Name: "runroot",
- Usage: "run root directory",
- },
- cli.StringFlag{
- Name: "storage-driver",
- Usage: "storage driver",
- },
- cli.StringSliceFlag{
- Name: "storage-opt",
- Usage: "storage option",
- },
- cli.StringFlag{
- Name: "image-name",
- Usage: "set image name",
- Value: "kubernetes/pause",
- },
- cli.StringFlag{
- Name: "source-binary",
- Usage: "source binary",
- Value: "../../pause/pause",
- },
- cli.StringFlag{
- Name: "image-binary",
- Usage: "image binary",
- Value: "/pause",
- },
- }
-
- app.Action = func(c *cli.Context) error {
- debug := c.GlobalBool("debug")
- rootDir := c.GlobalString("root")
- runrootDir := c.GlobalString("runroot")
- storageDriver := c.GlobalString("storage-driver")
- storageOptions := c.GlobalStringSlice("storage-opt")
- imageName := c.GlobalString("image-name")
- sourceBinary := c.GlobalString("source-binary")
- imageBinary := c.GlobalString("image-binary")
-
- if debug {
- logrus.SetLevel(logrus.DebugLevel)
- } else {
- logrus.SetLevel(logrus.ErrorLevel)
- }
- if rootDir == "" && runrootDir != "" {
- logrus.Errorf("must set --root and --runroot, or neither")
- os.Exit(1)
- }
- if rootDir != "" && runrootDir == "" {
- logrus.Errorf("must set --root and --runroot, or neither")
- os.Exit(1)
- }
- storeOptions := sstorage.DefaultStoreOptions
- if rootDir != "" && runrootDir != "" {
- storeOptions.GraphDriverName = storageDriver
- storeOptions.GraphDriverOptions = storageOptions
- storeOptions.GraphRoot = rootDir
- storeOptions.RunRoot = runrootDir
- }
- store, err := sstorage.GetStore(storeOptions)
- if err != nil {
- logrus.Errorf("error opening storage: %v", err)
- os.Exit(1)
- }
- defer func() {
- _, _ = store.Shutdown(false)
- }()
-
- layerBuffer := &bytes.Buffer{}
- binary, err := os.Open(sourceBinary)
- if err != nil {
- logrus.Errorf("error opening image binary: %v", err)
- os.Exit(1)
- }
- binInfo, err := binary.Stat()
- if err != nil {
- logrus.Errorf("error statting image binary: %v", err)
- os.Exit(1)
- }
- archive := tar.NewWriter(layerBuffer)
- err = archive.WriteHeader(&tar.Header{
- Name: imageBinary,
- Size: binInfo.Size(),
- Mode: 0555,
- ModTime: binInfo.ModTime(),
- Typeflag: tar.TypeReg,
- Uname: "root",
- Gname: "root",
- })
- if err != nil {
- logrus.Errorf("error writing archive header: %v", err)
- os.Exit(1)
- }
- _, err = io.Copy(archive, binary)
- if err != nil {
- logrus.Errorf("error archiving image binary: %v", err)
- os.Exit(1)
- }
- archive.Close()
- binary.Close()
- layerInfo := types.BlobInfo{
- Digest: digest.Canonical.FromBytes(layerBuffer.Bytes()),
- Size: int64(layerBuffer.Len()),
- }
-
- ref, err := storage.Transport.ParseStoreReference(store, imageName)
- if err != nil {
- logrus.Errorf("error parsing image name: %v", err)
- os.Exit(1)
- }
- ctx := context.TODO()
- img, err := ref.NewImageDestination(ctx, nil)
- if err != nil {
- logrus.Errorf("error preparing to write image: %v", err)
- os.Exit(1)
- }
- defer img.Close()
- layer, err := img.PutBlob(ctx, layerBuffer, layerInfo, blobinfocache.NewMemoryCache(), false)
- if err != nil {
- logrus.Errorf("error preparing to write image: %v", err)
- os.Exit(1)
- }
- config := &v1.Image{
- Architecture: runtime.GOARCH,
- OS: runtime.GOOS,
- Config: v1.ImageConfig{
- User: "root",
- Entrypoint: []string{imageBinary},
- },
- RootFS: v1.RootFS{
- Type: "layers",
- DiffIDs: []digest.Digest{
- layer.Digest,
- },
- },
- }
- cbytes, err := json.Marshal(config)
- if err != nil {
- logrus.Errorf("error encoding configuration: %v", err)
- os.Exit(1)
- }
- configInfo := types.BlobInfo{
- Digest: digest.Canonical.FromBytes(cbytes),
- Size: int64(len(cbytes)),
- }
- configInfo, err = img.PutBlob(ctx, bytes.NewBuffer(cbytes), configInfo, blobinfocache.NewMemoryCache(), false)
- if err != nil {
- logrus.Errorf("error saving configuration: %v", err)
- os.Exit(1)
- }
- manifest := &v1.Manifest{
- Versioned: specs.Versioned{
- SchemaVersion: 2,
- },
- Config: v1.Descriptor{
- MediaType: v1.MediaTypeImageConfig,
- Digest: configInfo.Digest,
- Size: int64(len(cbytes)),
- },
- Layers: []v1.Descriptor{{
- MediaType: v1.MediaTypeImageLayer,
- Digest: layer.Digest,
- Size: layer.Size,
- }},
- }
- mbytes, err := json.Marshal(manifest)
- if err != nil {
- logrus.Errorf("error encoding manifest: %v", err)
- os.Exit(1)
- }
- err = img.PutManifest(ctx, mbytes)
- if err != nil {
- logrus.Errorf("error saving manifest: %v", err)
- os.Exit(1)
- }
- err = img.Commit(ctx)
- if err != nil {
- logrus.Errorf("error committing image: %v", err)
- os.Exit(1)
- }
- return nil
- }
-
- if err := app.Run(os.Args); err != nil {
- logrus.Fatal(err)
- }
-}
diff --git a/test/copyimg/copyimg.go b/test/copyimg/copyimg.go
deleted file mode 100644
index da00964fa..000000000
--- a/test/copyimg/copyimg.go
+++ /dev/null
@@ -1,204 +0,0 @@
-package main
-
-import (
- "context"
- "os"
-
- "github.com/containers/image/copy"
- "github.com/containers/image/signature"
- "github.com/containers/image/storage"
- "github.com/containers/image/transports/alltransports"
- "github.com/containers/image/types"
- sstorage "github.com/containers/storage"
- "github.com/containers/storage/pkg/reexec"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
-)
-
-func main() {
- if reexec.Init() {
- return
- }
-
- app := cli.NewApp()
- app.Name = "copyimg"
- app.Usage = "barebones image copier"
- app.Version = "0.0.1"
-
- app.Flags = []cli.Flag{
- cli.BoolFlag{
- Name: "debug",
- Usage: "turn on debug logging",
- },
- cli.StringFlag{
- Name: "root",
- Usage: "graph root directory",
- },
- cli.StringFlag{
- Name: "runroot",
- Usage: "run root directory",
- },
- cli.StringFlag{
- Name: "storage-driver",
- Usage: "storage driver",
- },
- cli.StringSliceFlag{
- Name: "storage-opt",
- Usage: "storage option",
- },
- cli.StringFlag{
- Name: "signature-policy",
- Usage: "signature policy",
- },
- cli.StringFlag{
- Name: "image-name",
- Usage: "set image name",
- },
- cli.StringFlag{
- Name: "add-name",
- Usage: "name to add to image",
- },
- cli.StringFlag{
- Name: "import-from",
- Usage: "import source",
- },
- cli.StringFlag{
- Name: "export-to",
- Usage: "export target",
- },
- }
-
- app.Action = func(c *cli.Context) error {
- var store sstorage.Store
- var ref, importRef, exportRef types.ImageReference
- var err error
-
- debug := c.GlobalBool("debug")
- rootDir := c.GlobalString("root")
- runrootDir := c.GlobalString("runroot")
- storageDriver := c.GlobalString("storage-driver")
- storageOptions := c.GlobalStringSlice("storage-opt")
- signaturePolicy := c.GlobalString("signature-policy")
- imageName := c.GlobalString("image-name")
- addName := c.GlobalString("add-name")
- importFrom := c.GlobalString("import-from")
- exportTo := c.GlobalString("export-to")
-
- if debug {
- logrus.SetLevel(logrus.DebugLevel)
- } else {
- logrus.SetLevel(logrus.ErrorLevel)
- }
-
- if imageName != "" {
- if rootDir == "" && runrootDir != "" {
- logrus.Errorf("must set --root and --runroot, or neither")
- os.Exit(1)
- }
- if rootDir != "" && runrootDir == "" {
- logrus.Errorf("must set --root and --runroot, or neither")
- os.Exit(1)
- }
- storeOptions := sstorage.DefaultStoreOptions
- if rootDir != "" && runrootDir != "" {
- storeOptions.GraphDriverName = storageDriver
- storeOptions.GraphDriverOptions = storageOptions
- storeOptions.GraphRoot = rootDir
- storeOptions.RunRoot = runrootDir
- }
- store, err = sstorage.GetStore(storeOptions)
- if err != nil {
- logrus.Errorf("error opening storage: %v", err)
- os.Exit(1)
- }
- defer func() {
- _, _ = store.Shutdown(false)
- }()
-
- storage.Transport.SetStore(store)
- ref, err = storage.Transport.ParseStoreReference(store, imageName)
- if err != nil {
- logrus.Errorf("error parsing image name: %v", err)
- os.Exit(1)
- }
- }
-
- systemContext := types.SystemContext{
- SignaturePolicyPath: signaturePolicy,
- }
- policy, err := signature.DefaultPolicy(&systemContext)
- if err != nil {
- logrus.Errorf("error loading signature policy: %v", err)
- os.Exit(1)
- }
- policyContext, err := signature.NewPolicyContext(policy)
- if err != nil {
- logrus.Errorf("error loading signature policy: %v", err)
- os.Exit(1)
- }
- defer func() {
- _ = policyContext.Destroy()
- }()
- options := &copy.Options{}
-
- if importFrom != "" {
- importRef, err = alltransports.ParseImageName(importFrom)
- if err != nil {
- logrus.Errorf("error parsing image name %v: %v", importFrom, err)
- os.Exit(1)
- }
- }
-
- if exportTo != "" {
- exportRef, err = alltransports.ParseImageName(exportTo)
- if err != nil {
- logrus.Errorf("error parsing image name %v: %v", exportTo, err)
- os.Exit(1)
- }
- }
-
- ctx := context.TODO()
- if imageName != "" {
- if importFrom != "" {
- _, err = copy.Image(ctx, policyContext, ref, importRef, options)
- if err != nil {
- logrus.Errorf("error importing %s: %v", importFrom, err)
- os.Exit(1)
- }
- }
- if addName != "" {
- destImage, err1 := storage.Transport.GetStoreImage(store, ref)
- if err1 != nil {
- logrus.Errorf("error finding image: %v", err1)
- os.Exit(1)
- }
- names := append(destImage.Names, imageName, addName)
- err = store.SetNames(destImage.ID, names)
- if err != nil {
- logrus.Errorf("error adding name to %s: %v", imageName, err)
- os.Exit(1)
- }
- }
- if exportTo != "" {
- _, err = copy.Image(ctx, policyContext, exportRef, ref, options)
- if err != nil {
- logrus.Errorf("error exporting %s: %v", exportTo, err)
- os.Exit(1)
- }
- }
- } else {
- if importFrom != "" && exportTo != "" {
- _, err = copy.Image(ctx, policyContext, exportRef, importRef, options)
- if err != nil {
- logrus.Errorf("error copying %s to %s: %v", importFrom, exportTo, err)
- os.Exit(1)
- }
- }
- }
- return nil
- }
-
- if err := app.Run(os.Args); err != nil {
- logrus.Fatal(err)
- }
-}
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index b28a0c428..9a526b778 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -142,7 +142,7 @@ var _ = Describe("Podman create", func() {
}
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
os.Mkdir(mountPath, 0755)
- session := podmanTest.Podman([]string{"create", "--name", "test", "--rm", "--mount", fmt.Sprintf("type=bind,src=%s,target=/create/test", mountPath), ALPINE, "grep", "/create/test", "/proc/self/mountinfo"})
+ session := podmanTest.Podman([]string{"create", "--name", "test", "--mount", fmt.Sprintf("type=bind,src=%s,target=/create/test", mountPath), ALPINE, "grep", "/create/test", "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"start", "test"})
@@ -153,7 +153,7 @@ var _ = Describe("Podman create", func() {
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("/create/test rw"))
- session = podmanTest.Podman([]string{"create", "--name", "test_ro", "--rm", "--mount", fmt.Sprintf("type=bind,src=%s,target=/create/test,ro", mountPath), ALPINE, "grep", "/create/test", "/proc/self/mountinfo"})
+ session = podmanTest.Podman([]string{"create", "--name", "test_ro", "--mount", fmt.Sprintf("type=bind,src=%s,target=/create/test,ro", mountPath), ALPINE, "grep", "/create/test", "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"start", "test_ro"})
@@ -164,7 +164,7 @@ var _ = Describe("Podman create", func() {
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("/create/test ro"))
- session = podmanTest.Podman([]string{"create", "--name", "test_shared", "--rm", "--mount", fmt.Sprintf("type=bind,src=%s,target=/create/test,shared", mountPath), ALPINE, "grep", "/create/test", "/proc/self/mountinfo"})
+ session = podmanTest.Podman([]string{"create", "--name", "test_shared", "--mount", fmt.Sprintf("type=bind,src=%s,target=/create/test,shared", mountPath), ALPINE, "grep", "/create/test", "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"start", "test_shared"})
@@ -180,7 +180,7 @@ var _ = Describe("Podman create", func() {
mountPath = filepath.Join(podmanTest.TempDir, "scratchpad")
os.Mkdir(mountPath, 0755)
- session = podmanTest.Podman([]string{"create", "--name", "test_tmpfs", "--rm", "--mount", "type=tmpfs,target=/create/test", ALPINE, "grep", "/create/test", "/proc/self/mountinfo"})
+ session = podmanTest.Podman([]string{"create", "--name", "test_tmpfs", "--mount", "type=tmpfs,target=/create/test", ALPINE, "grep", "/create/test", "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"start", "test_tmpfs"})
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 22a36bb6c..6bd49de33 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -322,7 +322,7 @@ var _ = Describe("Podman run", func() {
os.Setenv("NOTIFY_SOCKET", sock)
defer os.Unsetenv("NOTIFY_SOCKET")
- session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "printenv", "NOTIFY_SOCKET"})
+ session := podmanTest.Podman([]string{"run", ALPINE, "printenv", "NOTIFY_SOCKET"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 0))
diff --git a/utils/utils.go b/utils/utils.go
index c7c5ab5cf..4a91b304f 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -9,6 +9,7 @@ import (
systemdDbus "github.com/coreos/go-systemd/dbus"
"github.com/godbus/dbus"
+ "github.com/pkg/errors"
)
// ExecCmd executes a command with args and returns its output as a string along
@@ -82,12 +83,9 @@ func newProp(name string, units interface{}) systemdDbus.Property {
}
}
-// DetachError is special error which returned in case of container detach.
-type DetachError struct{}
-
-func (DetachError) Error() string {
- return "detached from container"
-}
+// ErrDetach is an error indicating that the user manually detached from the
+// container.
+var ErrDetach = errors.New("detached from container")
// CopyDetachable is similar to io.Copy but support a detach key sequence to break out.
func CopyDetachable(dst io.Writer, src io.Reader, keys []byte) (written int64, err error) {
@@ -108,7 +106,7 @@ func CopyDetachable(dst io.Writer, src io.Reader, keys []byte) (written int64, e
}
if i == len(keys)-1 {
// src.Close()
- return 0, DetachError{}
+ return 0, ErrDetach
}
nr, er = src.Read(buf)
}
diff --git a/vendor.conf b/vendor.conf
index 116120aa8..36452038f 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -15,8 +15,8 @@ github.com/containerd/cgroups 39b18af02c4120960f517a3a4c2588fabb61d02c
github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d
github.com/containernetworking/cni v0.7.0-alpha1
github.com/containernetworking/plugins v0.7.4
-github.com/containers/image v1.3
-github.com/containers/storage v1.9
+github.com/containers/image 93bced01015eb94bec4821df1876314be8197680
+github.com/containers/storage 06b6c2e4cf254f5922a79da058c94ac2a65bb92f
github.com/containers/psgo v1.1
github.com/coreos/go-systemd v14
github.com/cri-o/ocicni 2d2983e40c242322a56c22a903785e7f83eb378c
@@ -68,8 +68,6 @@ github.com/stretchr/testify v1.3.0
github.com/syndtr/gocapability d98352740cb2c55f81556b63d4a1ec64c5a319c2
github.com/tchap/go-patricia v2.2.6
github.com/ulule/deepcopier ca99b135e50f526fde9cd88705f0ff2f3f95b77c
-# TODO: urfave/cli is not active anymore. We should transition to another library.
-github.com/urfave/cli b67dcf995b6a7b7f14fad5fcb7cc5441b05e814b
github.com/vbatts/tar-split v0.11.1
github.com/vishvananda/netlink v1.0.0
github.com/vishvananda/netns 13995c7128ccc8e51e9a6bd2b551020a27180abd
diff --git a/vendor/github.com/containers/image/copy/copy.go b/vendor/github.com/containers/image/copy/copy.go
index 89c7e580f..2d3a2a1a8 100644
--- a/vendor/github.com/containers/image/copy/copy.go
+++ b/vendor/github.com/containers/image/copy/copy.go
@@ -6,13 +6,16 @@ import (
"fmt"
"io"
"io/ioutil"
+ "os"
"reflect"
"runtime"
"strings"
"sync"
"time"
+ "github.com/containers/image/docker/reference"
"github.com/containers/image/image"
+ "github.com/containers/image/manifest"
"github.com/containers/image/pkg/blobinfocache"
"github.com/containers/image/pkg/compression"
"github.com/containers/image/signature"
@@ -22,6 +25,7 @@ import (
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
+ "golang.org/x/crypto/ssh/terminal"
"golang.org/x/sync/semaphore"
pb "gopkg.in/cheggaaa/pb.v1"
)
@@ -84,6 +88,7 @@ type copier struct {
dest types.ImageDestination
rawSource types.ImageSource
reportWriter io.Writer
+ progressOutput io.Writer
progressInterval time.Duration
progress chan types.ProgressProperties
blobInfoCache types.BlobInfoCache
@@ -152,11 +157,19 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
}
}()
+ // If reportWriter is not a TTY (e.g., when piping to a file), do not
+ // print the progress bars to avoid long and hard to parse output.
+ // createProgressBar() will print a single line instead.
+ progressOutput := reportWriter
+ if !isTTY(reportWriter) {
+ progressOutput = ioutil.Discard
+ }
copyInParallel := dest.HasThreadSafePutBlob() && rawSource.HasThreadSafeGetBlob()
c := &copier{
dest: dest,
rawSource: rawSource,
reportWriter: reportWriter,
+ progressOutput: progressOutput,
progressInterval: options.ProgressInterval,
progress: options.Progress,
copyInParallel: copyInParallel,
@@ -201,7 +214,7 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
// Image copies a single (on-manifest-list) image unparsedImage, using policyContext to validate
// source image admissibility.
-func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.PolicyContext, options *Options, unparsedImage *image.UnparsedImage) (manifest []byte, retErr error) {
+func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.PolicyContext, options *Options, unparsedImage *image.UnparsedImage) (manifestBytes []byte, retErr error) {
// The caller is handling manifest lists; this could happen only if a manifest list contains a manifest list.
// Make sure we fail cleanly in such cases.
multiImage, err := isMultiImage(ctx, unparsedImage)
@@ -224,6 +237,26 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
return nil, errors.Wrapf(err, "Error initializing image from source %s", transports.ImageName(c.rawSource.Reference()))
}
+ // If the destination is a digested reference, make a note of that, determine what digest value we're
+ // expecting, and check that the source manifest matches it.
+ destIsDigestedReference := false
+ if named := c.dest.Reference().DockerReference(); named != nil {
+ if digested, ok := named.(reference.Digested); ok {
+ destIsDigestedReference = true
+ sourceManifest, _, err := src.Manifest(ctx)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error reading manifest from source image")
+ }
+ matches, err := manifest.MatchesDigest(sourceManifest, digested.Digest())
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error computing digest of source image's manifest")
+ }
+ if !matches {
+ return nil, errors.New("Digest of source image's manifest would not match destination reference")
+ }
+ }
+ }
+
if err := checkImageDestinationForCurrentRuntimeOS(ctx, options.DestinationCtx, src, c.dest); err != nil {
return nil, err
}
@@ -251,15 +284,15 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
manifestUpdates: &types.ManifestUpdateOptions{InformationOnly: types.ManifestUpdateInformation{Destination: c.dest}},
src: src,
// diffIDsAreNeeded is computed later
- canModifyManifest: len(sigs) == 0,
- // Ensure _this_ copy sees exactly the intended data when either processing a signed image or signing it.
- // This may be too conservative, but for now, better safe than sorry, _especially_ on the SignBy path:
- // The signature makes the content non-repudiable, so it very much matters that the signature is made over exactly what the user intended.
- // We do intend the RecordDigestUncompressedPair calls to only work with reliable data, but at least there’s a risk
- // that the compressed version coming from a third party may be designed to attack some other decompressor implementation,
- // and we would reuse and sign it.
- canSubstituteBlobs: len(sigs) == 0 && options.SignBy == "",
+ canModifyManifest: len(sigs) == 0 && !destIsDigestedReference,
}
+ // Ensure _this_ copy sees exactly the intended data when either processing a signed image or signing it.
+ // This may be too conservative, but for now, better safe than sorry, _especially_ on the SignBy path:
+ // The signature makes the content non-repudiable, so it very much matters that the signature is made over exactly what the user intended.
+ // We do intend the RecordDigestUncompressedPair calls to only work with reliable data, but at least there’s a risk
+ // that the compressed version coming from a third party may be designed to attack some other decompressor implementation,
+ // and we would reuse and sign it.
+ ic.canSubstituteBlobs = ic.canModifyManifest && options.SignBy == ""
if err := ic.updateEmbeddedDockerReference(); err != nil {
return nil, err
@@ -283,7 +316,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
// and at least with the OpenShift registry "acceptschema2" option, there is no way to detect the support
// without actually trying to upload something and getting a types.ManifestTypeRejectedError.
// So, try the preferred manifest MIME type. If the process succeeds, fine…
- manifest, err = ic.copyUpdatedConfigAndManifest(ctx)
+ manifestBytes, err = ic.copyUpdatedConfigAndManifest(ctx)
if err != nil {
logrus.Debugf("Writing manifest using preferred type %s failed: %v", preferredManifestMIMEType, err)
// … if it fails, _and_ the failure is because the manifest is rejected, we may have other options.
@@ -314,7 +347,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
}
// We have successfully uploaded a manifest.
- manifest = attemptedManifest
+ manifestBytes = attemptedManifest
errs = nil // Mark this as a success so that we don't abort below.
break
}
@@ -324,7 +357,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
}
if options.SignBy != "" {
- newSig, err := c.createSignature(manifest, options.SignBy)
+ newSig, err := c.createSignature(manifestBytes, options.SignBy)
if err != nil {
return nil, err
}
@@ -336,7 +369,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
return nil, errors.Wrap(err, "Error writing signatures")
}
- return manifest, nil
+ return manifestBytes, nil
}
// Printf writes a formatted string to c.reportWriter.
@@ -394,17 +427,30 @@ func shortDigest(d digest.Digest) string {
return d.Encoded()[:12]
}
-// createProgressBar creates a pb.ProgressBar.
-func createProgressBar(srcInfo types.BlobInfo, kind string, writer io.Writer) *pb.ProgressBar {
+// createProgressBar creates a pb.ProgressBar. Note that if the copier's
+// reportWriter is ioutil.Discard, the progress bar's output will be discarded
+// and a single line will be printed instead.
+func (c *copier) createProgressBar(srcInfo types.BlobInfo, kind string) *pb.ProgressBar {
bar := pb.New(int(srcInfo.Size)).SetUnits(pb.U_BYTES)
bar.SetMaxWidth(80)
bar.ShowTimeLeft = false
bar.ShowPercent = false
bar.Prefix(fmt.Sprintf("Copying %s %s:", kind, shortDigest(srcInfo.Digest)))
- bar.Output = writer
+ bar.Output = c.progressOutput
+ if bar.Output == ioutil.Discard {
+ c.Printf("Copying %s %s\n", kind, srcInfo.Digest)
+ }
return bar
}
+// isTTY returns true if the io.Writer is a file and a tty.
+func isTTY(w io.Writer) bool {
+ if f, ok := w.(*os.File); ok {
+ return terminal.IsTerminal(int(f.Fd()))
+ }
+ return false
+}
+
// copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.canModifyManifest.
func (ic *imageCopier) copyLayers(ctx context.Context) error {
srcInfos := ic.src.LayerInfos()
@@ -456,7 +502,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
bar.Finish()
} else {
cld.destInfo = srcLayer
- logrus.Debugf("Skipping foreign layer %q copy to %s\n", cld.destInfo.Digest, ic.c.dest.Reference().Transport().Name())
+ logrus.Debugf("Skipping foreign layer %q copy to %s", cld.destInfo.Digest, ic.c.dest.Reference().Transport().Name())
bar.Prefix(fmt.Sprintf("Skipping blob %s (foreign layer):", shortDigest(srcLayer.Digest)))
bar.Add64(bar.Total)
bar.Finish()
@@ -469,12 +515,13 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
progressBars := make([]*pb.ProgressBar, numLayers)
for i, srcInfo := range srcInfos {
- bar := createProgressBar(srcInfo, "blob", nil)
+ bar := ic.c.createProgressBar(srcInfo, "blob")
progressBars[i] = bar
}
progressPool := pb.NewPool(progressBars...)
- progressPool.Output = ic.c.reportWriter
+ progressPool.Output = ic.c.progressOutput
+
if err := progressPool.Start(); err != nil {
return errors.Wrapf(err, "error creating progress-bar pool")
}
@@ -568,7 +615,7 @@ func (c *copier) copyConfig(ctx context.Context, src types.Image) error {
if err != nil {
return errors.Wrapf(err, "Error reading config blob %s", srcInfo.Digest)
}
- bar := createProgressBar(srcInfo, "config", c.reportWriter)
+ bar := c.createProgressBar(srcInfo, "config")
defer bar.Finish()
bar.Start()
destInfo, err := c.copyBlobFromStream(ctx, bytes.NewReader(configBlob), srcInfo, nil, false, true, bar)
diff --git a/vendor/github.com/containers/image/docker/docker_client.go b/vendor/github.com/containers/image/docker/docker_client.go
index 23d2ac70f..43eb22ba2 100644
--- a/vendor/github.com/containers/image/docker/docker_client.go
+++ b/vendor/github.com/containers/image/docker/docker_client.go
@@ -91,7 +91,6 @@ type dockerClient struct {
password string
signatureBase signatureStorageBase
scope authScope
- extraScope *authScope // If non-nil, a temporary extra token scope (necessary for mounting from another repo)
// The following members are detected registry properties:
// They are set after a successful detectProperties(), and never change afterwards.
scheme string // Empty value also used to indicate detectProperties() has not yet succeeded.
@@ -282,7 +281,7 @@ func CheckAuth(ctx context.Context, sys *types.SystemContext, username, password
client.username = username
client.password = password
- resp, err := client.makeRequest(ctx, "GET", "/v2/", nil, nil, v2Auth)
+ resp, err := client.makeRequest(ctx, "GET", "/v2/", nil, nil, v2Auth, nil)
if err != nil {
return err
}
@@ -362,8 +361,8 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
q.Set("n", strconv.Itoa(limit))
u.RawQuery = q.Encode()
- logrus.Debugf("trying to talk to v1 search endpoint\n")
- resp, err := client.makeRequest(ctx, "GET", u.String(), nil, nil, noAuth)
+ logrus.Debugf("trying to talk to v1 search endpoint")
+ resp, err := client.makeRequest(ctx, "GET", u.String(), nil, nil, noAuth, nil)
if err != nil {
logrus.Debugf("error getting search results from v1 endpoint %q: %v", registry, err)
} else {
@@ -379,8 +378,8 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
}
}
- logrus.Debugf("trying to talk to v2 search endpoint\n")
- resp, err := client.makeRequest(ctx, "GET", "/v2/_catalog", nil, nil, v2Auth)
+ logrus.Debugf("trying to talk to v2 search endpoint")
+ resp, err := client.makeRequest(ctx, "GET", "/v2/_catalog", nil, nil, v2Auth, nil)
if err != nil {
logrus.Debugf("error getting search results from v2 endpoint %q: %v", registry, err)
} else {
@@ -409,20 +408,20 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
// makeRequest creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
// The host name and schema is taken from the client or autodetected, and the path is relative to it, i.e. the path usually starts with /v2/.
-func (c *dockerClient) makeRequest(ctx context.Context, method, path string, headers map[string][]string, stream io.Reader, auth sendAuth) (*http.Response, error) {
+func (c *dockerClient) makeRequest(ctx context.Context, method, path string, headers map[string][]string, stream io.Reader, auth sendAuth, extraScope *authScope) (*http.Response, error) {
if err := c.detectProperties(ctx); err != nil {
return nil, err
}
url := fmt.Sprintf("%s://%s%s", c.scheme, c.registry, path)
- return c.makeRequestToResolvedURL(ctx, method, url, headers, stream, -1, auth)
+ return c.makeRequestToResolvedURL(ctx, method, url, headers, stream, -1, auth, extraScope)
}
// makeRequestToResolvedURL creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
// streamLen, if not -1, specifies the length of the data expected on stream.
// makeRequest should generally be preferred.
// TODO(runcom): too many arguments here, use a struct
-func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url string, headers map[string][]string, stream io.Reader, streamLen int64, auth sendAuth) (*http.Response, error) {
+func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url string, headers map[string][]string, stream io.Reader, streamLen int64, auth sendAuth, extraScope *authScope) (*http.Response, error) {
req, err := http.NewRequest(method, url, stream)
if err != nil {
return nil, err
@@ -441,7 +440,7 @@ func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url
req.Header.Add("User-Agent", c.sys.DockerRegistryUserAgent)
}
if auth == v2Auth {
- if err := c.setupRequestAuth(req); err != nil {
+ if err := c.setupRequestAuth(req, extraScope); err != nil {
return nil, err
}
}
@@ -460,7 +459,7 @@ func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url
// 2) gcr.io is sending 401 without a WWW-Authenticate header in the real request
//
// debugging: https://github.com/containers/image/pull/211#issuecomment-273426236 and follows up
-func (c *dockerClient) setupRequestAuth(req *http.Request) error {
+func (c *dockerClient) setupRequestAuth(req *http.Request, extraScope *authScope) error {
if len(c.challenges) == 0 {
return nil
}
@@ -474,10 +473,10 @@ func (c *dockerClient) setupRequestAuth(req *http.Request) error {
case "bearer":
cacheKey := ""
scopes := []authScope{c.scope}
- if c.extraScope != nil {
+ if extraScope != nil {
// Using ':' as a separator here is unambiguous because getBearerToken below uses the same separator when formatting a remote request (and because repository names can't contain colons).
- cacheKey = fmt.Sprintf("%s:%s", c.extraScope.remoteName, c.extraScope.actions)
- scopes = append(scopes, *c.extraScope)
+ cacheKey = fmt.Sprintf("%s:%s", extraScope.remoteName, extraScope.actions)
+ scopes = append(scopes, *extraScope)
}
var token bearerToken
t, inCache := c.tokenCache.Load(cacheKey)
@@ -564,7 +563,7 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
ping := func(scheme string) error {
url := fmt.Sprintf(resolvedPingV2URL, scheme, c.registry)
- resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth)
+ resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
if err != nil {
logrus.Debugf("Ping %s err %s (%#v)", url, err.Error(), err)
return err
@@ -591,7 +590,7 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
// best effort to understand if we're talking to a V1 registry
pingV1 := func(scheme string) bool {
url := fmt.Sprintf(resolvedPingV1URL, scheme, c.registry)
- resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth)
+ resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
if err != nil {
logrus.Debugf("Ping %s err %s (%#v)", url, err.Error(), err)
return false
@@ -625,7 +624,7 @@ func (c *dockerClient) detectProperties(ctx context.Context) error {
// using the original data structures.
func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerReference, manifestDigest digest.Digest) (*extensionSignatureList, error) {
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(ref.ref), manifestDigest)
- res, err := c.makeRequest(ctx, "GET", path, nil, nil, v2Auth)
+ res, err := c.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/containers/image/docker/docker_image.go b/vendor/github.com/containers/image/docker/docker_image.go
index 2ab95f329..530c7513e 100644
--- a/vendor/github.com/containers/image/docker/docker_image.go
+++ b/vendor/github.com/containers/image/docker/docker_image.go
@@ -66,7 +66,7 @@ func GetRepositoryTags(ctx context.Context, sys *types.SystemContext, ref types.
tags := make([]string, 0)
for {
- res, err := client.makeRequest(ctx, "GET", path, nil, nil, v2Auth)
+ res, err := client.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/containers/image/docker/docker_image_dest.go b/vendor/github.com/containers/image/docker/docker_image_dest.go
index 973d160d0..38500dd0e 100644
--- a/vendor/github.com/containers/image/docker/docker_image_dest.go
+++ b/vendor/github.com/containers/image/docker/docker_image_dest.go
@@ -12,6 +12,7 @@ import (
"net/url"
"os"
"path/filepath"
+ "strings"
"github.com/containers/image/docker/reference"
"github.com/containers/image/manifest"
@@ -113,7 +114,7 @@ func (c *sizeCounter) Write(p []byte) (n int, err error) {
// HasThreadSafePutBlob indicates whether PutBlob can be executed concurrently.
func (d *dockerImageDestination) HasThreadSafePutBlob() bool {
- return false
+ return true
}
// PutBlob writes contents of stream and returns data representing the result (with all data filled in).
@@ -140,7 +141,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
// FIXME? Chunked upload, progress reporting, etc.
uploadPath := fmt.Sprintf(blobUploadPath, reference.Path(d.ref.ref))
logrus.Debugf("Uploading %s", uploadPath)
- res, err := d.c.makeRequest(ctx, "POST", uploadPath, nil, nil, v2Auth)
+ res, err := d.c.makeRequest(ctx, "POST", uploadPath, nil, nil, v2Auth, nil)
if err != nil {
return types.BlobInfo{}, err
}
@@ -157,7 +158,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
digester := digest.Canonical.Digester()
sizeCounter := &sizeCounter{}
tee := io.TeeReader(stream, io.MultiWriter(digester.Hash(), sizeCounter))
- res, err = d.c.makeRequestToResolvedURL(ctx, "PATCH", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, tee, inputInfo.Size, v2Auth)
+ res, err = d.c.makeRequestToResolvedURL(ctx, "PATCH", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, tee, inputInfo.Size, v2Auth, nil)
if err != nil {
logrus.Debugf("Error uploading layer chunked, response %#v", res)
return types.BlobInfo{}, err
@@ -176,7 +177,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
// TODO: check inputInfo.Digest == computedDigest https://github.com/containers/image/pull/70#discussion_r77646717
locationQuery.Set("digest", computedDigest.String())
uploadLocation.RawQuery = locationQuery.Encode()
- res, err = d.c.makeRequestToResolvedURL(ctx, "PUT", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, nil, -1, v2Auth)
+ res, err = d.c.makeRequestToResolvedURL(ctx, "PUT", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, nil, -1, v2Auth, nil)
if err != nil {
return types.BlobInfo{}, err
}
@@ -194,10 +195,10 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
// blobExists returns true iff repo contains a blob with digest, and if so, also its size.
// If the destination does not contain the blob, or it is unknown, blobExists ordinarily returns (false, -1, nil);
// it returns a non-nil error only on an unexpected failure.
-func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.Named, digest digest.Digest) (bool, int64, error) {
+func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.Named, digest digest.Digest, extraScope *authScope) (bool, int64, error) {
checkPath := fmt.Sprintf(blobsPath, reference.Path(repo), digest.String())
logrus.Debugf("Checking %s", checkPath)
- res, err := d.c.makeRequest(ctx, "HEAD", checkPath, nil, nil, v2Auth)
+ res, err := d.c.makeRequest(ctx, "HEAD", checkPath, nil, nil, v2Auth, extraScope)
if err != nil {
return false, -1, err
}
@@ -218,7 +219,7 @@ func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.
}
// mountBlob tries to mount blob srcDigest from srcRepo to the current destination.
-func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo reference.Named, srcDigest digest.Digest) error {
+func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo reference.Named, srcDigest digest.Digest, extraScope *authScope) error {
u := url.URL{
Path: fmt.Sprintf(blobUploadPath, reference.Path(d.ref.ref)),
RawQuery: url.Values{
@@ -228,7 +229,7 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
}
mountPath := u.String()
logrus.Debugf("Trying to mount %s", mountPath)
- res, err := d.c.makeRequest(ctx, "POST", mountPath, nil, nil, v2Auth)
+ res, err := d.c.makeRequest(ctx, "POST", mountPath, nil, nil, v2Auth, extraScope)
if err != nil {
return err
}
@@ -246,7 +247,7 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
return errors.Wrap(err, "Error determining upload URL after a mount attempt")
}
logrus.Debugf("... started an upload instead of mounting, trying to cancel at %s", uploadLocation.String())
- res2, err := d.c.makeRequestToResolvedURL(ctx, "DELETE", uploadLocation.String(), nil, nil, -1, v2Auth)
+ res2, err := d.c.makeRequestToResolvedURL(ctx, "DELETE", uploadLocation.String(), nil, nil, -1, v2Auth, extraScope)
if err != nil {
logrus.Debugf("Error trying to cancel an inadvertent upload: %s", err)
} else {
@@ -276,7 +277,7 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
}
// First, check whether the blob happens to already exist at the destination.
- exists, size, err := d.blobExists(ctx, d.ref.ref, info.Digest)
+ exists, size, err := d.blobExists(ctx, d.ref.ref, info.Digest, nil)
if err != nil {
return false, types.BlobInfo{}, err
}
@@ -286,15 +287,6 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
}
// Then try reusing blobs from other locations.
-
- // Checking candidateRepo, and mounting from it, requires an expanded token scope.
- // We still want to reuse the ping information and other aspects of the client, so rather than make a fresh copy, there is this a bit ugly extraScope hack.
- if d.c.extraScope != nil {
- return false, types.BlobInfo{}, errors.New("Internal error: dockerClient.extraScope was set before TryReusingBlob")
- }
- defer func() {
- d.c.extraScope = nil
- }()
for _, candidate := range cache.CandidateLocations(d.ref.Transport(), bicTransportScope(d.ref), info.Digest, canSubstitute) {
candidateRepo, err := parseBICLocationReference(candidate.Location)
if err != nil {
@@ -314,7 +306,10 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
}
// Whatever happens here, don't abort the entire operation. It's likely we just don't have permissions, and if it is a critical network error, we will find out soon enough anyway.
- d.c.extraScope = &authScope{
+
+ // Checking candidateRepo, and mounting from it, requires an
+ // expanded token scope.
+ extraScope := &authScope{
remoteName: reference.Path(candidateRepo),
actions: "pull",
}
@@ -325,7 +320,7 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
// Even worse, docker/distribution does not actually reasonably implement canceling uploads
// (it would require a "delete" action in the token, and Quay does not give that to anyone, so we can't ask);
// so, be a nice client and don't create unnecesary upload sessions on the server.
- exists, size, err := d.blobExists(ctx, candidateRepo, candidate.Digest)
+ exists, size, err := d.blobExists(ctx, candidateRepo, candidate.Digest, extraScope)
if err != nil {
logrus.Debugf("... Failed: %v", err)
continue
@@ -335,7 +330,7 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
continue // logrus.Debug() already happened in blobExists
}
if candidateRepo.Name() != d.ref.ref.Name() {
- if err := d.mountBlob(ctx, candidateRepo, candidate.Digest); err != nil {
+ if err := d.mountBlob(ctx, candidateRepo, candidate.Digest, extraScope); err != nil {
logrus.Debugf("... Mount failed: %v", err)
continue
}
@@ -369,7 +364,7 @@ func (d *dockerImageDestination) PutManifest(ctx context.Context, m []byte) erro
if mimeType != "" {
headers["Content-Type"] = []string{mimeType}
}
- res, err := d.c.makeRequest(ctx, "PUT", path, headers, bytes.NewReader(m), v2Auth)
+ res, err := d.c.makeRequest(ctx, "PUT", path, headers, bytes.NewReader(m), v2Auth, nil)
if err != nil {
return err
}
@@ -396,14 +391,29 @@ func isManifestInvalidError(err error) bool {
if !ok || len(errors) == 0 {
return false
}
- ec, ok := errors[0].(errcode.ErrorCoder)
+ err = errors[0]
+ ec, ok := err.(errcode.ErrorCoder)
if !ok {
return false
}
+
+ switch ec.ErrorCode() {
// ErrorCodeManifestInvalid is returned by OpenShift with acceptschema2=false.
+ case v2.ErrorCodeManifestInvalid:
+ return true
// ErrorCodeTagInvalid is returned by docker/distribution (at least as of commit ec87e9b6971d831f0eff752ddb54fb64693e51cd)
// when uploading to a tag (because it can’t find a matching tag inside the manifest)
- return ec.ErrorCode() == v2.ErrorCodeManifestInvalid || ec.ErrorCode() == v2.ErrorCodeTagInvalid
+ case v2.ErrorCodeTagInvalid:
+ return true
+ // ErrorCodeUnsupported with 'Invalid JSON syntax' is returned by AWS ECR when
+ // uploading an OCI manifest that is (correctly, according to the spec) missing
+ // a top-level media type. See libpod issue #1719
+ // FIXME: remove this case when ECR behavior is fixed
+ case errcode.ErrorCodeUnsupported:
+ return strings.Contains(err.Error(), "Invalid JSON syntax")
+ default:
+ return false
+ }
}
func (d *dockerImageDestination) PutSignatures(ctx context.Context, signatures [][]byte) error {
@@ -574,7 +584,7 @@ sigExists:
}
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(d.ref.ref), d.manifestDigest.String())
- res, err := d.c.makeRequest(ctx, "PUT", path, nil, bytes.NewReader(body), v2Auth)
+ res, err := d.c.makeRequest(ctx, "PUT", path, nil, bytes.NewReader(body), v2Auth, nil)
if err != nil {
return err
}
diff --git a/vendor/github.com/containers/image/docker/docker_image_src.go b/vendor/github.com/containers/image/docker/docker_image_src.go
index c88ff2f34..8367792bf 100644
--- a/vendor/github.com/containers/image/docker/docker_image_src.go
+++ b/vendor/github.com/containers/image/docker/docker_image_src.go
@@ -89,7 +89,7 @@ func (s *dockerImageSource) fetchManifest(ctx context.Context, tagOrDigest strin
path := fmt.Sprintf(manifestPath, reference.Path(s.ref.ref), tagOrDigest)
headers := make(map[string][]string)
headers["Accept"] = manifest.DefaultRequestedManifestMIMETypes
- res, err := s.c.makeRequest(ctx, "GET", path, headers, nil, v2Auth)
+ res, err := s.c.makeRequest(ctx, "GET", path, headers, nil, v2Auth, nil)
if err != nil {
return nil, "", err
}
@@ -137,7 +137,7 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
err error
)
for _, url := range urls {
- resp, err = s.c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth)
+ resp, err = s.c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
if err == nil {
if resp.StatusCode != http.StatusOK {
err = errors.Errorf("error fetching external blob from %q: %d (%s)", url, resp.StatusCode, http.StatusText(resp.StatusCode))
@@ -147,10 +147,10 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
break
}
}
- if resp.Body != nil && err == nil {
- return resp.Body, getBlobSize(resp), nil
+ if err != nil {
+ return nil, 0, err
}
- return nil, 0, err
+ return resp.Body, getBlobSize(resp), nil
}
func getBlobSize(resp *http.Response) int64 {
@@ -176,7 +176,7 @@ func (s *dockerImageSource) GetBlob(ctx context.Context, info types.BlobInfo, ca
path := fmt.Sprintf(blobsPath, reference.Path(s.ref.ref), info.Digest.String())
logrus.Debugf("Downloading %s", path)
- res, err := s.c.makeRequest(ctx, "GET", path, nil, nil, v2Auth)
+ res, err := s.c.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
if err != nil {
return nil, 0, err
}
@@ -340,7 +340,7 @@ func deleteImage(ctx context.Context, sys *types.SystemContext, ref dockerRefere
return err
}
getPath := fmt.Sprintf(manifestPath, reference.Path(ref.ref), refTail)
- get, err := c.makeRequest(ctx, "GET", getPath, headers, nil, v2Auth)
+ get, err := c.makeRequest(ctx, "GET", getPath, headers, nil, v2Auth, nil)
if err != nil {
return err
}
@@ -362,7 +362,7 @@ func deleteImage(ctx context.Context, sys *types.SystemContext, ref dockerRefere
// When retrieving the digest from a registry >= 2.3 use the following header:
// "Accept": "application/vnd.docker.distribution.manifest.v2+json"
- delete, err := c.makeRequest(ctx, "DELETE", deletePath, headers, nil, v2Auth)
+ delete, err := c.makeRequest(ctx, "DELETE", deletePath, headers, nil, v2Auth, nil)
if err != nil {
return err
}
diff --git a/vendor/github.com/containers/image/docker/tarfile/src.go b/vendor/github.com/containers/image/docker/tarfile/src.go
index 889e5f8e8..03735f8a4 100644
--- a/vendor/github.com/containers/image/docker/tarfile/src.go
+++ b/vendor/github.com/containers/image/docker/tarfile/src.go
@@ -9,6 +9,7 @@ import (
"io/ioutil"
"os"
"path"
+ "sync"
"github.com/containers/image/internal/tmpdir"
"github.com/containers/image/manifest"
@@ -21,8 +22,10 @@ import (
// Source is a partial implementation of types.ImageSource for reading from tarPath.
type Source struct {
tarPath string
- removeTarPathOnClose bool // Remove temp file on close if true
+ removeTarPathOnClose bool // Remove temp file on close if true
+ cacheDataLock sync.Once // Atomic way to ensure that ensureCachedDataIsPresent is only invoked once
// The following data is only available after ensureCachedDataIsPresent() succeeds
+ cacheDataResult error // The return value of ensureCachedDataIsPresent, since it should be as safe to cache as the side effects
tarManifest *ManifestItem // nil if not available yet.
configBytes []byte
configDigest digest.Digest
@@ -199,43 +202,46 @@ func (s *Source) readTarComponent(path string) ([]byte, error) {
// ensureCachedDataIsPresent loads data necessary for any of the public accessors.
func (s *Source) ensureCachedDataIsPresent() error {
- if s.tarManifest != nil {
- return nil
- }
-
- // Read and parse manifest.json
- tarManifest, err := s.loadTarManifest()
- if err != nil {
- return err
- }
+ s.cacheDataLock.Do(func() {
+ // Read and parse manifest.json
+ tarManifest, err := s.loadTarManifest()
+ if err != nil {
+ s.cacheDataResult = err
+ return
+ }
- // Check to make sure length is 1
- if len(tarManifest) != 1 {
- return errors.Errorf("Unexpected tar manifest.json: expected 1 item, got %d", len(tarManifest))
- }
+ // Check to make sure length is 1
+ if len(tarManifest) != 1 {
+ s.cacheDataResult = errors.Errorf("Unexpected tar manifest.json: expected 1 item, got %d", len(tarManifest))
+ return
+ }
- // Read and parse config.
- configBytes, err := s.readTarComponent(tarManifest[0].Config)
- if err != nil {
- return err
- }
- var parsedConfig manifest.Schema2Image // There's a lot of info there, but we only really care about layer DiffIDs.
- if err := json.Unmarshal(configBytes, &parsedConfig); err != nil {
- return errors.Wrapf(err, "Error decoding tar config %s", tarManifest[0].Config)
- }
+ // Read and parse config.
+ configBytes, err := s.readTarComponent(tarManifest[0].Config)
+ if err != nil {
+ s.cacheDataResult = err
+ return
+ }
+ var parsedConfig manifest.Schema2Image // There's a lot of info there, but we only really care about layer DiffIDs.
+ if err := json.Unmarshal(configBytes, &parsedConfig); err != nil {
+ s.cacheDataResult = errors.Wrapf(err, "Error decoding tar config %s", tarManifest[0].Config)
+ return
+ }
- knownLayers, err := s.prepareLayerData(&tarManifest[0], &parsedConfig)
- if err != nil {
- return err
- }
+ knownLayers, err := s.prepareLayerData(&tarManifest[0], &parsedConfig)
+ if err != nil {
+ s.cacheDataResult = err
+ return
+ }
- // Success; commit.
- s.tarManifest = &tarManifest[0]
- s.configBytes = configBytes
- s.configDigest = digest.FromBytes(configBytes)
- s.orderedDiffIDList = parsedConfig.RootFS.DiffIDs
- s.knownLayers = knownLayers
- return nil
+ // Success; commit.
+ s.tarManifest = &tarManifest[0]
+ s.configBytes = configBytes
+ s.configDigest = digest.FromBytes(configBytes)
+ s.orderedDiffIDList = parsedConfig.RootFS.DiffIDs
+ s.knownLayers = knownLayers
+ })
+ return s.cacheDataResult
}
// loadTarManifest loads and decodes the manifest.json.
@@ -399,7 +405,7 @@ func (r uncompressedReadCloser) Close() error {
// HasThreadSafeGetBlob indicates whether GetBlob can be executed concurrently.
func (s *Source) HasThreadSafeGetBlob() bool {
- return false
+ return true
}
// GetBlob returns a stream for the specified blob, and the blob’s size (or -1 if unknown).
diff --git a/vendor/github.com/containers/image/ostree/ostree_src.go b/vendor/github.com/containers/image/ostree/ostree_src.go
index df432c9f3..35d852139 100644
--- a/vendor/github.com/containers/image/ostree/ostree_src.go
+++ b/vendor/github.com/containers/image/ostree/ostree_src.go
@@ -17,7 +17,7 @@ import (
"github.com/containers/image/types"
"github.com/containers/storage/pkg/ioutils"
"github.com/klauspost/pgzip"
- "github.com/opencontainers/go-digest"
+ digest "github.com/opencontainers/go-digest"
glib "github.com/ostreedev/ostree-go/pkg/glibobject"
"github.com/pkg/errors"
"github.com/vbatts/tar-split/tar/asm"
@@ -313,24 +313,19 @@ func (s *ostreeImageSource) GetBlob(ctx context.Context, info types.BlobInfo, ca
if err != nil {
return nil, 0, err
}
- defer mfz.Close()
metaUnpacker := storage.NewJSONUnpacker(mfz)
getter, err := newOSTreePathFileGetter(s.repo, branch)
if err != nil {
+ mfz.Close()
return nil, 0, err
}
ots := asm.NewOutputTarStream(getter, metaUnpacker)
- pipeReader, pipeWriter := io.Pipe()
- go func() {
- io.Copy(pipeWriter, ots)
- pipeWriter.Close()
- }()
-
- rc := ioutils.NewReadCloserWrapper(pipeReader, func() error {
+ rc := ioutils.NewReadCloserWrapper(ots, func() error {
getter.Close()
+ mfz.Close()
return ots.Close()
})
return rc, layerSize, nil
diff --git a/vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go b/vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
index 9e3e9cfe1..3d0bb0df2 100644
--- a/vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
+++ b/vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
@@ -53,20 +53,23 @@ type Registry struct {
Prefix string `toml:"prefix"`
}
-// backwards compatability to sysregistries v1
-type v1TOMLregistries struct {
+// V1TOMLregistries is for backwards compatibility to sysregistries v1
+type V1TOMLregistries struct {
Registries []string `toml:"registries"`
}
+// V1TOMLConfig is for backwards compatibility to sysregistries v1
+type V1TOMLConfig struct {
+ Search V1TOMLregistries `toml:"search"`
+ Insecure V1TOMLregistries `toml:"insecure"`
+ Block V1TOMLregistries `toml:"block"`
+}
+
// tomlConfig is the data type used to unmarshal the toml config.
type tomlConfig struct {
Registries []Registry `toml:"registry"`
// backwards compatability to sysregistries v1
- V1Registries struct {
- Search v1TOMLregistries `toml:"search"`
- Insecure v1TOMLregistries `toml:"insecure"`
- Block v1TOMLregistries `toml:"block"`
- } `toml:"registries"`
+ V1TOMLConfig `toml:"registries"`
}
// InvalidRegistries represents an invalid registry configurations. An example
@@ -129,21 +132,21 @@ func getV1Registries(config *tomlConfig) ([]Registry, error) {
// Note: config.V1Registries.Search needs to be processed first to ensure registryOrder is populated in the right order
// if one of the search registries is also in one of the other lists.
- for _, search := range config.V1Registries.Search.Registries {
+ for _, search := range config.V1TOMLConfig.Search.Registries {
reg, err := getRegistry(search)
if err != nil {
return nil, err
}
reg.Search = true
}
- for _, blocked := range config.V1Registries.Block.Registries {
+ for _, blocked := range config.V1TOMLConfig.Block.Registries {
reg, err := getRegistry(blocked)
if err != nil {
return nil, err
}
reg.Blocked = true
}
- for _, insecure := range config.V1Registries.Insecure.Registries {
+ for _, insecure := range config.V1TOMLConfig.Insecure.Registries {
reg, err := getRegistry(insecure)
if err != nil {
return nil, err
diff --git a/vendor/github.com/containers/image/storage/storage_image.go b/vendor/github.com/containers/image/storage/storage_image.go
index b53fbdf6e..67dc6142b 100644
--- a/vendor/github.com/containers/image/storage/storage_image.go
+++ b/vendor/github.com/containers/image/storage/storage_image.go
@@ -14,6 +14,7 @@ import (
"sync"
"sync/atomic"
+ "github.com/containers/image/docker/reference"
"github.com/containers/image/image"
"github.com/containers/image/internal/tmpdir"
"github.com/containers/image/manifest"
@@ -70,6 +71,13 @@ type storageImageCloser struct {
size int64
}
+// manifestBigDataKey returns a key suitable for recording a manifest with the specified digest using storage.Store.ImageBigData and related functions.
+// If a specific manifest digest is explicitly requested by the user, the key retruned function should be used preferably;
+// for compatibility, if a manifest is not available under this key, check also storage.ImageDigestBigDataKey
+func manifestBigDataKey(digest digest.Digest) string {
+ return storage.ImageDigestManifestBigDataNamePrefix + "-" + digest.String()
+}
+
// newImageSource sets up an image for reading.
func newImageSource(imageRef storageReference) (*storageImageSource, error) {
// First, locate the image.
@@ -177,12 +185,29 @@ func (s *storageImageSource) GetManifest(ctx context.Context, instanceDigest *di
return nil, "", ErrNoManifestLists
}
if len(s.cachedManifest) == 0 {
- // We stored the manifest as an item named after storage.ImageDigestBigDataKey.
- cachedBlob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, storage.ImageDigestBigDataKey)
- if err != nil {
- return nil, "", err
+ // The manifest is stored as a big data item.
+ // Prefer the manifest corresponding to the user-specified digest, if available.
+ if s.imageRef.named != nil {
+ if digested, ok := s.imageRef.named.(reference.Digested); ok {
+ key := manifestBigDataKey(digested.Digest())
+ blob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, key)
+ if err != nil && !os.IsNotExist(err) { // os.IsNotExist is true if the image exists but there is no data corresponding to key
+ return nil, "", err
+ }
+ if err == nil {
+ s.cachedManifest = blob
+ }
+ }
+ }
+ // If the user did not specify a digest, or this is an old image stored before manifestBigDataKey was introduced, use the default manifest.
+ // Note that the manifest may not match the expected digest, and that is likely to fail eventually, e.g. in c/image/image/UnparsedImage.Manifest().
+ if len(s.cachedManifest) == 0 {
+ cachedBlob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, storage.ImageDigestBigDataKey)
+ if err != nil {
+ return nil, "", err
+ }
+ s.cachedManifest = cachedBlob
}
- s.cachedManifest = cachedBlob
}
return s.cachedManifest, manifest.GuessMIMEType(s.cachedManifest), err
}
@@ -660,6 +685,7 @@ func (s *storageImageDestination) Commit(ctx context.Context) error {
}
lastLayer = layer.ID
}
+
// If one of those blobs was a configuration blob, then we can try to dig out the date when the image
// was originally created, in case we're just copying it. If not, no harm done.
options := &storage.ImageOptions{}
@@ -667,9 +693,6 @@ func (s *storageImageDestination) Commit(ctx context.Context) error {
logrus.Debugf("setting image creation date to %s", inspect.Created)
options.CreationDate = *inspect.Created
}
- if manifestDigest, err := manifest.Digest(s.manifest); err == nil {
- options.Digest = manifestDigest
- }
// Create the image record, pointing to the most-recently added layer.
intendedID := s.imageRef.id
if intendedID == "" {
@@ -735,8 +758,20 @@ func (s *storageImageDestination) Commit(ctx context.Context) error {
}
logrus.Debugf("set names of image %q to %v", img.ID, names)
}
- // Save the manifest. Use storage.ImageDigestBigDataKey as the item's
- // name, so that its digest can be used to locate the image in the Store.
+ // Save the manifest. Allow looking it up by digest by using the key convention defined by the Store.
+ // Record the manifest twice: using a digest-specific key to allow references to that specific digest instance,
+ // and using storage.ImageDigestBigDataKey for future users that don’t specify any digest and for compatibility with older readers.
+ manifestDigest, err := manifest.Digest(s.manifest)
+ if err != nil {
+ return errors.Wrapf(err, "error computing manifest digest")
+ }
+ if err := s.imageRef.transport.store.SetImageBigData(img.ID, manifestBigDataKey(manifestDigest), s.manifest); err != nil {
+ if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
+ logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
+ }
+ logrus.Debugf("error saving manifest for image %q: %v", img.ID, err)
+ return err
+ }
if err := s.imageRef.transport.store.SetImageBigData(img.ID, storage.ImageDigestBigDataKey, s.manifest); err != nil {
if _, err2 := s.imageRef.transport.store.DeleteImage(img.ID, true); err2 != nil {
logrus.Debugf("error deleting incomplete image %q: %v", img.ID, err2)
@@ -788,9 +823,21 @@ func (s *storageImageDestination) SupportedManifestMIMETypes() []string {
}
// PutManifest writes the manifest to the destination.
-func (s *storageImageDestination) PutManifest(ctx context.Context, manifest []byte) error {
- s.manifest = make([]byte, len(manifest))
- copy(s.manifest, manifest)
+func (s *storageImageDestination) PutManifest(ctx context.Context, manifestBlob []byte) error {
+ if s.imageRef.named != nil {
+ if digested, ok := s.imageRef.named.(reference.Digested); ok {
+ matches, err := manifest.MatchesDigest(manifestBlob, digested.Digest())
+ if err != nil {
+ return err
+ }
+ if !matches {
+ return fmt.Errorf("Manifest does not match expected digest %s", digested.Digest())
+ }
+ }
+ }
+
+ s.manifest = make([]byte, len(manifestBlob))
+ copy(s.manifest, manifestBlob)
return nil
}
diff --git a/vendor/github.com/containers/image/storage/storage_reference.go b/vendor/github.com/containers/image/storage/storage_reference.go
index 73306b972..c046d9f22 100644
--- a/vendor/github.com/containers/image/storage/storage_reference.go
+++ b/vendor/github.com/containers/image/storage/storage_reference.go
@@ -55,7 +55,7 @@ func imageMatchesRepo(image *storage.Image, ref reference.Named) bool {
// one present with the same name or ID, and return the image.
func (s *storageReference) resolveImage() (*storage.Image, error) {
var loadedImage *storage.Image
- if s.id == "" {
+ if s.id == "" && s.named != nil {
// Look for an image that has the expanded reference name as an explicit Name value.
image, err := s.transport.store.Image(s.named.String())
if image != nil && err == nil {
@@ -69,7 +69,7 @@ func (s *storageReference) resolveImage() (*storage.Image, error) {
// though possibly with a different tag or digest, as a Name value, so
// that the canonical reference can be implicitly resolved to the image.
images, err := s.transport.store.ImagesByDigest(digested.Digest())
- if images != nil && err == nil {
+ if err == nil && len(images) > 0 {
for _, image := range images {
if imageMatchesRepo(image, s.named) {
loadedImage = image
@@ -97,6 +97,24 @@ func (s *storageReference) resolveImage() (*storage.Image, error) {
return nil, ErrNoSuchImage
}
}
+ // Default to having the image digest that we hand back match the most recently
+ // added manifest...
+ if digest, ok := loadedImage.BigDataDigests[storage.ImageDigestBigDataKey]; ok {
+ loadedImage.Digest = digest
+ }
+ // ... unless the named reference says otherwise, and it matches one of the digests
+ // in the image. For those cases, set the Digest field to that value, for the
+ // sake of older consumers that don't know there's a whole list in there now.
+ if s.named != nil {
+ if digested, ok := s.named.(reference.Digested); ok {
+ for _, digest := range loadedImage.Digests {
+ if digest == digested.Digest() {
+ loadedImage.Digest = digest
+ break
+ }
+ }
+ }
+ }
return loadedImage, nil
}
diff --git a/vendor/github.com/containers/image/storage/storage_transport.go b/vendor/github.com/containers/image/storage/storage_transport.go
index b53c389bd..02d2f5c08 100644
--- a/vendor/github.com/containers/image/storage/storage_transport.go
+++ b/vendor/github.com/containers/image/storage/storage_transport.go
@@ -284,11 +284,6 @@ func (s storageTransport) GetStoreImage(store storage.Store, ref types.ImageRefe
}
}
if sref, ok := ref.(*storageReference); ok {
- if sref.id != "" {
- if img, err := store.Image(sref.id); err == nil {
- return img, nil
- }
- }
tmpRef := *sref
if img, err := tmpRef.resolveImage(); err == nil {
return img, nil
diff --git a/vendor/github.com/containers/image/version/version.go b/vendor/github.com/containers/image/version/version.go
index 6644bcff3..10075992d 100644
--- a/vendor/github.com/containers/image/version/version.go
+++ b/vendor/github.com/containers/image/version/version.go
@@ -8,7 +8,7 @@ const (
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 1
// VersionPatch is for backwards-compatible bug fixes
- VersionPatch = 0
+ VersionPatch = 5
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = "-dev"
diff --git a/vendor/github.com/containers/storage/images.go b/vendor/github.com/containers/storage/images.go
index d99842534..fa4a7c43b 100644
--- a/vendor/github.com/containers/storage/images.go
+++ b/vendor/github.com/containers/storage/images.go
@@ -5,8 +5,10 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "strings"
"time"
+ "github.com/containers/image/manifest"
"github.com/containers/storage/pkg/ioutils"
"github.com/containers/storage/pkg/stringid"
"github.com/containers/storage/pkg/truncindex"
@@ -15,9 +17,13 @@ import (
)
const (
- // ImageDigestBigDataKey is the name of the big data item whose
- // contents we consider useful for computing a "digest" of the
- // image, by which we can locate the image later.
+ // ImageDigestManifestBigDataNamePrefix is a prefix of big data item
+ // names which we consider to be manifests, used for computing a
+ // "digest" value for the image as a whole, by which we can locate the
+ // image later.
+ ImageDigestManifestBigDataNamePrefix = "manifest"
+ // ImageDigestBigDataKey is provided for compatibility with older
+ // versions of the image library. It will be removed in the future.
ImageDigestBigDataKey = "manifest"
)
@@ -27,12 +33,19 @@ type Image struct {
// value which was generated by the library.
ID string `json:"id"`
- // Digest is a digest value that we can use to locate the image.
+ // Digest is a digest value that we can use to locate the image, if one
+ // was specified at creation-time.
Digest digest.Digest `json:"digest,omitempty"`
+ // Digests is a list of digest values of the image's manifests, and
+ // possibly a manually-specified value, that we can use to locate the
+ // image. If Digest is set, its value is also in this list.
+ Digests []digest.Digest `json:"-"`
+
// Names is an optional set of user-defined convenience values. The
// image can be referred to by its ID or any of its names. Names are
- // unique among images.
+ // unique among images, and are often the text representation of tagged
+ // or canonical references.
Names []string `json:"names,omitempty"`
// TopLayer is the ID of the topmost layer of the image itself, if the
@@ -92,8 +105,10 @@ type ROImageStore interface {
// Images returns a slice enumerating the known images.
Images() ([]Image, error)
- // Images returns a slice enumerating the images which have a big data
- // item with the name ImageDigestBigDataKey and the specified digest.
+ // ByDigest returns a slice enumerating the images which have either an
+ // explicitly-set digest, or a big data item with a name that starts
+ // with ImageDigestManifestBigDataNamePrefix, which matches the
+ // specified digest.
ByDigest(d digest.Digest) ([]*Image, error)
}
@@ -111,7 +126,8 @@ type ImageStore interface {
Create(id string, names []string, layer, metadata string, created time.Time, searchableDigest digest.Digest) (*Image, error)
// SetNames replaces the list of names associated with an image with the
- // supplied values.
+ // supplied values. The values are expected to be valid normalized
+ // named image references.
SetNames(id string, names []string) error
// Delete removes the record of the image.
@@ -135,6 +151,7 @@ func copyImage(i *Image) *Image {
return &Image{
ID: i.ID,
Digest: i.Digest,
+ Digests: copyDigestSlice(i.Digests),
Names: copyStringSlice(i.Names),
TopLayer: i.TopLayer,
MappedTopLayers: copyStringSlice(i.MappedTopLayers),
@@ -147,6 +164,17 @@ func copyImage(i *Image) *Image {
}
}
+func copyImageSlice(slice []*Image) []*Image {
+ if len(slice) > 0 {
+ cp := make([]*Image, len(slice))
+ for i := range slice {
+ cp[i] = copyImage(slice[i])
+ }
+ return cp
+ }
+ return nil
+}
+
func (r *imageStore) Images() ([]Image, error) {
images := make([]Image, len(r.images))
for i := range r.images {
@@ -167,6 +195,46 @@ func (r *imageStore) datapath(id, key string) string {
return filepath.Join(r.datadir(id), makeBigDataBaseName(key))
}
+// bigDataNameIsManifest determines if a big data item with the specified name
+// is considered to be representative of the image, in that its digest can be
+// said to also be the image's digest. Currently, if its name is, or begins
+// with, "manifest", we say that it is.
+func bigDataNameIsManifest(name string) bool {
+ return strings.HasPrefix(name, ImageDigestManifestBigDataNamePrefix)
+}
+
+// recomputeDigests takes a fixed digest and a name-to-digest map and builds a
+// list of the unique values that would identify the image.
+func (image *Image) recomputeDigests() error {
+ validDigests := make([]digest.Digest, 0, len(image.BigDataDigests)+1)
+ digests := make(map[digest.Digest]struct{})
+ if image.Digest != "" {
+ if err := image.Digest.Validate(); err != nil {
+ return errors.Wrapf(err, "error validating image digest %q", string(image.Digest))
+ }
+ digests[image.Digest] = struct{}{}
+ validDigests = append(validDigests, image.Digest)
+ }
+ for name, digest := range image.BigDataDigests {
+ if !bigDataNameIsManifest(name) {
+ continue
+ }
+ if digest.Validate() != nil {
+ return errors.Wrapf(digest.Validate(), "error validating digest %q for big data item %q", string(digest), name)
+ }
+ // Deduplicate the digest values.
+ if _, known := digests[digest]; !known {
+ digests[digest] = struct{}{}
+ validDigests = append(validDigests, digest)
+ }
+ }
+ if image.Digest == "" && len(validDigests) > 0 {
+ image.Digest = validDigests[0]
+ }
+ image.Digests = validDigests
+ return nil
+}
+
func (r *imageStore) Load() error {
shouldSave := false
rpath := r.imagespath()
@@ -189,17 +257,18 @@ func (r *imageStore) Load() error {
r.removeName(conflict, name)
shouldSave = true
}
- names[name] = images[n]
}
- // Implicit digest
- if digest, ok := image.BigDataDigests[ImageDigestBigDataKey]; ok {
- digests[digest] = append(digests[digest], images[n])
+ // Compute the digest list.
+ err = image.recomputeDigests()
+ if err != nil {
+ return errors.Wrapf(err, "error computing digests for image with ID %q (%v)", image.ID, image.Names)
}
- // Explicit digest
- if image.Digest == "" {
- image.Digest = image.BigDataDigests[ImageDigestBigDataKey]
- } else if image.Digest != image.BigDataDigests[ImageDigestBigDataKey] {
- digests[image.Digest] = append(digests[image.Digest], images[n])
+ for _, name := range image.Names {
+ names[name] = image
+ }
+ for _, digest := range image.Digests {
+ list := digests[digest]
+ digests[digest] = append(list, image)
}
}
}
@@ -333,12 +402,12 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c
}
}
if _, idInUse := r.byid[id]; idInUse {
- return nil, ErrDuplicateID
+ return nil, errors.Wrapf(ErrDuplicateID, "an image with ID %q already exists", id)
}
names = dedupeNames(names)
for _, name := range names {
- if _, nameInUse := r.byname[name]; nameInUse {
- return nil, ErrDuplicateName
+ if image, nameInUse := r.byname[name]; nameInUse {
+ return nil, errors.Wrapf(ErrDuplicateName, "image name %q is already associated with image %q", name, image.ID)
}
}
if created.IsZero() {
@@ -348,6 +417,7 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c
image = &Image{
ID: id,
Digest: searchableDigest,
+ Digests: nil,
Names: names,
TopLayer: layer,
Metadata: metadata,
@@ -357,16 +427,20 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c
Created: created,
Flags: make(map[string]interface{}),
}
+ err := image.recomputeDigests()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error validating digests for new image")
+ }
r.images = append(r.images, image)
r.idindex.Add(id)
r.byid[id] = image
- if searchableDigest != "" {
- list := r.bydigest[searchableDigest]
- r.bydigest[searchableDigest] = append(list, image)
- }
for _, name := range names {
r.byname[name] = image
}
+ for _, digest := range image.Digests {
+ list := r.bydigest[digest]
+ r.bydigest[digest] = append(list, image)
+ }
err = r.Save()
image = copyImage(image)
}
@@ -444,6 +518,14 @@ func (r *imageStore) Delete(id string) error {
for _, name := range image.Names {
delete(r.byname, name)
}
+ for _, digest := range image.Digests {
+ prunedList := imageSliceWithoutValue(r.bydigest[digest], image)
+ if len(prunedList) == 0 {
+ delete(r.bydigest, digest)
+ } else {
+ r.bydigest[digest] = prunedList
+ }
+ }
if toDeleteIndex != -1 {
// delete the image at toDeleteIndex
if toDeleteIndex == len(r.images)-1 {
@@ -452,28 +534,6 @@ func (r *imageStore) Delete(id string) error {
r.images = append(r.images[:toDeleteIndex], r.images[toDeleteIndex+1:]...)
}
}
- if digest, ok := image.BigDataDigests[ImageDigestBigDataKey]; ok {
- // remove the image from the digest-based index
- if list, ok := r.bydigest[digest]; ok {
- prunedList := imageSliceWithoutValue(list, image)
- if len(prunedList) == 0 {
- delete(r.bydigest, digest)
- } else {
- r.bydigest[digest] = prunedList
- }
- }
- }
- if image.Digest != "" {
- // remove the image's hard-coded digest from the digest-based index
- if list, ok := r.bydigest[image.Digest]; ok {
- prunedList := imageSliceWithoutValue(list, image)
- if len(prunedList) == 0 {
- delete(r.bydigest, image.Digest)
- } else {
- r.bydigest[image.Digest] = prunedList
- }
- }
- }
if err := r.Save(); err != nil {
return err
}
@@ -504,7 +564,7 @@ func (r *imageStore) Exists(id string) bool {
func (r *imageStore) ByDigest(d digest.Digest) ([]*Image, error) {
if images, ok := r.bydigest[d]; ok {
- return images, nil
+ return copyImageSlice(images), nil
}
return nil, ErrImageUnknown
}
@@ -606,10 +666,19 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error {
if !ok {
return ErrImageUnknown
}
- if err := os.MkdirAll(r.datadir(image.ID), 0700); err != nil {
+ err := os.MkdirAll(r.datadir(image.ID), 0700)
+ if err != nil {
return err
}
- err := ioutils.AtomicWriteFile(r.datapath(image.ID, key), data, 0600)
+ var newDigest digest.Digest
+ if bigDataNameIsManifest(key) {
+ if newDigest, err = manifest.Digest(data); err != nil {
+ return errors.Wrapf(err, "error digesting manifest")
+ }
+ } else {
+ newDigest = digest.Canonical.FromBytes(data)
+ }
+ err = ioutils.AtomicWriteFile(r.datapath(image.ID, key), data, 0600)
if err == nil {
save := false
if image.BigDataSizes == nil {
@@ -621,7 +690,6 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error {
image.BigDataDigests = make(map[string]digest.Digest)
}
oldDigest, digestOk := image.BigDataDigests[key]
- newDigest := digest.Canonical.FromBytes(data)
image.BigDataDigests[key] = newDigest
if !sizeOk || oldSize != image.BigDataSizes[key] || !digestOk || oldDigest != newDigest {
save = true
@@ -637,20 +705,21 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error {
image.BigDataNames = append(image.BigDataNames, key)
save = true
}
- if key == ImageDigestBigDataKey {
- if oldDigest != "" && oldDigest != newDigest && oldDigest != image.Digest {
- // remove the image from the list of images in the digest-based
- // index which corresponds to the old digest for this item, unless
- // it's also the hard-coded digest
- if list, ok := r.bydigest[oldDigest]; ok {
- prunedList := imageSliceWithoutValue(list, image)
- if len(prunedList) == 0 {
- delete(r.bydigest, oldDigest)
- } else {
- r.bydigest[oldDigest] = prunedList
- }
+ for _, oldDigest := range image.Digests {
+ // remove the image from the list of images in the digest-based index
+ if list, ok := r.bydigest[oldDigest]; ok {
+ prunedList := imageSliceWithoutValue(list, image)
+ if len(prunedList) == 0 {
+ delete(r.bydigest, oldDigest)
+ } else {
+ r.bydigest[oldDigest] = prunedList
}
}
+ }
+ if err = image.recomputeDigests(); err != nil {
+ return errors.Wrapf(err, "error loading recomputing image digest information for %s", image.ID)
+ }
+ for _, newDigest := range image.Digests {
// add the image to the list of images in the digest-based index which
// corresponds to the new digest for this item, unless it's already there
list := r.bydigest[newDigest]
diff --git a/vendor/github.com/containers/storage/images_ffjson.go b/vendor/github.com/containers/storage/images_ffjson.go
index 539acfe93..6b40ebd59 100644
--- a/vendor/github.com/containers/storage/images_ffjson.go
+++ b/vendor/github.com/containers/storage/images_ffjson.go
@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
-// source: ./images.go
+// source: images.go
package storage
diff --git a/vendor/github.com/containers/storage/pkg/config/config.go b/vendor/github.com/containers/storage/pkg/config/config.go
new file mode 100644
index 000000000..bdb5fbcb8
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/config/config.go
@@ -0,0 +1,96 @@
+package config
+
+// ThinpoolOptionsConfig represents the "storage.options.thinpool"
+// TOML config table.
+type ThinpoolOptionsConfig struct {
+ // AutoExtendPercent determines the amount by which pool needs to be
+ // grown. This is specified in terms of % of pool size. So a value of
+ // 20 means that when threshold is hit, pool will be grown by 20% of
+ // existing pool size.
+ AutoExtendPercent string `toml:"autoextend_percent"`
+
+ // AutoExtendThreshold determines the pool extension threshold in terms
+ // of percentage of pool size. For example, if threshold is 60, that
+ // means when pool is 60% full, threshold has been hit.
+ AutoExtendThreshold string `toml:"autoextend_threshold"`
+
+ // BaseSize specifies the size to use when creating the base device,
+ // which limits the size of images and containers.
+ BaseSize string `toml:"basesize"`
+
+ // BlockSize specifies a custom blocksize to use for the thin pool.
+ BlockSize string `toml:"blocksize"`
+
+ // DirectLvmDevice specifies a custom block storage device to use for
+ // the thin pool.
+ DirectLvmDevice string `toml:"directlvm_device"`
+
+ // DirectLvmDeviceForcewipes device even if device already has a
+ // filesystem
+ DirectLvmDeviceForce string `toml:"directlvm_device_force"`
+
+ // Fs specifies the filesystem type to use for the base device.
+ Fs string `toml:"fs"`
+
+ // log_level sets the log level of devicemapper.
+ LogLevel string `toml:"log_level"`
+
+ // MinFreeSpace specifies the min free space percent in a thin pool
+ // require for new device creation to
+ MinFreeSpace string `toml:"min_free_space"`
+
+ // MkfsArg specifies extra mkfs arguments to be used when creating the
+ // basedevice.
+ MkfsArg string `toml:"mkfsarg"`
+
+ // MountOpt specifies extra mount options used when mounting the thin
+ // devices.
+ MountOpt string `toml:"mountopt"`
+
+ // UseDeferredDeletion marks device for deferred deletion
+ UseDeferredDeletion string `toml:"use_deferred_deletion"`
+
+ // UseDeferredRemoval marks device for deferred removal
+ UseDeferredRemoval string `toml:"use_deferred_removal"`
+
+ // XfsNoSpaceMaxRetriesFreeSpace specifies the maximum number of
+ // retries XFS should attempt to complete IO when ENOSPC (no space)
+ // error is returned by underlying storage device.
+ XfsNoSpaceMaxRetries string `toml:"xfs_nospace_max_retries"`
+}
+
+// OptionsConfig represents the "storage.options" TOML config table.
+type OptionsConfig struct {
+ // AdditionalImagesStores is the location of additional read/only
+ // Image stores. Usually used to access Networked File System
+ // for shared image content
+ AdditionalImageStores []string `toml:"additionalimagestores"`
+
+ // Size
+ Size string `toml:"size"`
+
+ // RemapUIDs is a list of default UID mappings to use for layers.
+ RemapUIDs string `toml:"remap-uids"`
+ // RemapGIDs is a list of default GID mappings to use for layers.
+ RemapGIDs string `toml:"remap-gids"`
+
+ // RemapUser is the name of one or more entries in /etc/subuid which
+ // should be used to set up default UID mappings.
+ RemapUser string `toml:"remap-user"`
+ // RemapGroup is the name of one or more entries in /etc/subgid which
+ // should be used to set up default GID mappings.
+ RemapGroup string `toml:"remap-group"`
+ // Thinpool container options to be handed to thinpool drivers
+ Thinpool struct{ ThinpoolOptionsConfig } `toml:"thinpool"`
+ // OSTree repository
+ OstreeRepo string `toml:"ostree_repo"`
+
+ // Do not create a bind mount on the storage home
+ SkipMountHome string `toml:"skip_mount_home"`
+
+ // Alternative program to use for the mount of the file system
+ MountProgram string `toml:"mount_program"`
+
+ // MountOpt specifies extra mount options used when mounting
+ MountOpt string `toml:"mountopt"`
+}
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index 3fe305cc1..856c73e51 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -18,6 +18,7 @@ import (
"github.com/BurntSushi/toml"
drivers "github.com/containers/storage/drivers"
"github.com/containers/storage/pkg/archive"
+ "github.com/containers/storage/pkg/config"
"github.com/containers/storage/pkg/directory"
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/ioutils"
@@ -842,12 +843,16 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return nil, -1, err
+ }
}
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return nil, -1, err
+ }
}
if id == "" {
id = stringid.GenerateRandomID()
@@ -870,7 +875,9 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
lstore.Lock()
defer lstore.Unlock()
if modified, err := lstore.Modified(); modified || err != nil {
- lstore.Load()
+ if err = lstore.Load(); err != nil {
+ return nil, -1, err
+ }
}
}
if l, err := lstore.Get(parent); err == nil && l != nil {
@@ -946,7 +953,9 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, o
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
ilayer, err = store.Get(layer)
if err == nil {
@@ -966,7 +975,9 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, o
ristore.Lock()
defer ristore.Unlock()
if modified, err := ristore.Modified(); modified || err != nil {
- ristore.Load()
+ if err = ristore.Load(); err != nil {
+ return nil, err
+ }
}
creationDate := time.Now().UTC()
@@ -1004,7 +1015,9 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, crea
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
}
// Walk the top layer list.
@@ -1125,14 +1138,18 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return nil, err
+ }
}
var cimage *Image
for _, store := range append([]ROImageStore{istore}, istores...) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
cimage, err = store.Get(image)
if err == nil {
@@ -1162,7 +1179,9 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return nil, err
+ }
}
if !options.HostUIDMapping && len(options.UIDMap) == 0 {
uidMap = s.uidMap
@@ -1222,7 +1241,9 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return nil, err
+ }
}
options.IDMappingOptions = IDMappingOptions{
HostUIDMapping: len(options.UIDMap) == 0,
@@ -1254,17 +1275,23 @@ func (s *store) SetMetadata(id, metadata string) error {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return err
+ }
}
ristore.Lock()
defer ristore.Unlock()
if modified, err := ristore.Modified(); modified || err != nil {
- ristore.Load()
+ if err := ristore.Load(); err != nil {
+ return err
+ }
}
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return err
+ }
}
if rlstore.Exists(id) {
@@ -1292,7 +1319,9 @@ func (s *store) Metadata(id string) (string, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return "", err
+ }
}
if store.Exists(id) {
return store.Metadata(id)
@@ -1311,7 +1340,9 @@ func (s *store) Metadata(id string) (string, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return "", err
+ }
}
if store.Exists(id) {
return store.Metadata(id)
@@ -1325,7 +1356,9 @@ func (s *store) Metadata(id string) (string, error) {
cstore.Lock()
defer cstore.Unlock()
if modified, err := cstore.Modified(); modified || err != nil {
- cstore.Load()
+ if err = cstore.Load(); err != nil {
+ return "", err
+ }
}
if cstore.Exists(id) {
return cstore.Metadata(id)
@@ -1346,7 +1379,9 @@ func (s *store) ListImageBigData(id string) ([]string, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
bigDataNames, err := store.BigDataNames(id)
if err == nil {
@@ -1369,7 +1404,9 @@ func (s *store) ImageBigDataSize(id, key string) (int64, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return -1, err
+ }
}
size, err := store.BigDataSize(id, key)
if err == nil {
@@ -1393,7 +1430,9 @@ func (s *store) ImageBigDataDigest(id, key string) (digest.Digest, error) {
ristore.Lock()
defer ristore.Unlock()
if modified, err := ristore.Modified(); modified || err != nil {
- ristore.Load()
+ if err = ristore.Load(); err != nil {
+ return "", nil
+ }
}
d, err := ristore.BigDataDigest(id, key)
if err == nil && d.Validate() == nil {
@@ -1416,7 +1455,9 @@ func (s *store) ImageBigData(id, key string) ([]byte, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
data, err := store.BigData(id, key)
if err == nil {
@@ -1435,7 +1476,9 @@ func (s *store) SetImageBigData(id, key string, data []byte) error {
ristore.Lock()
defer ristore.Unlock()
if modified, err := ristore.Modified(); modified || err != nil {
- ristore.Load()
+ if err = ristore.Load(); err != nil {
+ return nil
+ }
}
return ristore.SetBigData(id, key, data)
@@ -1456,7 +1499,9 @@ func (s *store) ImageSize(id string) (int64, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return -1, err
+ }
}
}
@@ -1475,7 +1520,9 @@ func (s *store) ImageSize(id string) (int64, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return -1, err
+ }
}
if image, err = store.Get(id); err == nil {
imageStore = store
@@ -1560,7 +1607,9 @@ func (s *store) ContainerSize(id string) (int64, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return -1, err
+ }
}
}
@@ -1582,7 +1631,9 @@ func (s *store) ContainerSize(id string) (int64, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return -1, err
+ }
}
// Read the container record.
@@ -1644,7 +1695,9 @@ func (s *store) ListContainerBigData(id string) ([]string, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return nil, err
+ }
}
return rcstore.BigDataNames(id)
@@ -1658,7 +1711,9 @@ func (s *store) ContainerBigDataSize(id, key string) (int64, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return -1, err
+ }
}
return rcstore.BigDataSize(id, key)
}
@@ -1671,7 +1726,9 @@ func (s *store) ContainerBigDataDigest(id, key string) (digest.Digest, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return "", err
+ }
}
return rcstore.BigDataDigest(id, key)
}
@@ -1684,7 +1741,9 @@ func (s *store) ContainerBigData(id, key string) ([]byte, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return nil, err
+ }
}
return rcstore.BigData(id, key)
}
@@ -1697,7 +1756,9 @@ func (s *store) SetContainerBigData(id, key string, data []byte) error {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return err
+ }
}
return rcstore.SetBigData(id, key, data)
}
@@ -1715,7 +1776,9 @@ func (s *store) Exists(id string) bool {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return false
+ }
}
if store.Exists(id) {
return true
@@ -1734,7 +1797,9 @@ func (s *store) Exists(id string) bool {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return false
+ }
}
if store.Exists(id) {
return true
@@ -1748,7 +1813,9 @@ func (s *store) Exists(id string) bool {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return false
+ }
}
if rcstore.Exists(id) {
return true
@@ -1779,7 +1846,9 @@ func (s *store) SetNames(id string, names []string) error {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return err
+ }
}
if rlstore.Exists(id) {
return rlstore.SetNames(id, deduped)
@@ -1792,7 +1861,9 @@ func (s *store) SetNames(id string, names []string) error {
ristore.Lock()
defer ristore.Unlock()
if modified, err := ristore.Modified(); modified || err != nil {
- ristore.Load()
+ if err = ristore.Load(); err != nil {
+ return err
+ }
}
if ristore.Exists(id) {
return ristore.SetNames(id, deduped)
@@ -1805,7 +1876,9 @@ func (s *store) SetNames(id string, names []string) error {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return err
+ }
}
if rcstore.Exists(id) {
return rcstore.SetNames(id, deduped)
@@ -1826,7 +1899,9 @@ func (s *store) Names(id string) ([]string, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
if l, err := store.Get(id); l != nil && err == nil {
return l.Names, nil
@@ -1845,7 +1920,9 @@ func (s *store) Names(id string) ([]string, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
if i, err := store.Get(id); i != nil && err == nil {
return i.Names, nil
@@ -1859,7 +1936,9 @@ func (s *store) Names(id string) ([]string, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return nil, err
+ }
}
if c, err := rcstore.Get(id); c != nil && err == nil {
return c.Names, nil
@@ -1880,7 +1959,9 @@ func (s *store) Lookup(name string) (string, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return "", err
+ }
}
if l, err := store.Get(name); l != nil && err == nil {
return l.ID, nil
@@ -1899,7 +1980,9 @@ func (s *store) Lookup(name string) (string, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return "", err
+ }
}
if i, err := store.Get(name); i != nil && err == nil {
return i.ID, nil
@@ -1913,7 +1996,9 @@ func (s *store) Lookup(name string) (string, error) {
cstore.Lock()
defer cstore.Unlock()
if modified, err := cstore.Modified(); modified || err != nil {
- cstore.Load()
+ if err = cstore.Load(); err != nil {
+ return "", err
+ }
}
if c, err := cstore.Get(name); c != nil && err == nil {
return c.ID, nil
@@ -1939,17 +2024,23 @@ func (s *store) DeleteLayer(id string) error {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return err
+ }
}
ristore.Lock()
defer ristore.Unlock()
if modified, err := ristore.Modified(); modified || err != nil {
- ristore.Load()
+ if err = ristore.Load(); err != nil {
+ return err
+ }
}
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return err
+ }
}
if rlstore.Exists(id) {
@@ -2005,17 +2096,23 @@ func (s *store) DeleteImage(id string, commit bool) (layers []string, err error)
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return nil, err
+ }
}
ristore.Lock()
defer ristore.Unlock()
if modified, err := ristore.Modified(); modified || err != nil {
- ristore.Load()
+ if err = ristore.Load(); err != nil {
+ return nil, err
+ }
}
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return nil, err
+ }
}
layersToRemove := []string{}
if ristore.Exists(id) {
@@ -2137,17 +2234,23 @@ func (s *store) DeleteContainer(id string) error {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return err
+ }
}
ristore.Lock()
defer ristore.Unlock()
if modified, err := ristore.Modified(); modified || err != nil {
- ristore.Load()
+ if err = ristore.Load(); err != nil {
+ return err
+ }
}
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return err
+ }
}
if rcstore.Exists(id) {
@@ -2192,17 +2295,23 @@ func (s *store) Delete(id string) error {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return err
+ }
}
ristore.Lock()
defer ristore.Unlock()
if modified, err := ristore.Modified(); modified || err != nil {
- ristore.Load()
+ if err := ristore.Load(); err != nil {
+ return err
+ }
}
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return err
+ }
}
if rcstore.Exists(id) {
@@ -2254,17 +2363,23 @@ func (s *store) Wipe() error {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return err
+ }
}
ristore.Lock()
defer ristore.Unlock()
if modified, err := ristore.Modified(); modified || err != nil {
- ristore.Load()
+ if err = ristore.Load(); err != nil {
+ return err
+ }
}
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return err
+ }
}
if err = rcstore.Wipe(); err != nil {
@@ -2306,7 +2421,9 @@ func (s *store) Mount(id, mountLabel string) (string, error) {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return "", err
+ }
}
if rlstore.Exists(id) {
options := drivers.MountOpts{
@@ -2331,7 +2448,9 @@ func (s *store) Mounted(id string) (int, error) {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return 0, err
+ }
}
return rlstore.Mounted(id)
@@ -2348,7 +2467,9 @@ func (s *store) Unmount(id string, force bool) (bool, error) {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return false, err
+ }
}
if rlstore.Exists(id) {
return rlstore.Unmount(id, force)
@@ -2369,7 +2490,9 @@ func (s *store) Changes(from, to string) ([]archive.Change, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
if store.Exists(to) {
return store.Changes(from, to)
@@ -2391,7 +2514,9 @@ func (s *store) DiffSize(from, to string) (int64, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return -1, err
+ }
}
if store.Exists(to) {
return store.DiffSize(from, to)
@@ -2412,7 +2537,9 @@ func (s *store) Diff(from, to string, options *DiffOptions) (io.ReadCloser, erro
for _, store := range append([]ROLayerStore{lstore}, lstores...) {
store.Lock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
if store.Exists(to) {
rc, err := store.Diff(from, to, options)
@@ -2440,7 +2567,9 @@ func (s *store) ApplyDiff(to string, diff io.Reader) (int64, error) {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return -1, err
+ }
}
if rlstore.Exists(to) {
return rlstore.ApplyDiff(to, diff)
@@ -2463,7 +2592,9 @@ func (s *store) layersByMappedDigest(m func(ROLayerStore, digest.Digest) ([]Laye
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
storeLayers, err := m(store, d)
if err != nil {
@@ -2507,7 +2638,9 @@ func (s *store) LayerSize(id string) (int64, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return -1, err
+ }
}
if store.Exists(id) {
return store.Size(id)
@@ -2524,7 +2657,9 @@ func (s *store) LayerParentOwners(id string) ([]int, []int, error) {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return nil, nil, err
+ }
}
if rlstore.Exists(id) {
return rlstore.ParentOwners(id)
@@ -2544,12 +2679,16 @@ func (s *store) ContainerParentOwners(id string) ([]int, []int, error) {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return nil, nil, err
+ }
}
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return nil, nil, err
+ }
}
container, err := rcstore.Get(id)
if err != nil {
@@ -2577,7 +2716,9 @@ func (s *store) Layers() ([]Layer, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
storeLayers, err := store.Layers()
if err != nil {
@@ -2603,7 +2744,9 @@ func (s *store) Images() ([]Image, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
storeImages, err := store.Images()
if err != nil {
@@ -2623,7 +2766,9 @@ func (s *store) Containers() ([]Container, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return nil, err
+ }
}
return rcstore.Containers()
@@ -2642,7 +2787,9 @@ func (s *store) Layer(id string) (*Layer, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
layer, err := store.Get(id)
if err == nil {
@@ -2665,7 +2812,9 @@ func (s *store) Image(id string) (*Image, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
image, err := store.Get(id)
if err == nil {
@@ -2695,7 +2844,9 @@ func (s *store) ImagesByTopLayer(id string) ([]*Image, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
imageList, err := store.Images()
if err != nil {
@@ -2726,7 +2877,9 @@ func (s *store) ImagesByDigest(d digest.Digest) ([]*Image, error) {
store.Lock()
defer store.Unlock()
if modified, err := store.Modified(); modified || err != nil {
- store.Load()
+ if err = store.Load(); err != nil {
+ return nil, err
+ }
}
imageList, err := store.ByDigest(d)
if err != nil && err != ErrImageUnknown {
@@ -2745,7 +2898,9 @@ func (s *store) Container(id string) (*Container, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return nil, err
+ }
}
return rcstore.Get(id)
@@ -2759,7 +2914,9 @@ func (s *store) ContainerLayerID(id string) (string, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return "", err
+ }
}
container, err := rcstore.Get(id)
if err != nil {
@@ -2780,7 +2937,9 @@ func (s *store) ContainerByLayer(id string) (*Container, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return nil, err
+ }
}
containerList, err := rcstore.Containers()
if err != nil {
@@ -2803,7 +2962,9 @@ func (s *store) ContainerDirectory(id string) (string, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return "", err
+ }
}
id, err = rcstore.Lookup(id)
@@ -2828,7 +2989,9 @@ func (s *store) ContainerRunDirectory(id string) (string, error) {
rcstore.Lock()
defer rcstore.Unlock()
if modified, err := rcstore.Modified(); modified || err != nil {
- rcstore.Load()
+ if err = rcstore.Load(); err != nil {
+ return "", err
+ }
}
id, err = rcstore.Lookup(id)
@@ -2899,7 +3062,9 @@ func (s *store) Shutdown(force bool) ([]string, error) {
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
- rlstore.Load()
+ if err = rlstore.Load(); err != nil {
+ return nil, err
+ }
}
layers, err := rlstore.Layers()
@@ -2992,6 +3157,15 @@ func copyStringDigestMap(m map[string]digest.Digest) map[string]digest.Digest {
return ret
}
+func copyDigestSlice(slice []digest.Digest) []digest.Digest {
+ if len(slice) == 0 {
+ return nil
+ }
+ ret := make([]digest.Digest, len(slice))
+ copy(ret, slice)
+ return ret
+}
+
// copyStringInterfaceMap still forces us to assume that the interface{} is
// a non-pointer scalar value
func copyStringInterfaceMap(m map[string]interface{}) map[string]interface{} {
@@ -3005,108 +3179,13 @@ func copyStringInterfaceMap(m map[string]interface{}) map[string]interface{} {
// DefaultConfigFile path to the system wide storage.conf file
const DefaultConfigFile = "/etc/containers/storage.conf"
-// ThinpoolOptionsConfig represents the "storage.options.thinpool"
-// TOML config table.
-type ThinpoolOptionsConfig struct {
- // AutoExtendPercent determines the amount by which pool needs to be
- // grown. This is specified in terms of % of pool size. So a value of
- // 20 means that when threshold is hit, pool will be grown by 20% of
- // existing pool size.
- AutoExtendPercent string `toml:"autoextend_percent"`
-
- // AutoExtendThreshold determines the pool extension threshold in terms
- // of percentage of pool size. For example, if threshold is 60, that
- // means when pool is 60% full, threshold has been hit.
- AutoExtendThreshold string `toml:"autoextend_threshold"`
-
- // BaseSize specifies the size to use when creating the base device,
- // which limits the size of images and containers.
- BaseSize string `toml:"basesize"`
-
- // BlockSize specifies a custom blocksize to use for the thin pool.
- BlockSize string `toml:"blocksize"`
-
- // DirectLvmDevice specifies a custom block storage device to use for
- // the thin pool.
- DirectLvmDevice string `toml:"directlvm_device"`
-
- // DirectLvmDeviceForcewipes device even if device already has a
- // filesystem
- DirectLvmDeviceForce string `toml:"directlvm_device_force"`
-
- // Fs specifies the filesystem type to use for the base device.
- Fs string `toml:"fs"`
-
- // log_level sets the log level of devicemapper.
- LogLevel string `toml:"log_level"`
-
- // MinFreeSpace specifies the min free space percent in a thin pool
- // require for new device creation to
- MinFreeSpace string `toml:"min_free_space"`
-
- // MkfsArg specifies extra mkfs arguments to be used when creating the
- // basedevice.
- MkfsArg string `toml:"mkfsarg"`
-
- // MountOpt specifies extra mount options used when mounting the thin
- // devices.
- MountOpt string `toml:"mountopt"`
-
- // UseDeferredDeletion marks device for deferred deletion
- UseDeferredDeletion string `toml:"use_deferred_deletion"`
-
- // UseDeferredRemoval marks device for deferred removal
- UseDeferredRemoval string `toml:"use_deferred_removal"`
-
- // XfsNoSpaceMaxRetriesFreeSpace specifies the maximum number of
- // retries XFS should attempt to complete IO when ENOSPC (no space)
- // error is returned by underlying storage device.
- XfsNoSpaceMaxRetries string `toml:"xfs_nospace_max_retries"`
-}
-
-// OptionsConfig represents the "storage.options" TOML config table.
-type OptionsConfig struct {
- // AdditionalImagesStores is the location of additional read/only
- // Image stores. Usually used to access Networked File System
- // for shared image content
- AdditionalImageStores []string `toml:"additionalimagestores"`
-
- // Size
- Size string `toml:"size"`
-
- // RemapUIDs is a list of default UID mappings to use for layers.
- RemapUIDs string `toml:"remap-uids"`
- // RemapGIDs is a list of default GID mappings to use for layers.
- RemapGIDs string `toml:"remap-gids"`
-
- // RemapUser is the name of one or more entries in /etc/subuid which
- // should be used to set up default UID mappings.
- RemapUser string `toml:"remap-user"`
- // RemapGroup is the name of one or more entries in /etc/subgid which
- // should be used to set up default GID mappings.
- RemapGroup string `toml:"remap-group"`
- // Thinpool container options to be handed to thinpool drivers
- Thinpool struct{ ThinpoolOptionsConfig } `toml:"thinpool"`
- // OSTree repository
- OstreeRepo string `toml:"ostree_repo"`
-
- // Do not create a bind mount on the storage home
- SkipMountHome string `toml:"skip_mount_home"`
-
- // Alternative program to use for the mount of the file system
- MountProgram string `toml:"mount_program"`
-
- // MountOpt specifies extra mount options used when mounting
- MountOpt string `toml:"mountopt"`
-}
-
// TOML-friendly explicit tables used for conversions.
type tomlConfig struct {
Storage struct {
- Driver string `toml:"driver"`
- RunRoot string `toml:"runroot"`
- GraphRoot string `toml:"graphroot"`
- Options struct{ OptionsConfig } `toml:"options"`
+ Driver string `toml:"driver"`
+ RunRoot string `toml:"runroot"`
+ GraphRoot string `toml:"graphroot"`
+ Options struct{ config.OptionsConfig } `toml:"options"`
} `toml:"storage"`
}
diff --git a/vendor/github.com/containers/storage/vendor.conf b/vendor/github.com/containers/storage/vendor.conf
index 04af9010b..c143b049d 100644
--- a/vendor/github.com/containers/storage/vendor.conf
+++ b/vendor/github.com/containers/storage/vendor.conf
@@ -1,12 +1,18 @@
github.com/BurntSushi/toml master
github.com/Microsoft/go-winio 307e919c663683a9000576fdc855acaf9534c165
github.com/Microsoft/hcsshim a8d9cc56cbce765a7eebdf4792e6ceceeff3edb8
+github.com/containers/image master
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00
github.com/docker/go-units 0dadbb0345b35ec7ef35e228dabb8de89a65bf52
+github.com/docker/libtrust master
+github.com/klauspost/compress v1.4.1
+github.com/klauspost/cpuid v1.2.0
+github.com/klauspost/pgzip v1.2.1
github.com/mattn/go-shellwords 753a2322a99f87c0eff284980e77f53041555bc6
github.com/mistifyio/go-zfs c0224de804d438efd11ea6e52ada8014537d6062
github.com/opencontainers/go-digest master
+github.com/opencontainers/image-spec master
github.com/opencontainers/runc 6c22e77604689db8725fa866f0f2ec0b3e8c3a07
github.com/opencontainers/selinux v1.1
github.com/ostreedev/ostree-go master
@@ -23,6 +29,3 @@ golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
gotest.tools master
github.com/google/go-cmp master
-github.com/klauspost/pgzip v1.2.1
-github.com/klauspost/compress v1.4.1
-github.com/klauspost/cpuid v1.2.0
diff --git a/vendor/github.com/urfave/cli/LICENSE b/vendor/github.com/urfave/cli/LICENSE
deleted file mode 100644
index 42a597e29..000000000
--- a/vendor/github.com/urfave/cli/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2016 Jeremy Saenz & Contributors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/vendor/github.com/urfave/cli/README.md b/vendor/github.com/urfave/cli/README.md
deleted file mode 100644
index f2baef4f0..000000000
--- a/vendor/github.com/urfave/cli/README.md
+++ /dev/null
@@ -1,1526 +0,0 @@
-cli
-===
-
-[![Build Status](https://travis-ci.org/urfave/cli.svg?branch=master)](https://travis-ci.org/urfave/cli)
-[![Windows Build Status](https://ci.appveyor.com/api/projects/status/rtgk5xufi932pb2v?svg=true)](https://ci.appveyor.com/project/urfave/cli)
-[![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://godoc.org/github.com/urfave/cli)
-[![codebeat](https://codebeat.co/badges/0a8f30aa-f975-404b-b878-5fab3ae1cc5f)](https://codebeat.co/projects/github-com-urfave-cli)
-[![Go Report Card](https://goreportcard.com/badge/urfave/cli)](https://goreportcard.com/report/urfave/cli)
-[![top level coverage](https://gocover.io/_badge/github.com/urfave/cli?0 "top level coverage")](http://gocover.io/github.com/urfave/cli) /
-[![altsrc coverage](https://gocover.io/_badge/github.com/urfave/cli/altsrc?0 "altsrc coverage")](http://gocover.io/github.com/urfave/cli/altsrc)
-
-This is the library formerly known as `github.com/codegangsta/cli` -- Github
-will automatically redirect requests to this repository, but we recommend
-updating your references for clarity.
-
-cli is a simple, fast, and fun package for building command line apps in Go. The
-goal is to enable developers to write fast and distributable command line
-applications in an expressive way.
-
-<!-- toc -->
-
-- [Overview](#overview)
-- [Installation](#installation)
- * [Supported platforms](#supported-platforms)
- * [Using the `v2` branch](#using-the-v2-branch)
- * [Pinning to the `v1` releases](#pinning-to-the-v1-releases)
-- [Getting Started](#getting-started)
-- [Examples](#examples)
- * [Arguments](#arguments)
- * [Flags](#flags)
- + [Placeholder Values](#placeholder-values)
- + [Alternate Names](#alternate-names)
- + [Ordering](#ordering)
- + [Values from the Environment](#values-from-the-environment)
- + [Values from files](#values-from-files)
- + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others)
- + [Precedence](#precedence)
- * [Subcommands](#subcommands)
- * [Subcommands categories](#subcommands-categories)
- * [Exit code](#exit-code)
- * [Bash Completion](#bash-completion)
- + [Enabling](#enabling)
- + [Distribution](#distribution)
- + [Customization](#customization)
- * [Generated Help Text](#generated-help-text)
- + [Customization](#customization-1)
- * [Version Flag](#version-flag)
- + [Customization](#customization-2)
- + [Full API Example](#full-api-example)
- * [Combining short Bool options](#combining-short-bool-options)
-- [Contribution Guidelines](#contribution-guidelines)
-
-<!-- tocstop -->
-
-## Overview
-
-Command line apps are usually so tiny that there is absolutely no reason why
-your code should *not* be self-documenting. Things like generating help text and
-parsing command flags/options should not hinder productivity when writing a
-command line app.
-
-**This is where cli comes into play.** cli makes command line programming fun,
-organized, and expressive!
-
-## Installation
-
-Make sure you have a working Go environment. Go version 1.2+ is supported. [See
-the install instructions for Go](http://golang.org/doc/install.html).
-
-To install cli, simply run:
-```
-$ go get github.com/urfave/cli
-```
-
-Make sure your `PATH` includes the `$GOPATH/bin` directory so your commands can
-be easily used:
-```
-export PATH=$PATH:$GOPATH/bin
-```
-
-### Supported platforms
-
-cli is tested against multiple versions of Go on Linux, and against the latest
-released version of Go on OS X and Windows. For full details, see
-[`./.travis.yml`](./.travis.yml) and [`./appveyor.yml`](./appveyor.yml).
-
-### Using the `v2` branch
-
-**Warning**: The `v2` branch is currently unreleased and considered unstable.
-
-There is currently a long-lived branch named `v2` that is intended to land as
-the new `master` branch once development there has settled down. The current
-`master` branch (mirrored as `v1`) is being manually merged into `v2` on
-an irregular human-based schedule, but generally if one wants to "upgrade" to
-`v2` *now* and accept the volatility (read: "awesomeness") that comes along with
-that, please use whatever version pinning of your preference, such as via
-`gopkg.in`:
-
-```
-$ go get gopkg.in/urfave/cli.v2
-```
-
-``` go
-...
-import (
- "gopkg.in/urfave/cli.v2" // imports as package "cli"
-)
-...
-```
-
-### Pinning to the `v1` releases
-
-Similarly to the section above describing use of the `v2` branch, if one wants
-to avoid any unexpected compatibility pains once `v2` becomes `master`, then
-pinning to `v1` is an acceptable option, e.g.:
-
-```
-$ go get gopkg.in/urfave/cli.v1
-```
-
-``` go
-...
-import (
- "gopkg.in/urfave/cli.v1" // imports as package "cli"
-)
-...
-```
-
-This will pull the latest tagged `v1` release (e.g. `v1.18.1` at the time of writing).
-
-## Getting Started
-
-One of the philosophies behind cli is that an API should be playful and full of
-discovery. So a cli app can be as little as one line of code in `main()`.
-
-<!-- {
- "args": ["&#45;&#45;help"],
- "output": "A new cli application"
-} -->
-``` go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- err := cli.NewApp().Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-This app will run and show help text, but is not very useful. Let's give an
-action to execute and some help documentation:
-
-<!-- {
- "output": "boom! I say!"
-} -->
-``` go
-package main
-
-import (
- "fmt"
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
- app.Name = "boom"
- app.Usage = "make an explosive entrance"
- app.Action = func(c *cli.Context) error {
- fmt.Println("boom! I say!")
- return nil
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-Running this already gives you a ton of functionality, plus support for things
-like subcommands and flags, which are covered below.
-
-## Examples
-
-Being a programmer can be a lonely job. Thankfully by the power of automation
-that is not the case! Let's create a greeter app to fend off our demons of
-loneliness!
-
-Start by creating a directory named `greet`, and within it, add a file,
-`greet.go` with the following code in it:
-
-<!-- {
- "output": "Hello friend!"
-} -->
-``` go
-package main
-
-import (
- "fmt"
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
- app.Name = "greet"
- app.Usage = "fight the loneliness!"
- app.Action = func(c *cli.Context) error {
- fmt.Println("Hello friend!")
- return nil
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-Install our command to the `$GOPATH/bin` directory:
-
-```
-$ go install
-```
-
-Finally run our new command:
-
-```
-$ greet
-Hello friend!
-```
-
-cli also generates neat help text:
-
-```
-$ greet help
-NAME:
- greet - fight the loneliness!
-
-USAGE:
- greet [global options] command [command options] [arguments...]
-
-VERSION:
- 0.0.0
-
-COMMANDS:
- help, h Shows a list of commands or help for one command
-
-GLOBAL OPTIONS
- --version Shows version information
-```
-
-### Arguments
-
-You can lookup arguments by calling the `Args` function on `cli.Context`, e.g.:
-
-<!-- {
- "output": "Hello \""
-} -->
-``` go
-package main
-
-import (
- "fmt"
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
-
- app.Action = func(c *cli.Context) error {
- fmt.Printf("Hello %q", c.Args().Get(0))
- return nil
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-### Flags
-
-Setting and querying flags is simple.
-
-<!-- {
- "output": "Hello Nefertiti"
-} -->
-``` go
-package main
-
-import (
- "fmt"
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
-
- app.Flags = []cli.Flag {
- cli.StringFlag{
- Name: "lang",
- Value: "english",
- Usage: "language for the greeting",
- },
- }
-
- app.Action = func(c *cli.Context) error {
- name := "Nefertiti"
- if c.NArg() > 0 {
- name = c.Args().Get(0)
- }
- if c.String("lang") == "spanish" {
- fmt.Println("Hola", name)
- } else {
- fmt.Println("Hello", name)
- }
- return nil
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-You can also set a destination variable for a flag, to which the content will be
-scanned.
-
-<!-- {
- "output": "Hello someone"
-} -->
-``` go
-package main
-
-import (
- "log"
- "os"
- "fmt"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- var language string
-
- app := cli.NewApp()
-
- app.Flags = []cli.Flag {
- cli.StringFlag{
- Name: "lang",
- Value: "english",
- Usage: "language for the greeting",
- Destination: &language,
- },
- }
-
- app.Action = func(c *cli.Context) error {
- name := "someone"
- if c.NArg() > 0 {
- name = c.Args()[0]
- }
- if language == "spanish" {
- fmt.Println("Hola", name)
- } else {
- fmt.Println("Hello", name)
- }
- return nil
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-See full list of flags at http://godoc.org/github.com/urfave/cli
-
-#### Placeholder Values
-
-Sometimes it's useful to specify a flag's value within the usage string itself.
-Such placeholders are indicated with back quotes.
-
-For example this:
-
-<!-- {
- "args": ["&#45;&#45;help"],
- "output": "&#45;&#45;config FILE, &#45;c FILE"
-} -->
-```go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
-
- app.Flags = []cli.Flag{
- cli.StringFlag{
- Name: "config, c",
- Usage: "Load configuration from `FILE`",
- },
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-Will result in help output like:
-
-```
---config FILE, -c FILE Load configuration from FILE
-```
-
-Note that only the first placeholder is used. Subsequent back-quoted words will
-be left as-is.
-
-#### Alternate Names
-
-You can set alternate (or short) names for flags by providing a comma-delimited
-list for the `Name`. e.g.
-
-<!-- {
- "args": ["&#45;&#45;help"],
- "output": "&#45;&#45;lang value, &#45;l value.*language for the greeting.*default: \"english\""
-} -->
-``` go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
-
- app.Flags = []cli.Flag {
- cli.StringFlag{
- Name: "lang, l",
- Value: "english",
- Usage: "language for the greeting",
- },
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-That flag can then be set with `--lang spanish` or `-l spanish`. Note that
-giving two different forms of the same flag in the same command invocation is an
-error.
-
-#### Ordering
-
-Flags for the application and commands are shown in the order they are defined.
-However, it's possible to sort them from outside this library by using `FlagsByName`
-or `CommandsByName` with `sort`.
-
-For example this:
-
-<!-- {
- "args": ["&#45;&#45;help"],
- "output": "add a task to the list\n.*complete a task on the list\n.*\n\n.*\n.*Load configuration from FILE\n.*Language for the greeting.*"
-} -->
-``` go
-package main
-
-import (
- "log"
- "os"
- "sort"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
-
- app.Flags = []cli.Flag {
- cli.StringFlag{
- Name: "lang, l",
- Value: "english",
- Usage: "Language for the greeting",
- },
- cli.StringFlag{
- Name: "config, c",
- Usage: "Load configuration from `FILE`",
- },
- }
-
- app.Commands = []cli.Command{
- {
- Name: "complete",
- Aliases: []string{"c"},
- Usage: "complete a task on the list",
- Action: func(c *cli.Context) error {
- return nil
- },
- },
- {
- Name: "add",
- Aliases: []string{"a"},
- Usage: "add a task to the list",
- Action: func(c *cli.Context) error {
- return nil
- },
- },
- }
-
- sort.Sort(cli.FlagsByName(app.Flags))
- sort.Sort(cli.CommandsByName(app.Commands))
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-Will result in help output like:
-
-```
---config FILE, -c FILE Load configuration from FILE
---lang value, -l value Language for the greeting (default: "english")
-```
-
-#### Values from the Environment
-
-You can also have the default value set from the environment via `EnvVar`. e.g.
-
-<!-- {
- "args": ["&#45;&#45;help"],
- "output": "language for the greeting.*APP_LANG"
-} -->
-``` go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
-
- app.Flags = []cli.Flag {
- cli.StringFlag{
- Name: "lang, l",
- Value: "english",
- Usage: "language for the greeting",
- EnvVar: "APP_LANG",
- },
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-The `EnvVar` may also be given as a comma-delimited "cascade", where the first
-environment variable that resolves is used as the default.
-
-<!-- {
- "args": ["&#45;&#45;help"],
- "output": "language for the greeting.*LEGACY_COMPAT_LANG.*APP_LANG.*LANG"
-} -->
-``` go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
-
- app.Flags = []cli.Flag {
- cli.StringFlag{
- Name: "lang, l",
- Value: "english",
- Usage: "language for the greeting",
- EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
- },
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-#### Values from files
-
-You can also have the default value set from file via `FilePath`. e.g.
-
-<!-- {
- "args": ["&#45;&#45;help"],
- "output": "password for the mysql database"
-} -->
-``` go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
-
- app.Flags = []cli.Flag {
- cli.StringFlag{
- Name: "password, p",
- Usage: "password for the mysql database",
- FilePath: "/etc/mysql/password",
- },
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-Note that default values set from file (e.g. `FilePath`) take precedence over
-default values set from the enviornment (e.g. `EnvVar`).
-
-#### Values from alternate input sources (YAML, TOML, and others)
-
-There is a separate package altsrc that adds support for getting flag values
-from other file input sources.
-
-Currently supported input source formats:
-* YAML
-* TOML
-
-In order to get values for a flag from an alternate input source the following
-code would be added to wrap an existing cli.Flag like below:
-
-``` go
- altsrc.NewIntFlag(cli.IntFlag{Name: "test"})
-```
-
-Initialization must also occur for these flags. Below is an example initializing
-getting data from a yaml file below.
-
-``` go
- command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
-```
-
-The code above will use the "load" string as a flag name to get the file name of
-a yaml file from the cli.Context. It will then use that file name to initialize
-the yaml input source for any flags that are defined on that command. As a note
-the "load" flag used would also have to be defined on the command flags in order
-for this code snipped to work.
-
-Currently only YAML and JSON files are supported but developers can add support
-for other input sources by implementing the altsrc.InputSourceContext for their
-given sources.
-
-Here is a more complete sample of a command using YAML support:
-
-<!-- {
- "args": ["test-cmd", "&#45;&#45;help"],
- "output": "&#45&#45;test value.*default: 0"
-} -->
-``` go
-package notmain
-
-import (
- "fmt"
- "log"
- "os"
-
- "github.com/urfave/cli"
- "github.com/urfave/cli/altsrc"
-)
-
-func main() {
- app := cli.NewApp()
-
- flags := []cli.Flag{
- altsrc.NewIntFlag(cli.IntFlag{Name: "test"}),
- cli.StringFlag{Name: "load"},
- }
-
- app.Action = func(c *cli.Context) error {
- fmt.Println("yaml ist rad")
- return nil
- }
-
- app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load"))
- app.Flags = flags
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-#### Precedence
-
-The precedence for flag value sources is as follows (highest to lowest):
-
-0. Command line flag value from user
-0. Environment variable (if specified)
-0. Configuration file (if specified)
-0. Default defined on the flag
-
-### Subcommands
-
-Subcommands can be defined for a more git-like command line app.
-
-<!-- {
- "args": ["template", "add"],
- "output": "new task template: .+"
-} -->
-```go
-package main
-
-import (
- "fmt"
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
-
- app.Commands = []cli.Command{
- {
- Name: "add",
- Aliases: []string{"a"},
- Usage: "add a task to the list",
- Action: func(c *cli.Context) error {
- fmt.Println("added task: ", c.Args().First())
- return nil
- },
- },
- {
- Name: "complete",
- Aliases: []string{"c"},
- Usage: "complete a task on the list",
- Action: func(c *cli.Context) error {
- fmt.Println("completed task: ", c.Args().First())
- return nil
- },
- },
- {
- Name: "template",
- Aliases: []string{"t"},
- Usage: "options for task templates",
- Subcommands: []cli.Command{
- {
- Name: "add",
- Usage: "add a new template",
- Action: func(c *cli.Context) error {
- fmt.Println("new task template: ", c.Args().First())
- return nil
- },
- },
- {
- Name: "remove",
- Usage: "remove an existing template",
- Action: func(c *cli.Context) error {
- fmt.Println("removed task template: ", c.Args().First())
- return nil
- },
- },
- },
- },
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-### Subcommands categories
-
-For additional organization in apps that have many subcommands, you can
-associate a category for each command to group them together in the help
-output.
-
-E.g.
-
-```go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
-
- app.Commands = []cli.Command{
- {
- Name: "noop",
- },
- {
- Name: "add",
- Category: "Template actions",
- },
- {
- Name: "remove",
- Category: "Template actions",
- },
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-Will include:
-
-```
-COMMANDS:
- noop
-
- Template actions:
- add
- remove
-```
-
-### Exit code
-
-Calling `App.Run` will not automatically call `os.Exit`, which means that by
-default the exit code will "fall through" to being `0`. An explicit exit code
-may be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a
-`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.:
-
-``` go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- app := cli.NewApp()
- app.Flags = []cli.Flag{
- cli.BoolTFlag{
- Name: "ginger-crouton",
- Usage: "is it in the soup?",
- },
- }
- app.Action = func(ctx *cli.Context) error {
- if !ctx.Bool("ginger-crouton") {
- return cli.NewExitError("it is not in the soup", 86)
- }
- return nil
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-### Bash Completion
-
-You can enable completion commands by setting the `EnableBashCompletion`
-flag on the `App` object. By default, this setting will only auto-complete to
-show an app's subcommands, but you can write your own completion methods for
-the App or its subcommands.
-
-<!-- {
- "args": ["complete", "&#45;&#45;generate&#45;bash&#45;completion"],
- "output": "laundry"
-} -->
-``` go
-package main
-
-import (
- "fmt"
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
-
- app := cli.NewApp()
- app.EnableBashCompletion = true
- app.Commands = []cli.Command{
- {
- Name: "complete",
- Aliases: []string{"c"},
- Usage: "complete a task on the list",
- Action: func(c *cli.Context) error {
- fmt.Println("completed task: ", c.Args().First())
- return nil
- },
- BashComplete: func(c *cli.Context) {
- // This will complete if no args are passed
- if c.NArg() > 0 {
- return
- }
- for _, t := range tasks {
- fmt.Println(t)
- }
- },
- },
- }
-
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-#### Enabling
-
-Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while
-setting the `PROG` variable to the name of your program:
-
-`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
-
-#### Distribution
-
-Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename
-it to the name of the program you wish to add autocomplete support for (or
-automatically install it there if you are distributing a package). Don't forget
-to source the file to make it active in the current shell.
-
-```
-sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
-source /etc/bash_completion.d/<myprogram>
-```
-
-Alternatively, you can just document that users should source the generic
-`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set
-to the name of their program (as above).
-
-#### Customization
-
-The default bash completion flag (`--generate-bash-completion`) is defined as
-`cli.BashCompletionFlag`, and may be redefined if desired, e.g.:
-
-<!-- {
- "args": ["&#45;&#45;compgen"],
- "output": "wat\nhelp\nh"
-} -->
-``` go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- cli.BashCompletionFlag = cli.BoolFlag{
- Name: "compgen",
- Hidden: true,
- }
-
- app := cli.NewApp()
- app.EnableBashCompletion = true
- app.Commands = []cli.Command{
- {
- Name: "wat",
- },
- }
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-### Generated Help Text
-
-The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked
-by the cli internals in order to print generated help text for the app, command,
-or subcommand, and break execution.
-
-#### Customization
-
-All of the help text generation may be customized, and at multiple levels. The
-templates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and
-`SubcommandHelpTemplate` which may be reassigned or augmented, and full override
-is possible by assigning a compatible func to the `cli.HelpPrinter` variable,
-e.g.:
-
-<!-- {
- "output": "Ha HA. I pwnd the help!!1"
-} -->
-``` go
-package main
-
-import (
- "fmt"
- "log"
- "io"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- // EXAMPLE: Append to an existing template
- cli.AppHelpTemplate = fmt.Sprintf(`%s
-
-WEBSITE: http://awesometown.example.com
-
-SUPPORT: support@awesometown.example.com
-
-`, cli.AppHelpTemplate)
-
- // EXAMPLE: Override a template
- cli.AppHelpTemplate = `NAME:
- {{.Name}} - {{.Usage}}
-USAGE:
- {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
- {{if len .Authors}}
-AUTHOR:
- {{range .Authors}}{{ . }}{{end}}
- {{end}}{{if .Commands}}
-COMMANDS:
-{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
-GLOBAL OPTIONS:
- {{range .VisibleFlags}}{{.}}
- {{end}}{{end}}{{if .Copyright }}
-COPYRIGHT:
- {{.Copyright}}
- {{end}}{{if .Version}}
-VERSION:
- {{.Version}}
- {{end}}
-`
-
- // EXAMPLE: Replace the `HelpPrinter` func
- cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
- fmt.Println("Ha HA. I pwnd the help!!1")
- }
-
- err := cli.NewApp().Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-The default flag may be customized to something other than `-h/--help` by
-setting `cli.HelpFlag`, e.g.:
-
-<!-- {
- "args": ["&#45;&#45halp"],
- "output": "haaaaalp.*HALP"
-} -->
-``` go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- cli.HelpFlag = cli.BoolFlag{
- Name: "halp, haaaaalp",
- Usage: "HALP",
- EnvVar: "SHOW_HALP,HALPPLZ",
- }
-
- err := cli.NewApp().Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-### Version Flag
-
-The default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which
-is checked by the cli internals in order to print the `App.Version` via
-`cli.VersionPrinter` and break execution.
-
-#### Customization
-
-The default flag may be customized to something other than `-v/--version` by
-setting `cli.VersionFlag`, e.g.:
-
-<!-- {
- "args": ["&#45;&#45print-version"],
- "output": "partay version 19\\.99\\.0"
-} -->
-``` go
-package main
-
-import (
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-func main() {
- cli.VersionFlag = cli.BoolFlag{
- Name: "print-version, V",
- Usage: "print only the version",
- }
-
- app := cli.NewApp()
- app.Name = "partay"
- app.Version = "19.99.0"
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-Alternatively, the version printer at `cli.VersionPrinter` may be overridden, e.g.:
-
-<!-- {
- "args": ["&#45;&#45version"],
- "output": "version=19\\.99\\.0 revision=fafafaf"
-} -->
-``` go
-package main
-
-import (
- "fmt"
- "log"
- "os"
-
- "github.com/urfave/cli"
-)
-
-var (
- Revision = "fafafaf"
-)
-
-func main() {
- cli.VersionPrinter = func(c *cli.Context) {
- fmt.Printf("version=%s revision=%s\n", c.App.Version, Revision)
- }
-
- app := cli.NewApp()
- app.Name = "partay"
- app.Version = "19.99.0"
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
-}
-```
-
-#### Full API Example
-
-**Notice**: This is a contrived (functioning) example meant strictly for API
-demonstration purposes. Use of one's imagination is encouraged.
-
-<!-- {
- "output": "made it!\nPhew!"
-} -->
-``` go
-package main
-
-import (
- "errors"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "time"
-
- "github.com/urfave/cli"
-)
-
-func init() {
- cli.AppHelpTemplate += "\nCUSTOMIZED: you bet ur muffins\n"
- cli.CommandHelpTemplate += "\nYMMV\n"
- cli.SubcommandHelpTemplate += "\nor something\n"
-
- cli.HelpFlag = cli.BoolFlag{Name: "halp"}
- cli.BashCompletionFlag = cli.BoolFlag{Name: "compgen", Hidden: true}
- cli.VersionFlag = cli.BoolFlag{Name: "print-version, V"}
-
- cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
- fmt.Fprintf(w, "best of luck to you\n")
- }
- cli.VersionPrinter = func(c *cli.Context) {
- fmt.Fprintf(c.App.Writer, "version=%s\n", c.App.Version)
- }
- cli.OsExiter = func(c int) {
- fmt.Fprintf(cli.ErrWriter, "refusing to exit %d\n", c)
- }
- cli.ErrWriter = ioutil.Discard
- cli.FlagStringer = func(fl cli.Flag) string {
- return fmt.Sprintf("\t\t%s", fl.GetName())
- }
-}
-
-type hexWriter struct{}
-
-func (w *hexWriter) Write(p []byte) (int, error) {
- for _, b := range p {
- fmt.Printf("%x", b)
- }
- fmt.Printf("\n")
-
- return len(p), nil
-}
-
-type genericType struct{
- s string
-}
-
-func (g *genericType) Set(value string) error {
- g.s = value
- return nil
-}
-
-func (g *genericType) String() string {
- return g.s
-}
-
-func main() {
- app := cli.NewApp()
- app.Name = "kənˈtrīv"
- app.Version = "19.99.0"
- app.Compiled = time.Now()
- app.Authors = []cli.Author{
- cli.Author{
- Name: "Example Human",
- Email: "human@example.com",
- },
- }
- app.Copyright = "(c) 1999 Serious Enterprise"
- app.HelpName = "contrive"
- app.Usage = "demonstrate available API"
- app.UsageText = "contrive - demonstrating the available API"
- app.ArgsUsage = "[args and such]"
- app.Commands = []cli.Command{
- cli.Command{
- Name: "doo",
- Aliases: []string{"do"},
- Category: "motion",
- Usage: "do the doo",
- UsageText: "doo - does the dooing",
- Description: "no really, there is a lot of dooing to be done",
- ArgsUsage: "[arrgh]",
- Flags: []cli.Flag{
- cli.BoolFlag{Name: "forever, forevvarr"},
- },
- Subcommands: cli.Commands{
- cli.Command{
- Name: "wop",
- Action: wopAction,
- },
- },
- SkipFlagParsing: false,
- HideHelp: false,
- Hidden: false,
- HelpName: "doo!",
- BashComplete: func(c *cli.Context) {
- fmt.Fprintf(c.App.Writer, "--better\n")
- },
- Before: func(c *cli.Context) error {
- fmt.Fprintf(c.App.Writer, "brace for impact\n")
- return nil
- },
- After: func(c *cli.Context) error {
- fmt.Fprintf(c.App.Writer, "did we lose anyone?\n")
- return nil
- },
- Action: func(c *cli.Context) error {
- c.Command.FullName()
- c.Command.HasName("wop")
- c.Command.Names()
- c.Command.VisibleFlags()
- fmt.Fprintf(c.App.Writer, "dodododododoodododddooooododododooo\n")
- if c.Bool("forever") {
- c.Command.Run(c)
- }
- return nil
- },
- OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error {
- fmt.Fprintf(c.App.Writer, "for shame\n")
- return err
- },
- },
- }
- app.Flags = []cli.Flag{
- cli.BoolFlag{Name: "fancy"},
- cli.BoolTFlag{Name: "fancier"},
- cli.DurationFlag{Name: "howlong, H", Value: time.Second * 3},
- cli.Float64Flag{Name: "howmuch"},
- cli.GenericFlag{Name: "wat", Value: &genericType{}},
- cli.Int64Flag{Name: "longdistance"},
- cli.Int64SliceFlag{Name: "intervals"},
- cli.IntFlag{Name: "distance"},
- cli.IntSliceFlag{Name: "times"},
- cli.StringFlag{Name: "dance-move, d"},
- cli.StringSliceFlag{Name: "names, N"},
- cli.UintFlag{Name: "age"},
- cli.Uint64Flag{Name: "bigage"},
- }
- app.EnableBashCompletion = true
- app.HideHelp = false
- app.HideVersion = false
- app.BashComplete = func(c *cli.Context) {
- fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n")
- }
- app.Before = func(c *cli.Context) error {
- fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n")
- return nil
- }
- app.After = func(c *cli.Context) error {
- fmt.Fprintf(c.App.Writer, "Phew!\n")
- return nil
- }
- app.CommandNotFound = func(c *cli.Context, command string) {
- fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command)
- }
- app.OnUsageError = func(c *cli.Context, err error, isSubcommand bool) error {
- if isSubcommand {
- return err
- }
-
- fmt.Fprintf(c.App.Writer, "WRONG: %#v\n", err)
- return nil
- }
- app.Action = func(c *cli.Context) error {
- cli.DefaultAppComplete(c)
- cli.HandleExitCoder(errors.New("not an exit coder, though"))
- cli.ShowAppHelp(c)
- cli.ShowCommandCompletions(c, "nope")
- cli.ShowCommandHelp(c, "also-nope")
- cli.ShowCompletions(c)
- cli.ShowSubcommandHelp(c)
- cli.ShowVersion(c)
-
- categories := c.App.Categories()
- categories.AddCommand("sounds", cli.Command{
- Name: "bloop",
- })
-
- for _, category := range c.App.Categories() {
- fmt.Fprintf(c.App.Writer, "%s\n", category.Name)
- fmt.Fprintf(c.App.Writer, "%#v\n", category.Commands)
- fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands())
- }
-
- fmt.Printf("%#v\n", c.App.Command("doo"))
- if c.Bool("infinite") {
- c.App.Run([]string{"app", "doo", "wop"})
- }
-
- if c.Bool("forevar") {
- c.App.RunAsSubcommand(c)
- }
- c.App.Setup()
- fmt.Printf("%#v\n", c.App.VisibleCategories())
- fmt.Printf("%#v\n", c.App.VisibleCommands())
- fmt.Printf("%#v\n", c.App.VisibleFlags())
-
- fmt.Printf("%#v\n", c.Args().First())
- if len(c.Args()) > 0 {
- fmt.Printf("%#v\n", c.Args()[1])
- }
- fmt.Printf("%#v\n", c.Args().Present())
- fmt.Printf("%#v\n", c.Args().Tail())
-
- set := flag.NewFlagSet("contrive", 0)
- nc := cli.NewContext(c.App, set, c)
-
- fmt.Printf("%#v\n", nc.Args())
- fmt.Printf("%#v\n", nc.Bool("nope"))
- fmt.Printf("%#v\n", nc.BoolT("nerp"))
- fmt.Printf("%#v\n", nc.Duration("howlong"))
- fmt.Printf("%#v\n", nc.Float64("hay"))
- fmt.Printf("%#v\n", nc.Generic("bloop"))
- fmt.Printf("%#v\n", nc.Int64("bonk"))
- fmt.Printf("%#v\n", nc.Int64Slice("burnks"))
- fmt.Printf("%#v\n", nc.Int("bips"))
- fmt.Printf("%#v\n", nc.IntSlice("blups"))
- fmt.Printf("%#v\n", nc.String("snurt"))
- fmt.Printf("%#v\n", nc.StringSlice("snurkles"))
- fmt.Printf("%#v\n", nc.Uint("flub"))
- fmt.Printf("%#v\n", nc.Uint64("florb"))
- fmt.Printf("%#v\n", nc.GlobalBool("global-nope"))
- fmt.Printf("%#v\n", nc.GlobalBoolT("global-nerp"))
- fmt.Printf("%#v\n", nc.GlobalDuration("global-howlong"))
- fmt.Printf("%#v\n", nc.GlobalFloat64("global-hay"))
- fmt.Printf("%#v\n", nc.GlobalGeneric("global-bloop"))
- fmt.Printf("%#v\n", nc.GlobalInt("global-bips"))
- fmt.Printf("%#v\n", nc.GlobalIntSlice("global-blups"))
- fmt.Printf("%#v\n", nc.GlobalString("global-snurt"))
- fmt.Printf("%#v\n", nc.GlobalStringSlice("global-snurkles"))
-
- fmt.Printf("%#v\n", nc.FlagNames())
- fmt.Printf("%#v\n", nc.GlobalFlagNames())
- fmt.Printf("%#v\n", nc.GlobalIsSet("wat"))
- fmt.Printf("%#v\n", nc.GlobalSet("wat", "nope"))
- fmt.Printf("%#v\n", nc.NArg())
- fmt.Printf("%#v\n", nc.NumFlags())
- fmt.Printf("%#v\n", nc.Parent())
-
- nc.Set("wat", "also-nope")
-
- ec := cli.NewExitError("ohwell", 86)
- fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode())
- fmt.Printf("made it!\n")
- return nil
- }
-
- if os.Getenv("HEXY") != "" {
- app.Writer = &hexWriter{}
- app.ErrWriter = &hexWriter{}
- }
-
- app.Metadata = map[string]interface{}{
- "layers": "many",
- "explicable": false,
- "whatever-values": 19.99,
- }
-
-
- // ignore error so we don't exit non-zero and break gfmrun README example tests
- _ = app.Run(os.Args)
-}
-
-func wopAction(c *cli.Context) error {
- fmt.Fprintf(c.App.Writer, ":wave: over here, eh\n")
- return nil
-}
-```
-
-### Combining short Bool options
-
-Traditional use of boolean options using their shortnames look like this:
-```
-# cmd foobar -s -o
-```
-
-Suppose you want users to be able to combine your bool options with their shortname. This
-can be done using the **UseShortOptionHandling** bool in your commands. Suppose your program
-has a two bool flags such as *serve* and *option* with the short options of *-o* and
-*-s* respectively. With **UseShortOptionHandling** set to *true*, a user can use a syntax
-like:
-```
-# cmd foobar -so
-```
-
-If you enable the **UseShortOptionHandling*, then you must not use any flags that have a single
-leading *-* or this will result in failures. For example, **-option** can no longer be used. Flags
-with two leading dashes (such as **--options**) are still valid.
-
-## Contribution Guidelines
-
-See [./CONTRIBUTING.md](./CONTRIBUTING.md)
diff --git a/vendor/github.com/urfave/cli/app.go b/vendor/github.com/urfave/cli/app.go
deleted file mode 100644
index 9add067b0..000000000
--- a/vendor/github.com/urfave/cli/app.go
+++ /dev/null
@@ -1,508 +0,0 @@
-package cli
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "time"
-)
-
-var (
- changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md"
- appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL)
- runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL)
-
- contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you."
-
- errInvalidActionType = NewExitError("ERROR invalid Action type. "+
- fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+
- fmt.Sprintf("See %s", appActionDeprecationURL), 2)
-)
-
-// App is the main structure of a cli application. It is recommended that
-// an app be created with the cli.NewApp() function
-type App struct {
- // The name of the program. Defaults to path.Base(os.Args[0])
- Name string
- // Full name of command for help, defaults to Name
- HelpName string
- // Description of the program.
- Usage string
- // Text to override the USAGE section of help
- UsageText string
- // Description of the program argument format.
- ArgsUsage string
- // Version of the program
- Version string
- // Description of the program
- Description string
- // List of commands to execute
- Commands []Command
- // List of flags to parse
- Flags []Flag
- // Boolean to enable bash completion commands
- EnableBashCompletion bool
- // Boolean to hide built-in help command
- HideHelp bool
- // Boolean to hide built-in version flag and the VERSION section of help
- HideVersion bool
- // Populate on app startup, only gettable through method Categories()
- categories CommandCategories
- // An action to execute when the bash-completion flag is set
- BashComplete BashCompleteFunc
- // An action to execute before any subcommands are run, but after the context is ready
- // If a non-nil error is returned, no subcommands are run
- Before BeforeFunc
- // An action to execute after any subcommands are run, but after the subcommand has finished
- // It is run even if Action() panics
- After AfterFunc
-
- // The action to execute when no subcommands are specified
- // Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}`
- // *Note*: support for the deprecated `Action` signature will be removed in a future version
- Action interface{}
-
- // Execute this function if the proper command cannot be found
- CommandNotFound CommandNotFoundFunc
- // Execute this function if an usage error occurs
- OnUsageError OnUsageErrorFunc
- // Compilation date
- Compiled time.Time
- // List of all authors who contributed
- Authors []Author
- // Copyright of the binary if any
- Copyright string
- // Name of Author (Note: Use App.Authors, this is deprecated)
- Author string
- // Email of Author (Note: Use App.Authors, this is deprecated)
- Email string
- // Writer writer to write output to
- Writer io.Writer
- // ErrWriter writes error output
- ErrWriter io.Writer
- // Execute this function to handle ExitErrors. If not provided, HandleExitCoder is provided to
- // function as a default, so this is optional.
- ExitErrHandler ExitErrHandlerFunc
- // Other custom info
- Metadata map[string]interface{}
- // Carries a function which returns app specific info.
- ExtraInfo func() map[string]string
- // CustomAppHelpTemplate the text template for app help topic.
- // cli.go uses text/template to render templates. You can
- // render custom help text by setting this variable.
- CustomAppHelpTemplate string
-
- didSetup bool
-}
-
-// Tries to find out when this binary was compiled.
-// Returns the current time if it fails to find it.
-func compileTime() time.Time {
- info, err := os.Stat(os.Args[0])
- if err != nil {
- return time.Now()
- }
- return info.ModTime()
-}
-
-// NewApp creates a new cli Application with some reasonable defaults for Name,
-// Usage, Version and Action.
-func NewApp() *App {
- return &App{
- Name: filepath.Base(os.Args[0]),
- HelpName: filepath.Base(os.Args[0]),
- Usage: "A new cli application",
- UsageText: "",
- Version: "0.0.0",
- BashComplete: DefaultAppComplete,
- Action: helpCommand.Action,
- Compiled: compileTime(),
- Writer: os.Stdout,
- }
-}
-
-// Setup runs initialization code to ensure all data structures are ready for
-// `Run` or inspection prior to `Run`. It is internally called by `Run`, but
-// will return early if setup has already happened.
-func (a *App) Setup() {
- if a.didSetup {
- return
- }
-
- a.didSetup = true
-
- if a.Author != "" || a.Email != "" {
- a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
- }
-
- newCmds := []Command{}
- for _, c := range a.Commands {
- if c.HelpName == "" {
- c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
- }
- newCmds = append(newCmds, c)
- }
- a.Commands = newCmds
-
- if a.Command(helpCommand.Name) == nil && !a.HideHelp {
- a.Commands = append(a.Commands, helpCommand)
- if (HelpFlag != BoolFlag{}) {
- a.appendFlag(HelpFlag)
- }
- }
-
- if !a.HideVersion {
- a.appendFlag(VersionFlag)
- }
-
- a.categories = CommandCategories{}
- for _, command := range a.Commands {
- a.categories = a.categories.AddCommand(command.Category, command)
- }
- sort.Sort(a.categories)
-
- if a.Metadata == nil {
- a.Metadata = make(map[string]interface{})
- }
-
- if a.Writer == nil {
- a.Writer = os.Stdout
- }
-}
-
-// Run is the entry point to the cli app. Parses the arguments slice and routes
-// to the proper flag/args combination
-func (a *App) Run(arguments []string) (err error) {
- a.Setup()
-
- // handle the completion flag separately from the flagset since
- // completion could be attempted after a flag, but before its value was put
- // on the command line. this causes the flagset to interpret the completion
- // flag name as the value of the flag before it which is undesirable
- // note that we can only do this because the shell autocomplete function
- // always appends the completion flag at the end of the command
- shellComplete, arguments := checkShellCompleteFlag(a, arguments)
-
- // parse flags
- set, err := flagSet(a.Name, a.Flags)
- if err != nil {
- return err
- }
-
- set.SetOutput(ioutil.Discard)
- err = set.Parse(arguments[1:])
- nerr := normalizeFlags(a.Flags, set)
- context := NewContext(a, set, nil)
- if nerr != nil {
- fmt.Fprintln(a.Writer, nerr)
- ShowAppHelp(context)
- return nerr
- }
- context.shellComplete = shellComplete
-
- if checkCompletions(context) {
- return nil
- }
-
- if err != nil {
- if a.OnUsageError != nil {
- err := a.OnUsageError(context, err, false)
- a.handleExitCoder(context, err)
- return err
- }
- fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
- ShowAppHelp(context)
- return err
- }
-
- if !a.HideHelp && checkHelp(context) {
- ShowAppHelp(context)
- return nil
- }
-
- if !a.HideVersion && checkVersion(context) {
- ShowVersion(context)
- return nil
- }
-
- if a.After != nil {
- defer func() {
- if afterErr := a.After(context); afterErr != nil {
- if err != nil {
- err = NewMultiError(err, afterErr)
- } else {
- err = afterErr
- }
- }
- }()
- }
-
- if a.Before != nil {
- beforeErr := a.Before(context)
- if beforeErr != nil {
- fmt.Fprintf(a.Writer, "%v\n\n", beforeErr)
- ShowAppHelp(context)
- a.handleExitCoder(context, beforeErr)
- err = beforeErr
- return err
- }
- }
-
- args := context.Args()
- if args.Present() {
- name := args.First()
- c := a.Command(name)
- if c != nil {
- return c.Run(context)
- }
- }
-
- if a.Action == nil {
- a.Action = helpCommand.Action
- }
-
- // Run default Action
- err = HandleAction(a.Action, context)
-
- a.handleExitCoder(context, err)
- return err
-}
-
-// RunAndExitOnError calls .Run() and exits non-zero if an error was returned
-//
-// Deprecated: instead you should return an error that fulfills cli.ExitCoder
-// to cli.App.Run. This will cause the application to exit with the given eror
-// code in the cli.ExitCoder
-func (a *App) RunAndExitOnError() {
- if err := a.Run(os.Args); err != nil {
- fmt.Fprintln(a.errWriter(), err)
- OsExiter(1)
- }
-}
-
-// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
-// generate command-specific flags
-func (a *App) RunAsSubcommand(ctx *Context) (err error) {
- // append help to commands
- if len(a.Commands) > 0 {
- if a.Command(helpCommand.Name) == nil && !a.HideHelp {
- a.Commands = append(a.Commands, helpCommand)
- if (HelpFlag != BoolFlag{}) {
- a.appendFlag(HelpFlag)
- }
- }
- }
-
- newCmds := []Command{}
- for _, c := range a.Commands {
- if c.HelpName == "" {
- c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
- }
- newCmds = append(newCmds, c)
- }
- a.Commands = newCmds
-
- // parse flags
- set, err := flagSet(a.Name, a.Flags)
- if err != nil {
- return err
- }
-
- set.SetOutput(ioutil.Discard)
- err = set.Parse(ctx.Args().Tail())
- nerr := normalizeFlags(a.Flags, set)
- context := NewContext(a, set, ctx)
-
- if nerr != nil {
- fmt.Fprintln(a.Writer, nerr)
- fmt.Fprintln(a.Writer)
- if len(a.Commands) > 0 {
- ShowSubcommandHelp(context)
- } else {
- ShowCommandHelp(ctx, context.Args().First())
- }
- return nerr
- }
-
- if checkCompletions(context) {
- return nil
- }
-
- if err != nil {
- if a.OnUsageError != nil {
- err = a.OnUsageError(context, err, true)
- a.handleExitCoder(context, err)
- return err
- }
- fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
- ShowSubcommandHelp(context)
- return err
- }
-
- if len(a.Commands) > 0 {
- if checkSubcommandHelp(context) {
- return nil
- }
- } else {
- if checkCommandHelp(ctx, context.Args().First()) {
- return nil
- }
- }
-
- if a.After != nil {
- defer func() {
- afterErr := a.After(context)
- if afterErr != nil {
- a.handleExitCoder(context, err)
- if err != nil {
- err = NewMultiError(err, afterErr)
- } else {
- err = afterErr
- }
- }
- }()
- }
-
- if a.Before != nil {
- beforeErr := a.Before(context)
- if beforeErr != nil {
- a.handleExitCoder(context, beforeErr)
- err = beforeErr
- return err
- }
- }
-
- args := context.Args()
- if args.Present() {
- name := args.First()
- c := a.Command(name)
- if c != nil {
- return c.Run(context)
- }
- }
-
- // Run default Action
- err = HandleAction(a.Action, context)
-
- a.handleExitCoder(context, err)
- return err
-}
-
-// Command returns the named command on App. Returns nil if the command does not exist
-func (a *App) Command(name string) *Command {
- for _, c := range a.Commands {
- if c.HasName(name) {
- return &c
- }
- }
-
- return nil
-}
-
-// Categories returns a slice containing all the categories with the commands they contain
-func (a *App) Categories() CommandCategories {
- return a.categories
-}
-
-// VisibleCategories returns a slice of categories and commands that are
-// Hidden=false
-func (a *App) VisibleCategories() []*CommandCategory {
- ret := []*CommandCategory{}
- for _, category := range a.categories {
- if visible := func() *CommandCategory {
- for _, command := range category.Commands {
- if !command.Hidden {
- return category
- }
- }
- return nil
- }(); visible != nil {
- ret = append(ret, visible)
- }
- }
- return ret
-}
-
-// VisibleCommands returns a slice of the Commands with Hidden=false
-func (a *App) VisibleCommands() []Command {
- ret := []Command{}
- for _, command := range a.Commands {
- if !command.Hidden {
- ret = append(ret, command)
- }
- }
- return ret
-}
-
-// VisibleFlags returns a slice of the Flags with Hidden=false
-func (a *App) VisibleFlags() []Flag {
- return visibleFlags(a.Flags)
-}
-
-func (a *App) hasFlag(flag Flag) bool {
- for _, f := range a.Flags {
- if flag == f {
- return true
- }
- }
-
- return false
-}
-
-func (a *App) errWriter() io.Writer {
- // When the app ErrWriter is nil use the package level one.
- if a.ErrWriter == nil {
- return ErrWriter
- }
-
- return a.ErrWriter
-}
-
-func (a *App) appendFlag(flag Flag) {
- if !a.hasFlag(flag) {
- a.Flags = append(a.Flags, flag)
- }
-}
-
-func (a *App) handleExitCoder(context *Context, err error) {
- if a.ExitErrHandler != nil {
- a.ExitErrHandler(context, err)
- } else {
- HandleExitCoder(err)
- }
-}
-
-// Author represents someone who has contributed to a cli project.
-type Author struct {
- Name string // The Authors name
- Email string // The Authors email
-}
-
-// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
-func (a Author) String() string {
- e := ""
- if a.Email != "" {
- e = " <" + a.Email + ">"
- }
-
- return fmt.Sprintf("%v%v", a.Name, e)
-}
-
-// HandleAction attempts to figure out which Action signature was used. If
-// it's an ActionFunc or a func with the legacy signature for Action, the func
-// is run!
-func HandleAction(action interface{}, context *Context) (err error) {
- if a, ok := action.(ActionFunc); ok {
- return a(context)
- } else if a, ok := action.(func(*Context) error); ok {
- return a(context)
- } else if a, ok := action.(func(*Context)); ok { // deprecated function signature
- a(context)
- return nil
- }
-
- return errInvalidActionType
-}
diff --git a/vendor/github.com/urfave/cli/category.go b/vendor/github.com/urfave/cli/category.go
deleted file mode 100644
index bf3c73c55..000000000
--- a/vendor/github.com/urfave/cli/category.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package cli
-
-// CommandCategories is a slice of *CommandCategory.
-type CommandCategories []*CommandCategory
-
-// CommandCategory is a category containing commands.
-type CommandCategory struct {
- Name string
- Commands Commands
-}
-
-func (c CommandCategories) Less(i, j int) bool {
- return lexicographicLess(c[i].Name, c[j].Name)
-}
-
-func (c CommandCategories) Len() int {
- return len(c)
-}
-
-func (c CommandCategories) Swap(i, j int) {
- c[i], c[j] = c[j], c[i]
-}
-
-// AddCommand adds a command to a category.
-func (c CommandCategories) AddCommand(category string, command Command) CommandCategories {
- for _, commandCategory := range c {
- if commandCategory.Name == category {
- commandCategory.Commands = append(commandCategory.Commands, command)
- return c
- }
- }
- return append(c, &CommandCategory{Name: category, Commands: []Command{command}})
-}
-
-// VisibleCommands returns a slice of the Commands with Hidden=false
-func (c *CommandCategory) VisibleCommands() []Command {
- ret := []Command{}
- for _, command := range c.Commands {
- if !command.Hidden {
- ret = append(ret, command)
- }
- }
- return ret
-}
diff --git a/vendor/github.com/urfave/cli/cli.go b/vendor/github.com/urfave/cli/cli.go
deleted file mode 100644
index 90c07eb8e..000000000
--- a/vendor/github.com/urfave/cli/cli.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// Package cli provides a minimal framework for creating and organizing command line
-// Go applications. cli is designed to be easy to understand and write, the most simple
-// cli application can be written as follows:
-// func main() {
-// cli.NewApp().Run(os.Args)
-// }
-//
-// Of course this application does not do much, so let's make this an actual application:
-// func main() {
-// app := cli.NewApp()
-// app.Name = "greet"
-// app.Usage = "say a greeting"
-// app.Action = func(c *cli.Context) error {
-// println("Greetings")
-// return nil
-// }
-//
-// app.Run(os.Args)
-// }
-package cli
-
-//go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go
diff --git a/vendor/github.com/urfave/cli/command.go b/vendor/github.com/urfave/cli/command.go
deleted file mode 100644
index 3d44404f1..000000000
--- a/vendor/github.com/urfave/cli/command.go
+++ /dev/null
@@ -1,383 +0,0 @@
-package cli
-
-import (
- "flag"
- "fmt"
- "io/ioutil"
- "sort"
- "strings"
-)
-
-// Command is a subcommand for a cli.App.
-type Command struct {
- // The name of the command
- Name string
- // short name of the command. Typically one character (deprecated, use `Aliases`)
- ShortName string
- // A list of aliases for the command
- Aliases []string
- // A short description of the usage of this command
- Usage string
- // Custom text to show on USAGE section of help
- UsageText string
- // A longer explanation of how the command works
- Description string
- // A short description of the arguments of this command
- ArgsUsage string
- // The category the command is part of
- Category string
- // The function to call when checking for bash command completions
- BashComplete BashCompleteFunc
- // An action to execute before any sub-subcommands are run, but after the context is ready
- // If a non-nil error is returned, no sub-subcommands are run
- Before BeforeFunc
- // An action to execute after any subcommands are run, but after the subcommand has finished
- // It is run even if Action() panics
- After AfterFunc
- // The function to call when this command is invoked
- Action interface{}
- // TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind
- // of deprecation period has passed, maybe?
-
- // Execute this function if a usage error occurs.
- OnUsageError OnUsageErrorFunc
- // List of child commands
- Subcommands Commands
- // List of flags to parse
- Flags []Flag
- // Treat all flags as normal arguments if true
- SkipFlagParsing bool
- // Skip argument reordering which attempts to move flags before arguments,
- // but only works if all flags appear after all arguments. This behavior was
- // removed n version 2 since it only works under specific conditions so we
- // backport here by exposing it as an option for compatibility.
- SkipArgReorder bool
- // Boolean to hide built-in help command
- HideHelp bool
- // Boolean to hide this command from help or completion
- Hidden bool
- // Boolean to enable short-option handling so user can combine several
- // single-character bool arguments into one
- // i.e. foobar -o -v -> foobar -ov
- UseShortOptionHandling bool
-
- // Full name of command for help, defaults to full command name, including parent commands.
- HelpName string
- commandNamePath []string
-
- // CustomHelpTemplate the text template for the command help topic.
- // cli.go uses text/template to render templates. You can
- // render custom help text by setting this variable.
- CustomHelpTemplate string
-}
-
-type CommandsByName []Command
-
-func (c CommandsByName) Len() int {
- return len(c)
-}
-
-func (c CommandsByName) Less(i, j int) bool {
- return lexicographicLess(c[i].Name, c[j].Name)
-}
-
-func (c CommandsByName) Swap(i, j int) {
- c[i], c[j] = c[j], c[i]
-}
-
-// FullName returns the full name of the command.
-// For subcommands this ensures that parent commands are part of the command path
-func (c Command) FullName() string {
- if c.commandNamePath == nil {
- return c.Name
- }
- return strings.Join(c.commandNamePath, " ")
-}
-
-// Commands is a slice of Command
-type Commands []Command
-
-// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
-func (c Command) Run(ctx *Context) (err error) {
- if len(c.Subcommands) > 0 {
- return c.startApp(ctx)
- }
-
- if !c.HideHelp && (HelpFlag != BoolFlag{}) {
- // append help to flags
- c.Flags = append(
- c.Flags,
- HelpFlag,
- )
- }
-
- set, err := c.parseFlags(ctx.Args().Tail())
-
- context := NewContext(ctx.App, set, ctx)
- context.Command = c
- if checkCommandCompletions(context, c.Name) {
- return nil
- }
-
- if err != nil {
- if c.OnUsageError != nil {
- err := c.OnUsageError(context, err, false)
- context.App.handleExitCoder(context, err)
- return err
- }
- fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error())
- fmt.Fprintln(context.App.Writer)
- ShowCommandHelp(context, c.Name)
- return err
- }
-
- if checkCommandHelp(context, c.Name) {
- return nil
- }
-
- if c.After != nil {
- defer func() {
- afterErr := c.After(context)
- if afterErr != nil {
- context.App.handleExitCoder(context, err)
- if err != nil {
- err = NewMultiError(err, afterErr)
- } else {
- err = afterErr
- }
- }
- }()
- }
-
- if c.Before != nil {
- err = c.Before(context)
- if err != nil {
- ShowCommandHelp(context, c.Name)
- context.App.handleExitCoder(context, err)
- return err
- }
- }
-
- if c.Action == nil {
- c.Action = helpSubcommand.Action
- }
-
- err = HandleAction(c.Action, context)
-
- if err != nil {
- context.App.handleExitCoder(context, err)
- }
- return err
-}
-
-func (c *Command) parseFlags(args Args) (*flag.FlagSet, error) {
- set, err := flagSet(c.Name, c.Flags)
- if err != nil {
- return nil, err
- }
- set.SetOutput(ioutil.Discard)
-
- if c.SkipFlagParsing {
- return set, set.Parse(append([]string{"--"}, args...))
- }
-
- if !c.SkipArgReorder {
- args = reorderArgs(args)
- }
-
-PARSE:
- err = set.Parse(args)
- if err != nil {
- if c.UseShortOptionHandling {
- // To enable short-option handling (e.g., "-it" vs "-i -t")
- // we have to iteratively catch parsing errors. This way
- // we achieve LR parsing without transforming any arguments.
- // Otherwise, there is no way we can discriminate combined
- // short options from common arguments that should be left
- // untouched.
- errStr := err.Error()
- trimmed := strings.TrimPrefix(errStr, "flag provided but not defined: ")
- if errStr == trimmed {
- return nil, err
- }
- // regenerate the initial args with the split short opts
- newArgs := Args{}
- for i, arg := range args {
- if arg != trimmed {
- newArgs = append(newArgs, arg)
- continue
- }
- shortOpts := translateShortOptions(set, Args{trimmed})
- if len(shortOpts) == 1 {
- return nil, err
- }
- // add each short option and all remaining arguments
- newArgs = append(newArgs, shortOpts...)
- newArgs = append(newArgs, args[i+1:]...)
- args = newArgs
- // now reset the flagset parse again
- set, err = flagSet(c.Name, c.Flags)
- if err != nil {
- return nil, err
- }
- set.SetOutput(ioutil.Discard)
- goto PARSE
- }
- }
- return nil, err
- }
-
- err = normalizeFlags(c.Flags, set)
- if err != nil {
- return nil, err
- }
-
- return set, nil
-}
-
-// reorderArgs moves all flags before arguments as this is what flag expects
-func reorderArgs(args []string) []string {
- var nonflags, flags []string
-
- readFlagValue := false
- for i, arg := range args {
- if arg == "--" {
- nonflags = append(nonflags, args[i:]...)
- break
- }
-
- if readFlagValue && !strings.HasPrefix(arg, "-") && !strings.HasPrefix(arg, "--") {
- readFlagValue = false
- flags = append(flags, arg)
- continue
- }
- readFlagValue = false
-
- if arg != "-" && strings.HasPrefix(arg, "-") {
- flags = append(flags, arg)
-
- readFlagValue = !strings.Contains(arg, "=")
- } else {
- nonflags = append(nonflags, arg)
- }
- }
-
- return append(flags, nonflags...)
-}
-
-func translateShortOptions(set *flag.FlagSet, flagArgs Args) []string {
- allCharsFlags := func (s string) bool {
- for i := range s {
- f := set.Lookup(string(s[i]))
- if f == nil {
- return false
- }
- }
- return true
- }
-
- // separate combined flags
- var flagArgsSeparated []string
- for _, flagArg := range flagArgs {
- if strings.HasPrefix(flagArg, "-") && strings.HasPrefix(flagArg, "--") == false && len(flagArg) > 2 {
- if !allCharsFlags(flagArg[1:]) {
- flagArgsSeparated = append(flagArgsSeparated, flagArg)
- continue
- }
- for _, flagChar := range flagArg[1:] {
- flagArgsSeparated = append(flagArgsSeparated, "-"+string(flagChar))
- }
- } else {
- flagArgsSeparated = append(flagArgsSeparated, flagArg)
- }
- }
- return flagArgsSeparated
-}
-
-// Names returns the names including short names and aliases.
-func (c Command) Names() []string {
- names := []string{c.Name}
-
- if c.ShortName != "" {
- names = append(names, c.ShortName)
- }
-
- return append(names, c.Aliases...)
-}
-
-// HasName returns true if Command.Name or Command.ShortName matches given name
-func (c Command) HasName(name string) bool {
- for _, n := range c.Names() {
- if n == name {
- return true
- }
- }
- return false
-}
-
-func (c Command) startApp(ctx *Context) error {
- app := NewApp()
- app.Metadata = ctx.App.Metadata
- // set the name and usage
- app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
- if c.HelpName == "" {
- app.HelpName = c.HelpName
- } else {
- app.HelpName = app.Name
- }
-
- app.Usage = c.Usage
- app.Description = c.Description
- app.ArgsUsage = c.ArgsUsage
-
- // set CommandNotFound
- app.CommandNotFound = ctx.App.CommandNotFound
- app.CustomAppHelpTemplate = c.CustomHelpTemplate
-
- // set the flags and commands
- app.Commands = c.Subcommands
- app.Flags = c.Flags
- app.HideHelp = c.HideHelp
-
- app.Version = ctx.App.Version
- app.HideVersion = ctx.App.HideVersion
- app.Compiled = ctx.App.Compiled
- app.Author = ctx.App.Author
- app.Email = ctx.App.Email
- app.Writer = ctx.App.Writer
- app.ErrWriter = ctx.App.ErrWriter
-
- app.categories = CommandCategories{}
- for _, command := range c.Subcommands {
- app.categories = app.categories.AddCommand(command.Category, command)
- }
-
- sort.Sort(app.categories)
-
- // bash completion
- app.EnableBashCompletion = ctx.App.EnableBashCompletion
- if c.BashComplete != nil {
- app.BashComplete = c.BashComplete
- }
-
- // set the actions
- app.Before = c.Before
- app.After = c.After
- if c.Action != nil {
- app.Action = c.Action
- } else {
- app.Action = helpSubcommand.Action
- }
- app.OnUsageError = c.OnUsageError
-
- for index, cc := range app.Commands {
- app.Commands[index].commandNamePath = []string{c.Name, cc.Name}
- }
-
- return app.RunAsSubcommand(ctx)
-}
-
-// VisibleFlags returns a slice of the Flags with Hidden=false
-func (c Command) VisibleFlags() []Flag {
- return visibleFlags(c.Flags)
-}
diff --git a/vendor/github.com/urfave/cli/context.go b/vendor/github.com/urfave/cli/context.go
deleted file mode 100644
index 552ee7405..000000000
--- a/vendor/github.com/urfave/cli/context.go
+++ /dev/null
@@ -1,287 +0,0 @@
-package cli
-
-import (
- "errors"
- "flag"
- "os"
- "reflect"
- "strings"
- "syscall"
-)
-
-// Context is a type that is passed through to
-// each Handler action in a cli application. Context
-// can be used to retrieve context-specific Args and
-// parsed command-line options.
-type Context struct {
- App *App
- Command Command
- shellComplete bool
- flagSet *flag.FlagSet
- setFlags map[string]bool
- parentContext *Context
-}
-
-// NewContext creates a new context. For use in when invoking an App or Command action.
-func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
- c := &Context{App: app, flagSet: set, parentContext: parentCtx}
-
- if parentCtx != nil {
- c.shellComplete = parentCtx.shellComplete
- }
-
- return c
-}
-
-// NumFlags returns the number of flags set
-func (c *Context) NumFlags() int {
- return c.flagSet.NFlag()
-}
-
-// Set sets a context flag to a value.
-func (c *Context) Set(name, value string) error {
- c.setFlags = nil
- return c.flagSet.Set(name, value)
-}
-
-// GlobalSet sets a context flag to a value on the global flagset
-func (c *Context) GlobalSet(name, value string) error {
- globalContext(c).setFlags = nil
- return globalContext(c).flagSet.Set(name, value)
-}
-
-// IsSet determines if the flag was actually set
-func (c *Context) IsSet(name string) bool {
- if c.setFlags == nil {
- c.setFlags = make(map[string]bool)
-
- c.flagSet.Visit(func(f *flag.Flag) {
- c.setFlags[f.Name] = true
- })
-
- c.flagSet.VisitAll(func(f *flag.Flag) {
- if _, ok := c.setFlags[f.Name]; ok {
- return
- }
- c.setFlags[f.Name] = false
- })
-
- // XXX hack to support IsSet for flags with EnvVar
- //
- // There isn't an easy way to do this with the current implementation since
- // whether a flag was set via an environment variable is very difficult to
- // determine here. Instead, we intend to introduce a backwards incompatible
- // change in version 2 to add `IsSet` to the Flag interface to push the
- // responsibility closer to where the information required to determine
- // whether a flag is set by non-standard means such as environment
- // variables is available.
- //
- // See https://github.com/urfave/cli/issues/294 for additional discussion
- flags := c.Command.Flags
- if c.Command.Name == "" { // cannot == Command{} since it contains slice types
- if c.App != nil {
- flags = c.App.Flags
- }
- }
- for _, f := range flags {
- eachName(f.GetName(), func(name string) {
- if isSet, ok := c.setFlags[name]; isSet || !ok {
- return
- }
-
- val := reflect.ValueOf(f)
- if val.Kind() == reflect.Ptr {
- val = val.Elem()
- }
-
- filePathValue := val.FieldByName("FilePath")
- if filePathValue.IsValid() {
- eachName(filePathValue.String(), func(filePath string) {
- if _, err := os.Stat(filePath); err == nil {
- c.setFlags[name] = true
- return
- }
- })
- }
-
- envVarValue := val.FieldByName("EnvVar")
- if envVarValue.IsValid() {
- eachName(envVarValue.String(), func(envVar string) {
- envVar = strings.TrimSpace(envVar)
- if _, ok := syscall.Getenv(envVar); ok {
- c.setFlags[name] = true
- return
- }
- })
- }
- })
- }
- }
-
- return c.setFlags[name]
-}
-
-// GlobalIsSet determines if the global flag was actually set
-func (c *Context) GlobalIsSet(name string) bool {
- ctx := c
- if ctx.parentContext != nil {
- ctx = ctx.parentContext
- }
-
- for ; ctx != nil; ctx = ctx.parentContext {
- if ctx.IsSet(name) {
- return true
- }
- }
- return false
-}
-
-// FlagNames returns a slice of flag names used in this context.
-func (c *Context) FlagNames() (names []string) {
- for _, flag := range c.Command.Flags {
- name := strings.Split(flag.GetName(), ",")[0]
- if name == "help" {
- continue
- }
- names = append(names, name)
- }
- return
-}
-
-// GlobalFlagNames returns a slice of global flag names used by the app.
-func (c *Context) GlobalFlagNames() (names []string) {
- for _, flag := range c.App.Flags {
- name := strings.Split(flag.GetName(), ",")[0]
- if name == "help" || name == "version" {
- continue
- }
- names = append(names, name)
- }
- return
-}
-
-// Parent returns the parent context, if any
-func (c *Context) Parent() *Context {
- return c.parentContext
-}
-
-// value returns the value of the flag coressponding to `name`
-func (c *Context) value(name string) interface{} {
- return c.flagSet.Lookup(name).Value.(flag.Getter).Get()
-}
-
-// Args contains apps console arguments
-type Args []string
-
-// Args returns the command line arguments associated with the context.
-func (c *Context) Args() Args {
- args := Args(c.flagSet.Args())
- return args
-}
-
-// NArg returns the number of the command line arguments.
-func (c *Context) NArg() int {
- return len(c.Args())
-}
-
-// Get returns the nth argument, or else a blank string
-func (a Args) Get(n int) string {
- if len(a) > n {
- return a[n]
- }
- return ""
-}
-
-// First returns the first argument, or else a blank string
-func (a Args) First() string {
- return a.Get(0)
-}
-
-// Tail returns the rest of the arguments (not the first one)
-// or else an empty string slice
-func (a Args) Tail() []string {
- if len(a) >= 2 {
- return []string(a)[1:]
- }
- return []string{}
-}
-
-// Present checks if there are any arguments present
-func (a Args) Present() bool {
- return len(a) != 0
-}
-
-// Swap swaps arguments at the given indexes
-func (a Args) Swap(from, to int) error {
- if from >= len(a) || to >= len(a) {
- return errors.New("index out of range")
- }
- a[from], a[to] = a[to], a[from]
- return nil
-}
-
-func globalContext(ctx *Context) *Context {
- if ctx == nil {
- return nil
- }
-
- for {
- if ctx.parentContext == nil {
- return ctx
- }
- ctx = ctx.parentContext
- }
-}
-
-func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
- if ctx.parentContext != nil {
- ctx = ctx.parentContext
- }
- for ; ctx != nil; ctx = ctx.parentContext {
- if f := ctx.flagSet.Lookup(name); f != nil {
- return ctx.flagSet
- }
- }
- return nil
-}
-
-func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
- switch ff.Value.(type) {
- case *StringSlice:
- default:
- set.Set(name, ff.Value.String())
- }
-}
-
-func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
- visited := make(map[string]bool)
- set.Visit(func(f *flag.Flag) {
- visited[f.Name] = true
- })
- for _, f := range flags {
- parts := strings.Split(f.GetName(), ",")
- if len(parts) == 1 {
- continue
- }
- var ff *flag.Flag
- for _, name := range parts {
- name = strings.Trim(name, " ")
- if visited[name] {
- if ff != nil {
- return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
- }
- ff = set.Lookup(name)
- }
- }
- if ff == nil {
- continue
- }
- for _, name := range parts {
- name = strings.Trim(name, " ")
- if !visited[name] {
- copyFlag(name, ff, set)
- }
- }
- }
- return nil
-}
diff --git a/vendor/github.com/urfave/cli/errors.go b/vendor/github.com/urfave/cli/errors.go
deleted file mode 100644
index 562b2953c..000000000
--- a/vendor/github.com/urfave/cli/errors.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package cli
-
-import (
- "fmt"
- "io"
- "os"
- "strings"
-)
-
-// OsExiter is the function used when the app exits. If not set defaults to os.Exit.
-var OsExiter = os.Exit
-
-// ErrWriter is used to write errors to the user. This can be anything
-// implementing the io.Writer interface and defaults to os.Stderr.
-var ErrWriter io.Writer = os.Stderr
-
-// MultiError is an error that wraps multiple errors.
-type MultiError struct {
- Errors []error
-}
-
-// NewMultiError creates a new MultiError. Pass in one or more errors.
-func NewMultiError(err ...error) MultiError {
- return MultiError{Errors: err}
-}
-
-// Error implements the error interface.
-func (m MultiError) Error() string {
- errs := make([]string, len(m.Errors))
- for i, err := range m.Errors {
- errs[i] = err.Error()
- }
-
- return strings.Join(errs, "\n")
-}
-
-type ErrorFormatter interface {
- Format(s fmt.State, verb rune)
-}
-
-// ExitCoder is the interface checked by `App` and `Command` for a custom exit
-// code
-type ExitCoder interface {
- error
- ExitCode() int
-}
-
-// ExitError fulfills both the builtin `error` interface and `ExitCoder`
-type ExitError struct {
- exitCode int
- message interface{}
-}
-
-// NewExitError makes a new *ExitError
-func NewExitError(message interface{}, exitCode int) *ExitError {
- return &ExitError{
- exitCode: exitCode,
- message: message,
- }
-}
-
-// Error returns the string message, fulfilling the interface required by
-// `error`
-func (ee *ExitError) Error() string {
- return fmt.Sprintf("%v", ee.message)
-}
-
-// ExitCode returns the exit code, fulfilling the interface required by
-// `ExitCoder`
-func (ee *ExitError) ExitCode() int {
- return ee.exitCode
-}
-
-// HandleExitCoder checks if the error fulfills the ExitCoder interface, and if
-// so prints the error to stderr (if it is non-empty) and calls OsExiter with the
-// given exit code. If the given error is a MultiError, then this func is
-// called on all members of the Errors slice and calls OsExiter with the last exit code.
-func HandleExitCoder(err error) {
- if err == nil {
- return
- }
-
- if exitErr, ok := err.(ExitCoder); ok {
- if err.Error() != "" {
- if _, ok := exitErr.(ErrorFormatter); ok {
- fmt.Fprintf(ErrWriter, "%+v\n", err)
- } else {
- fmt.Fprintln(ErrWriter, err)
- }
- }
- OsExiter(exitErr.ExitCode())
- return
- }
-
- if multiErr, ok := err.(MultiError); ok {
- code := handleMultiError(multiErr)
- OsExiter(code)
- return
- }
-}
-
-func handleMultiError(multiErr MultiError) int {
- code := 1
- for _, merr := range multiErr.Errors {
- if multiErr2, ok := merr.(MultiError); ok {
- code = handleMultiError(multiErr2)
- } else {
- fmt.Fprintln(ErrWriter, merr)
- if exitErr, ok := merr.(ExitCoder); ok {
- code = exitErr.ExitCode()
- }
- }
- }
- return code
-}
diff --git a/vendor/github.com/urfave/cli/flag.go b/vendor/github.com/urfave/cli/flag.go
deleted file mode 100644
index b0cffc006..000000000
--- a/vendor/github.com/urfave/cli/flag.go
+++ /dev/null
@@ -1,786 +0,0 @@
-package cli
-
-import (
- "flag"
- "fmt"
- "io/ioutil"
- "reflect"
- "runtime"
- "strconv"
- "strings"
- "syscall"
- "time"
-)
-
-const defaultPlaceholder = "value"
-
-// BashCompletionFlag enables bash-completion for all commands and subcommands
-var BashCompletionFlag Flag = BoolFlag{
- Name: "generate-bash-completion",
- Hidden: true,
-}
-
-// VersionFlag prints the version for the application
-var VersionFlag Flag = BoolFlag{
- Name: "version, v",
- Usage: "print the version",
-}
-
-// HelpFlag prints the help for all commands and subcommands
-// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
-// unless HideHelp is set to true)
-var HelpFlag Flag = BoolFlag{
- Name: "help, h",
- Usage: "show help",
-}
-
-// FlagStringer converts a flag definition to a string. This is used by help
-// to display a flag.
-var FlagStringer FlagStringFunc = stringifyFlag
-
-// FlagNamePrefixer converts a full flag name and its placeholder into the help
-// message flag prefix. This is used by the default FlagStringer.
-var FlagNamePrefixer FlagNamePrefixFunc = prefixedNames
-
-// FlagEnvHinter annotates flag help message with the environment variable
-// details. This is used by the default FlagStringer.
-var FlagEnvHinter FlagEnvHintFunc = withEnvHint
-
-// FlagFileHinter annotates flag help message with the environment variable
-// details. This is used by the default FlagStringer.
-var FlagFileHinter FlagFileHintFunc = withFileHint
-
-// FlagsByName is a slice of Flag.
-type FlagsByName []Flag
-
-func (f FlagsByName) Len() int {
- return len(f)
-}
-
-func (f FlagsByName) Less(i, j int) bool {
- return lexicographicLess(f[i].GetName(), f[j].GetName())
-}
-
-func (f FlagsByName) Swap(i, j int) {
- f[i], f[j] = f[j], f[i]
-}
-
-// Flag is a common interface related to parsing flags in cli.
-// For more advanced flag parsing techniques, it is recommended that
-// this interface be implemented.
-type Flag interface {
- fmt.Stringer
- // Apply Flag settings to the given flag set
- Apply(*flag.FlagSet)
- GetName() string
-}
-
-// errorableFlag is an interface that allows us to return errors during apply
-// it allows flags defined in this library to return errors in a fashion backwards compatible
-// TODO remove in v2 and modify the existing Flag interface to return errors
-type errorableFlag interface {
- Flag
-
- ApplyWithError(*flag.FlagSet) error
-}
-
-func flagSet(name string, flags []Flag) (*flag.FlagSet, error) {
- set := flag.NewFlagSet(name, flag.ContinueOnError)
-
- for _, f := range flags {
- //TODO remove in v2 when errorableFlag is removed
- if ef, ok := f.(errorableFlag); ok {
- if err := ef.ApplyWithError(set); err != nil {
- return nil, err
- }
- } else {
- f.Apply(set)
- }
- }
- return set, nil
-}
-
-func eachName(longName string, fn func(string)) {
- parts := strings.Split(longName, ",")
- for _, name := range parts {
- name = strings.Trim(name, " ")
- fn(name)
- }
-}
-
-// Generic is a generic parseable type identified by a specific flag
-type Generic interface {
- Set(value string) error
- String() string
-}
-
-// Apply takes the flagset and calls Set on the generic flag with the value
-// provided by the user for parsing by the flag
-// Ignores parsing errors
-func (f GenericFlag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError takes the flagset and calls Set on the generic flag with the value
-// provided by the user for parsing by the flag
-func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error {
- val := f.Value
- if fileEnvVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- if err := val.Set(fileEnvVal); err != nil {
- return fmt.Errorf("could not parse %s as value for flag %s: %s", fileEnvVal, f.Name, err)
- }
- }
-
- eachName(f.Name, func(name string) {
- set.Var(f.Value, name, f.Usage)
- })
-
- return nil
-}
-
-// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter
-type StringSlice []string
-
-// Set appends the string value to the list of values
-func (f *StringSlice) Set(value string) error {
- *f = append(*f, value)
- return nil
-}
-
-// String returns a readable representation of this value (for usage defaults)
-func (f *StringSlice) String() string {
- return fmt.Sprintf("%s", *f)
-}
-
-// Value returns the slice of strings set by this flag
-func (f *StringSlice) Value() []string {
- return *f
-}
-
-// Get returns the slice of strings set by this flag
-func (f *StringSlice) Get() interface{} {
- return *f
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f StringSliceFlag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f StringSliceFlag) ApplyWithError(set *flag.FlagSet) error {
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- newVal := &StringSlice{}
- for _, s := range strings.Split(envVal, ",") {
- s = strings.TrimSpace(s)
- if err := newVal.Set(s); err != nil {
- return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err)
- }
- }
- if f.Value == nil {
- f.Value = newVal
- } else {
- *f.Value = *newVal
- }
- }
-
- eachName(f.Name, func(name string) {
- if f.Value == nil {
- f.Value = &StringSlice{}
- }
- set.Var(f.Value, name, f.Usage)
- })
-
- return nil
-}
-
-// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter
-type IntSlice []int
-
-// Set parses the value into an integer and appends it to the list of values
-func (f *IntSlice) Set(value string) error {
- tmp, err := strconv.Atoi(value)
- if err != nil {
- return err
- }
- *f = append(*f, tmp)
- return nil
-}
-
-// String returns a readable representation of this value (for usage defaults)
-func (f *IntSlice) String() string {
- return fmt.Sprintf("%#v", *f)
-}
-
-// Value returns the slice of ints set by this flag
-func (f *IntSlice) Value() []int {
- return *f
-}
-
-// Get returns the slice of ints set by this flag
-func (f *IntSlice) Get() interface{} {
- return *f
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f IntSliceFlag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f IntSliceFlag) ApplyWithError(set *flag.FlagSet) error {
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- newVal := &IntSlice{}
- for _, s := range strings.Split(envVal, ",") {
- s = strings.TrimSpace(s)
- if err := newVal.Set(s); err != nil {
- return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err)
- }
- }
- if f.Value == nil {
- f.Value = newVal
- } else {
- *f.Value = *newVal
- }
- }
-
- eachName(f.Name, func(name string) {
- if f.Value == nil {
- f.Value = &IntSlice{}
- }
- set.Var(f.Value, name, f.Usage)
- })
-
- return nil
-}
-
-// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter
-type Int64Slice []int64
-
-// Set parses the value into an integer and appends it to the list of values
-func (f *Int64Slice) Set(value string) error {
- tmp, err := strconv.ParseInt(value, 10, 64)
- if err != nil {
- return err
- }
- *f = append(*f, tmp)
- return nil
-}
-
-// String returns a readable representation of this value (for usage defaults)
-func (f *Int64Slice) String() string {
- return fmt.Sprintf("%#v", *f)
-}
-
-// Value returns the slice of ints set by this flag
-func (f *Int64Slice) Value() []int64 {
- return *f
-}
-
-// Get returns the slice of ints set by this flag
-func (f *Int64Slice) Get() interface{} {
- return *f
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f Int64SliceFlag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error {
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- newVal := &Int64Slice{}
- for _, s := range strings.Split(envVal, ",") {
- s = strings.TrimSpace(s)
- if err := newVal.Set(s); err != nil {
- return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err)
- }
- }
- if f.Value == nil {
- f.Value = newVal
- } else {
- *f.Value = *newVal
- }
- }
-
- eachName(f.Name, func(name string) {
- if f.Value == nil {
- f.Value = &Int64Slice{}
- }
- set.Var(f.Value, name, f.Usage)
- })
- return nil
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f BoolFlag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f BoolFlag) ApplyWithError(set *flag.FlagSet) error {
- val := false
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- if envVal == "" {
- val = false
- } else {
- envValBool, err := strconv.ParseBool(envVal)
- if err != nil {
- return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err)
- }
- val = envValBool
- }
- }
-
- eachName(f.Name, func(name string) {
- if f.Destination != nil {
- set.BoolVar(f.Destination, name, val, f.Usage)
- return
- }
- set.Bool(name, val, f.Usage)
- })
-
- return nil
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f BoolTFlag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f BoolTFlag) ApplyWithError(set *flag.FlagSet) error {
- val := true
-
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- if envVal == "" {
- val = false
- } else {
- envValBool, err := strconv.ParseBool(envVal)
- if err != nil {
- return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err)
- }
- val = envValBool
- }
- }
-
- eachName(f.Name, func(name string) {
- if f.Destination != nil {
- set.BoolVar(f.Destination, name, val, f.Usage)
- return
- }
- set.Bool(name, val, f.Usage)
- })
-
- return nil
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f StringFlag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f StringFlag) ApplyWithError(set *flag.FlagSet) error {
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- f.Value = envVal
- }
-
- eachName(f.Name, func(name string) {
- if f.Destination != nil {
- set.StringVar(f.Destination, name, f.Value, f.Usage)
- return
- }
- set.String(name, f.Value, f.Usage)
- })
-
- return nil
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f IntFlag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f IntFlag) ApplyWithError(set *flag.FlagSet) error {
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- envValInt, err := strconv.ParseInt(envVal, 0, 64)
- if err != nil {
- return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err)
- }
- f.Value = int(envValInt)
- }
-
- eachName(f.Name, func(name string) {
- if f.Destination != nil {
- set.IntVar(f.Destination, name, f.Value, f.Usage)
- return
- }
- set.Int(name, f.Value, f.Usage)
- })
-
- return nil
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f Int64Flag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f Int64Flag) ApplyWithError(set *flag.FlagSet) error {
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- envValInt, err := strconv.ParseInt(envVal, 0, 64)
- if err != nil {
- return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err)
- }
-
- f.Value = envValInt
- }
-
- eachName(f.Name, func(name string) {
- if f.Destination != nil {
- set.Int64Var(f.Destination, name, f.Value, f.Usage)
- return
- }
- set.Int64(name, f.Value, f.Usage)
- })
-
- return nil
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f UintFlag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f UintFlag) ApplyWithError(set *flag.FlagSet) error {
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- envValInt, err := strconv.ParseUint(envVal, 0, 64)
- if err != nil {
- return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err)
- }
-
- f.Value = uint(envValInt)
- }
-
- eachName(f.Name, func(name string) {
- if f.Destination != nil {
- set.UintVar(f.Destination, name, f.Value, f.Usage)
- return
- }
- set.Uint(name, f.Value, f.Usage)
- })
-
- return nil
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f Uint64Flag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f Uint64Flag) ApplyWithError(set *flag.FlagSet) error {
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- envValInt, err := strconv.ParseUint(envVal, 0, 64)
- if err != nil {
- return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err)
- }
-
- f.Value = uint64(envValInt)
- }
-
- eachName(f.Name, func(name string) {
- if f.Destination != nil {
- set.Uint64Var(f.Destination, name, f.Value, f.Usage)
- return
- }
- set.Uint64(name, f.Value, f.Usage)
- })
-
- return nil
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f DurationFlag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f DurationFlag) ApplyWithError(set *flag.FlagSet) error {
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- envValDuration, err := time.ParseDuration(envVal)
- if err != nil {
- return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err)
- }
-
- f.Value = envValDuration
- }
-
- eachName(f.Name, func(name string) {
- if f.Destination != nil {
- set.DurationVar(f.Destination, name, f.Value, f.Usage)
- return
- }
- set.Duration(name, f.Value, f.Usage)
- })
-
- return nil
-}
-
-// Apply populates the flag given the flag set and environment
-// Ignores errors
-func (f Float64Flag) Apply(set *flag.FlagSet) {
- f.ApplyWithError(set)
-}
-
-// ApplyWithError populates the flag given the flag set and environment
-func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error {
- if envVal, ok := flagFromFileEnv(f.FilePath, f.EnvVar); ok {
- envValFloat, err := strconv.ParseFloat(envVal, 10)
- if err != nil {
- return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err)
- }
-
- f.Value = float64(envValFloat)
- }
-
- eachName(f.Name, func(name string) {
- if f.Destination != nil {
- set.Float64Var(f.Destination, name, f.Value, f.Usage)
- return
- }
- set.Float64(name, f.Value, f.Usage)
- })
-
- return nil
-}
-
-func visibleFlags(fl []Flag) []Flag {
- visible := []Flag{}
- for _, flag := range fl {
- field := flagValue(flag).FieldByName("Hidden")
- if !field.IsValid() || !field.Bool() {
- visible = append(visible, flag)
- }
- }
- return visible
-}
-
-func prefixFor(name string) (prefix string) {
- if len(name) == 1 {
- prefix = "-"
- } else {
- prefix = "--"
- }
-
- return
-}
-
-// Returns the placeholder, if any, and the unquoted usage string.
-func unquoteUsage(usage string) (string, string) {
- for i := 0; i < len(usage); i++ {
- if usage[i] == '`' {
- for j := i + 1; j < len(usage); j++ {
- if usage[j] == '`' {
- name := usage[i+1 : j]
- usage = usage[:i] + name + usage[j+1:]
- return name, usage
- }
- }
- break
- }
- }
- return "", usage
-}
-
-func prefixedNames(fullName, placeholder string) string {
- var prefixed string
- parts := strings.Split(fullName, ",")
- for i, name := range parts {
- name = strings.Trim(name, " ")
- prefixed += prefixFor(name) + name
- if placeholder != "" {
- prefixed += " " + placeholder
- }
- if i < len(parts)-1 {
- prefixed += ", "
- }
- }
- return prefixed
-}
-
-func withEnvHint(envVar, str string) string {
- envText := ""
- if envVar != "" {
- prefix := "$"
- suffix := ""
- sep := ", $"
- if runtime.GOOS == "windows" {
- prefix = "%"
- suffix = "%"
- sep = "%, %"
- }
- envText = " [" + prefix + strings.Join(strings.Split(envVar, ","), sep) + suffix + "]"
- }
- return str + envText
-}
-
-func withFileHint(filePath, str string) string {
- fileText := ""
- if filePath != "" {
- fileText = fmt.Sprintf(" [%s]", filePath)
- }
- return str + fileText
-}
-
-func flagValue(f Flag) reflect.Value {
- fv := reflect.ValueOf(f)
- for fv.Kind() == reflect.Ptr {
- fv = reflect.Indirect(fv)
- }
- return fv
-}
-
-func stringifyFlag(f Flag) string {
- fv := flagValue(f)
-
- switch f.(type) {
- case IntSliceFlag:
- return FlagFileHinter(
- fv.FieldByName("FilePath").String(),
- FlagEnvHinter(
- fv.FieldByName("EnvVar").String(),
- stringifyIntSliceFlag(f.(IntSliceFlag)),
- ),
- )
- case Int64SliceFlag:
- return FlagFileHinter(
- fv.FieldByName("FilePath").String(),
- FlagEnvHinter(
- fv.FieldByName("EnvVar").String(),
- stringifyInt64SliceFlag(f.(Int64SliceFlag)),
- ),
- )
- case StringSliceFlag:
- return FlagFileHinter(
- fv.FieldByName("FilePath").String(),
- FlagEnvHinter(
- fv.FieldByName("EnvVar").String(),
- stringifyStringSliceFlag(f.(StringSliceFlag)),
- ),
- )
- }
-
- placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
-
- needsPlaceholder := false
- defaultValueString := ""
-
- if val := fv.FieldByName("Value"); val.IsValid() {
- needsPlaceholder = true
- defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface())
-
- if val.Kind() == reflect.String && val.String() != "" {
- defaultValueString = fmt.Sprintf(" (default: %q)", val.String())
- }
- }
-
- if defaultValueString == " (default: )" {
- defaultValueString = ""
- }
-
- if needsPlaceholder && placeholder == "" {
- placeholder = defaultPlaceholder
- }
-
- usageWithDefault := strings.TrimSpace(usage + defaultValueString)
-
- return FlagFileHinter(
- fv.FieldByName("FilePath").String(),
- FlagEnvHinter(
- fv.FieldByName("EnvVar").String(),
- FlagNamePrefixer(fv.FieldByName("Name").String(), placeholder)+"\t"+usageWithDefault,
- ),
- )
-}
-
-func stringifyIntSliceFlag(f IntSliceFlag) string {
- defaultVals := []string{}
- if f.Value != nil && len(f.Value.Value()) > 0 {
- for _, i := range f.Value.Value() {
- defaultVals = append(defaultVals, strconv.Itoa(i))
- }
- }
-
- return stringifySliceFlag(f.Usage, f.Name, defaultVals)
-}
-
-func stringifyInt64SliceFlag(f Int64SliceFlag) string {
- defaultVals := []string{}
- if f.Value != nil && len(f.Value.Value()) > 0 {
- for _, i := range f.Value.Value() {
- defaultVals = append(defaultVals, strconv.FormatInt(i, 10))
- }
- }
-
- return stringifySliceFlag(f.Usage, f.Name, defaultVals)
-}
-
-func stringifyStringSliceFlag(f StringSliceFlag) string {
- defaultVals := []string{}
- if f.Value != nil && len(f.Value.Value()) > 0 {
- for _, s := range f.Value.Value() {
- if len(s) > 0 {
- defaultVals = append(defaultVals, strconv.Quote(s))
- }
- }
- }
-
- return stringifySliceFlag(f.Usage, f.Name, defaultVals)
-}
-
-func stringifySliceFlag(usage, name string, defaultVals []string) string {
- placeholder, usage := unquoteUsage(usage)
- if placeholder == "" {
- placeholder = defaultPlaceholder
- }
-
- defaultVal := ""
- if len(defaultVals) > 0 {
- defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", "))
- }
-
- usageWithDefault := strings.TrimSpace(usage + defaultVal)
- return FlagNamePrefixer(name, placeholder) + "\t" + usageWithDefault
-}
-
-func flagFromFileEnv(filePath, envName string) (val string, ok bool) {
- for _, envVar := range strings.Split(envName, ",") {
- envVar = strings.TrimSpace(envVar)
- if envVal, ok := syscall.Getenv(envVar); ok {
- return envVal, true
- }
- }
- for _, fileVar := range strings.Split(filePath, ",") {
- if data, err := ioutil.ReadFile(fileVar); err == nil {
- return string(data), true
- }
- }
- return "", false
-}
diff --git a/vendor/github.com/urfave/cli/flag_generated.go b/vendor/github.com/urfave/cli/flag_generated.go
deleted file mode 100644
index 001576c8b..000000000
--- a/vendor/github.com/urfave/cli/flag_generated.go
+++ /dev/null
@@ -1,640 +0,0 @@
-package cli
-
-import (
- "flag"
- "strconv"
- "time"
-)
-
-// WARNING: This file is generated!
-
-// BoolFlag is a flag with type bool
-type BoolFlag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Destination *bool
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f BoolFlag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f BoolFlag) GetName() string {
- return f.Name
-}
-
-// Bool looks up the value of a local BoolFlag, returns
-// false if not found
-func (c *Context) Bool(name string) bool {
- return lookupBool(name, c.flagSet)
-}
-
-// GlobalBool looks up the value of a global BoolFlag, returns
-// false if not found
-func (c *Context) GlobalBool(name string) bool {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupBool(name, fs)
- }
- return false
-}
-
-func lookupBool(name string, set *flag.FlagSet) bool {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := strconv.ParseBool(f.Value.String())
- if err != nil {
- return false
- }
- return parsed
- }
- return false
-}
-
-// BoolTFlag is a flag with type bool that is true by default
-type BoolTFlag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Destination *bool
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f BoolTFlag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f BoolTFlag) GetName() string {
- return f.Name
-}
-
-// BoolT looks up the value of a local BoolTFlag, returns
-// false if not found
-func (c *Context) BoolT(name string) bool {
- return lookupBoolT(name, c.flagSet)
-}
-
-// GlobalBoolT looks up the value of a global BoolTFlag, returns
-// false if not found
-func (c *Context) GlobalBoolT(name string) bool {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupBoolT(name, fs)
- }
- return false
-}
-
-func lookupBoolT(name string, set *flag.FlagSet) bool {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := strconv.ParseBool(f.Value.String())
- if err != nil {
- return false
- }
- return parsed
- }
- return false
-}
-
-// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration)
-type DurationFlag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value time.Duration
- Destination *time.Duration
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f DurationFlag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f DurationFlag) GetName() string {
- return f.Name
-}
-
-// Duration looks up the value of a local DurationFlag, returns
-// 0 if not found
-func (c *Context) Duration(name string) time.Duration {
- return lookupDuration(name, c.flagSet)
-}
-
-// GlobalDuration looks up the value of a global DurationFlag, returns
-// 0 if not found
-func (c *Context) GlobalDuration(name string) time.Duration {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupDuration(name, fs)
- }
- return 0
-}
-
-func lookupDuration(name string, set *flag.FlagSet) time.Duration {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := time.ParseDuration(f.Value.String())
- if err != nil {
- return 0
- }
- return parsed
- }
- return 0
-}
-
-// Float64Flag is a flag with type float64
-type Float64Flag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value float64
- Destination *float64
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f Float64Flag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f Float64Flag) GetName() string {
- return f.Name
-}
-
-// Float64 looks up the value of a local Float64Flag, returns
-// 0 if not found
-func (c *Context) Float64(name string) float64 {
- return lookupFloat64(name, c.flagSet)
-}
-
-// GlobalFloat64 looks up the value of a global Float64Flag, returns
-// 0 if not found
-func (c *Context) GlobalFloat64(name string) float64 {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupFloat64(name, fs)
- }
- return 0
-}
-
-func lookupFloat64(name string, set *flag.FlagSet) float64 {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := strconv.ParseFloat(f.Value.String(), 64)
- if err != nil {
- return 0
- }
- return parsed
- }
- return 0
-}
-
-// GenericFlag is a flag with type Generic
-type GenericFlag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value Generic
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f GenericFlag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f GenericFlag) GetName() string {
- return f.Name
-}
-
-// Generic looks up the value of a local GenericFlag, returns
-// nil if not found
-func (c *Context) Generic(name string) interface{} {
- return lookupGeneric(name, c.flagSet)
-}
-
-// GlobalGeneric looks up the value of a global GenericFlag, returns
-// nil if not found
-func (c *Context) GlobalGeneric(name string) interface{} {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupGeneric(name, fs)
- }
- return nil
-}
-
-func lookupGeneric(name string, set *flag.FlagSet) interface{} {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := f.Value, error(nil)
- if err != nil {
- return nil
- }
- return parsed
- }
- return nil
-}
-
-// Int64Flag is a flag with type int64
-type Int64Flag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value int64
- Destination *int64
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f Int64Flag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f Int64Flag) GetName() string {
- return f.Name
-}
-
-// Int64 looks up the value of a local Int64Flag, returns
-// 0 if not found
-func (c *Context) Int64(name string) int64 {
- return lookupInt64(name, c.flagSet)
-}
-
-// GlobalInt64 looks up the value of a global Int64Flag, returns
-// 0 if not found
-func (c *Context) GlobalInt64(name string) int64 {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupInt64(name, fs)
- }
- return 0
-}
-
-func lookupInt64(name string, set *flag.FlagSet) int64 {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := strconv.ParseInt(f.Value.String(), 0, 64)
- if err != nil {
- return 0
- }
- return parsed
- }
- return 0
-}
-
-// IntFlag is a flag with type int
-type IntFlag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value int
- Destination *int
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f IntFlag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f IntFlag) GetName() string {
- return f.Name
-}
-
-// Int looks up the value of a local IntFlag, returns
-// 0 if not found
-func (c *Context) Int(name string) int {
- return lookupInt(name, c.flagSet)
-}
-
-// GlobalInt looks up the value of a global IntFlag, returns
-// 0 if not found
-func (c *Context) GlobalInt(name string) int {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupInt(name, fs)
- }
- return 0
-}
-
-func lookupInt(name string, set *flag.FlagSet) int {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := strconv.ParseInt(f.Value.String(), 0, 64)
- if err != nil {
- return 0
- }
- return int(parsed)
- }
- return 0
-}
-
-// IntSliceFlag is a flag with type *IntSlice
-type IntSliceFlag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value *IntSlice
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f IntSliceFlag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f IntSliceFlag) GetName() string {
- return f.Name
-}
-
-// IntSlice looks up the value of a local IntSliceFlag, returns
-// nil if not found
-func (c *Context) IntSlice(name string) []int {
- return lookupIntSlice(name, c.flagSet)
-}
-
-// GlobalIntSlice looks up the value of a global IntSliceFlag, returns
-// nil if not found
-func (c *Context) GlobalIntSlice(name string) []int {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupIntSlice(name, fs)
- }
- return nil
-}
-
-func lookupIntSlice(name string, set *flag.FlagSet) []int {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := (f.Value.(*IntSlice)).Value(), error(nil)
- if err != nil {
- return nil
- }
- return parsed
- }
- return nil
-}
-
-// Int64SliceFlag is a flag with type *Int64Slice
-type Int64SliceFlag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value *Int64Slice
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f Int64SliceFlag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f Int64SliceFlag) GetName() string {
- return f.Name
-}
-
-// Int64Slice looks up the value of a local Int64SliceFlag, returns
-// nil if not found
-func (c *Context) Int64Slice(name string) []int64 {
- return lookupInt64Slice(name, c.flagSet)
-}
-
-// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns
-// nil if not found
-func (c *Context) GlobalInt64Slice(name string) []int64 {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupInt64Slice(name, fs)
- }
- return nil
-}
-
-func lookupInt64Slice(name string, set *flag.FlagSet) []int64 {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil)
- if err != nil {
- return nil
- }
- return parsed
- }
- return nil
-}
-
-// StringFlag is a flag with type string
-type StringFlag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value string
- Destination *string
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f StringFlag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f StringFlag) GetName() string {
- return f.Name
-}
-
-// String looks up the value of a local StringFlag, returns
-// "" if not found
-func (c *Context) String(name string) string {
- return lookupString(name, c.flagSet)
-}
-
-// GlobalString looks up the value of a global StringFlag, returns
-// "" if not found
-func (c *Context) GlobalString(name string) string {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupString(name, fs)
- }
- return ""
-}
-
-func lookupString(name string, set *flag.FlagSet) string {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := f.Value.String(), error(nil)
- if err != nil {
- return ""
- }
- return parsed
- }
- return ""
-}
-
-// StringSliceFlag is a flag with type *StringSlice
-type StringSliceFlag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value *StringSlice
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f StringSliceFlag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f StringSliceFlag) GetName() string {
- return f.Name
-}
-
-// StringSlice looks up the value of a local StringSliceFlag, returns
-// nil if not found
-func (c *Context) StringSlice(name string) []string {
- return lookupStringSlice(name, c.flagSet)
-}
-
-// GlobalStringSlice looks up the value of a global StringSliceFlag, returns
-// nil if not found
-func (c *Context) GlobalStringSlice(name string) []string {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupStringSlice(name, fs)
- }
- return nil
-}
-
-func lookupStringSlice(name string, set *flag.FlagSet) []string {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := (f.Value.(*StringSlice)).Value(), error(nil)
- if err != nil {
- return nil
- }
- return parsed
- }
- return nil
-}
-
-// Uint64Flag is a flag with type uint64
-type Uint64Flag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value uint64
- Destination *uint64
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f Uint64Flag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f Uint64Flag) GetName() string {
- return f.Name
-}
-
-// Uint64 looks up the value of a local Uint64Flag, returns
-// 0 if not found
-func (c *Context) Uint64(name string) uint64 {
- return lookupUint64(name, c.flagSet)
-}
-
-// GlobalUint64 looks up the value of a global Uint64Flag, returns
-// 0 if not found
-func (c *Context) GlobalUint64(name string) uint64 {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupUint64(name, fs)
- }
- return 0
-}
-
-func lookupUint64(name string, set *flag.FlagSet) uint64 {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := strconv.ParseUint(f.Value.String(), 0, 64)
- if err != nil {
- return 0
- }
- return parsed
- }
- return 0
-}
-
-// UintFlag is a flag with type uint
-type UintFlag struct {
- Name string
- Usage string
- EnvVar string
- FilePath string
- Hidden bool
- Value uint
- Destination *uint
-}
-
-// String returns a readable representation of this value
-// (for usage defaults)
-func (f UintFlag) String() string {
- return FlagStringer(f)
-}
-
-// GetName returns the name of the flag
-func (f UintFlag) GetName() string {
- return f.Name
-}
-
-// Uint looks up the value of a local UintFlag, returns
-// 0 if not found
-func (c *Context) Uint(name string) uint {
- return lookupUint(name, c.flagSet)
-}
-
-// GlobalUint looks up the value of a global UintFlag, returns
-// 0 if not found
-func (c *Context) GlobalUint(name string) uint {
- if fs := lookupGlobalFlagSet(name, c); fs != nil {
- return lookupUint(name, fs)
- }
- return 0
-}
-
-func lookupUint(name string, set *flag.FlagSet) uint {
- f := set.Lookup(name)
- if f != nil {
- parsed, err := strconv.ParseUint(f.Value.String(), 0, 64)
- if err != nil {
- return 0
- }
- return uint(parsed)
- }
- return 0
-}
diff --git a/vendor/github.com/urfave/cli/funcs.go b/vendor/github.com/urfave/cli/funcs.go
deleted file mode 100644
index 0036b1130..000000000
--- a/vendor/github.com/urfave/cli/funcs.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package cli
-
-// BashCompleteFunc is an action to execute when the bash-completion flag is set
-type BashCompleteFunc func(*Context)
-
-// BeforeFunc is an action to execute before any subcommands are run, but after
-// the context is ready if a non-nil error is returned, no subcommands are run
-type BeforeFunc func(*Context) error
-
-// AfterFunc is an action to execute after any subcommands are run, but after the
-// subcommand has finished it is run even if Action() panics
-type AfterFunc func(*Context) error
-
-// ActionFunc is the action to execute when no subcommands are specified
-type ActionFunc func(*Context) error
-
-// CommandNotFoundFunc is executed if the proper command cannot be found
-type CommandNotFoundFunc func(*Context, string)
-
-// OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying
-// customized usage error messages. This function is able to replace the
-// original error messages. If this function is not set, the "Incorrect usage"
-// is displayed and the execution is interrupted.
-type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error
-
-// ExitErrHandlerFunc is executed if provided in order to handle ExitError values
-// returned by Actions and Before/After functions.
-type ExitErrHandlerFunc func(context *Context, err error)
-
-// FlagStringFunc is used by the help generation to display a flag, which is
-// expected to be a single line.
-type FlagStringFunc func(Flag) string
-
-// FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix
-// text for a flag's full name.
-type FlagNamePrefixFunc func(fullName, placeholder string) string
-
-// FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help
-// with the environment variable details.
-type FlagEnvHintFunc func(envVar, str string) string
-
-// FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help
-// with the file path details.
-type FlagFileHintFunc func(filePath, str string) string
diff --git a/vendor/github.com/urfave/cli/help.go b/vendor/github.com/urfave/cli/help.go
deleted file mode 100644
index 65874fa2f..000000000
--- a/vendor/github.com/urfave/cli/help.go
+++ /dev/null
@@ -1,345 +0,0 @@
-package cli
-
-import (
- "fmt"
- "io"
- "os"
- "strings"
- "text/tabwriter"
- "text/template"
-)
-
-// AppHelpTemplate is the text template for the Default help topic.
-// cli.go uses text/template to render templates. You can
-// render custom help text by setting this variable.
-var AppHelpTemplate = `NAME:
- {{.Name}}{{if .Usage}} - {{.Usage}}{{end}}
-
-USAGE:
- {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
-
-VERSION:
- {{.Version}}{{end}}{{end}}{{if .Description}}
-
-DESCRIPTION:
- {{.Description}}{{end}}{{if len .Authors}}
-
-AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
- {{range $index, $author := .Authors}}{{if $index}}
- {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
-
-COMMANDS:{{range .VisibleCategories}}{{if .Name}}
-
- {{.Name}}:{{end}}{{range .VisibleCommands}}
- {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
-
-GLOBAL OPTIONS:
- {{range $index, $option := .VisibleFlags}}{{if $index}}
- {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}}
-
-COPYRIGHT:
- {{.Copyright}}{{end}}
-`
-
-// CommandHelpTemplate is the text template for the command help topic.
-// cli.go uses text/template to render templates. You can
-// render custom help text by setting this variable.
-var CommandHelpTemplate = `NAME:
- {{.HelpName}} - {{.Usage}}
-
-USAGE:
- {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}}
-
-CATEGORY:
- {{.Category}}{{end}}{{if .Description}}
-
-DESCRIPTION:
- {{.Description}}{{end}}{{if .VisibleFlags}}
-
-OPTIONS:
- {{range .VisibleFlags}}{{.}}
- {{end}}{{end}}
-`
-
-// SubcommandHelpTemplate is the text template for the subcommand help topic.
-// cli.go uses text/template to render templates. You can
-// render custom help text by setting this variable.
-var SubcommandHelpTemplate = `NAME:
- {{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}}
-
-USAGE:
- {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
-
-COMMANDS:{{range .VisibleCategories}}{{if .Name}}
- {{.Name}}:{{end}}{{range .VisibleCommands}}
- {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}
-{{end}}{{if .VisibleFlags}}
-OPTIONS:
- {{range .VisibleFlags}}{{.}}
- {{end}}{{end}}
-`
-
-var helpCommand = Command{
- Name: "help",
- Aliases: []string{"h"},
- Usage: "Shows a list of commands or help for one command",
- ArgsUsage: "[command]",
- Action: func(c *Context) error {
- args := c.Args()
- if args.Present() {
- return ShowCommandHelp(c, args.First())
- }
-
- ShowAppHelp(c)
- return nil
- },
-}
-
-var helpSubcommand = Command{
- Name: "help",
- Aliases: []string{"h"},
- Usage: "Shows a list of commands or help for one command",
- ArgsUsage: "[command]",
- Action: func(c *Context) error {
- args := c.Args()
- if args.Present() {
- return ShowCommandHelp(c, args.First())
- }
-
- return ShowSubcommandHelp(c)
- },
-}
-
-// Prints help for the App or Command
-type helpPrinter func(w io.Writer, templ string, data interface{})
-
-// Prints help for the App or Command with custom template function.
-type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{})
-
-// HelpPrinter is a function that writes the help output. If not set a default
-// is used. The function signature is:
-// func(w io.Writer, templ string, data interface{})
-var HelpPrinter helpPrinter = printHelp
-
-// HelpPrinterCustom is same as HelpPrinter but
-// takes a custom function for template function map.
-var HelpPrinterCustom helpPrinterCustom = printHelpCustom
-
-// VersionPrinter prints the version for the App
-var VersionPrinter = printVersion
-
-// ShowAppHelpAndExit - Prints the list of subcommands for the app and exits with exit code.
-func ShowAppHelpAndExit(c *Context, exitCode int) {
- ShowAppHelp(c)
- os.Exit(exitCode)
-}
-
-// ShowAppHelp is an action that displays the help.
-func ShowAppHelp(c *Context) (err error) {
- if c.App.CustomAppHelpTemplate == "" {
- HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
- return
- }
- customAppData := func() map[string]interface{} {
- if c.App.ExtraInfo == nil {
- return nil
- }
- return map[string]interface{}{
- "ExtraInfo": c.App.ExtraInfo,
- }
- }
- HelpPrinterCustom(c.App.Writer, c.App.CustomAppHelpTemplate, c.App, customAppData())
- return nil
-}
-
-// DefaultAppComplete prints the list of subcommands as the default app completion method
-func DefaultAppComplete(c *Context) {
- for _, command := range c.App.Commands {
- if command.Hidden {
- continue
- }
- if os.Getenv("_CLI_ZSH_AUTOCOMPLETE_HACK") == "1" {
- for _, name := range command.Names() {
- fmt.Fprintf(c.App.Writer, "%s:%s\n", name, command.Usage)
- }
- } else {
- for _, name := range command.Names() {
- fmt.Fprintf(c.App.Writer, "%s\n", name)
- }
- }
- }
-}
-
-// ShowCommandHelpAndExit - exits with code after showing help
-func ShowCommandHelpAndExit(c *Context, command string, code int) {
- ShowCommandHelp(c, command)
- os.Exit(code)
-}
-
-// ShowCommandHelp prints help for the given command
-func ShowCommandHelp(ctx *Context, command string) error {
- // show the subcommand help for a command with subcommands
- if command == "" {
- HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
- return nil
- }
-
- for _, c := range ctx.App.Commands {
- if c.HasName(command) {
- if c.CustomHelpTemplate != "" {
- HelpPrinterCustom(ctx.App.Writer, c.CustomHelpTemplate, c, nil)
- } else {
- HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
- }
- return nil
- }
- }
-
- if ctx.App.CommandNotFound == nil {
- return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3)
- }
-
- ctx.App.CommandNotFound(ctx, command)
- return nil
-}
-
-// ShowSubcommandHelp prints help for the given subcommand
-func ShowSubcommandHelp(c *Context) error {
- return ShowCommandHelp(c, c.Command.Name)
-}
-
-// ShowVersion prints the version number of the App
-func ShowVersion(c *Context) {
- VersionPrinter(c)
-}
-
-func printVersion(c *Context) {
- fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
-}
-
-// ShowCompletions prints the lists of commands within a given context
-func ShowCompletions(c *Context) {
- a := c.App
- if a != nil && a.BashComplete != nil {
- a.BashComplete(c)
- }
-}
-
-// ShowCommandCompletions prints the custom completions for a given command
-func ShowCommandCompletions(ctx *Context, command string) {
- c := ctx.App.Command(command)
- if c != nil && c.BashComplete != nil {
- c.BashComplete(ctx)
- }
-}
-
-func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) {
- funcMap := template.FuncMap{
- "join": strings.Join,
- }
- if customFunc != nil {
- for key, value := range customFunc {
- funcMap[key] = value
- }
- }
-
- w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0)
- t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
- err := t.Execute(w, data)
- if err != nil {
- // If the writer is closed, t.Execute will fail, and there's nothing
- // we can do to recover.
- if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" {
- fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err)
- }
- return
- }
- w.Flush()
-}
-
-func printHelp(out io.Writer, templ string, data interface{}) {
- printHelpCustom(out, templ, data, nil)
-}
-
-func checkVersion(c *Context) bool {
- found := false
- if VersionFlag.GetName() != "" {
- eachName(VersionFlag.GetName(), func(name string) {
- if c.GlobalBool(name) || c.Bool(name) {
- found = true
- }
- })
- }
- return found
-}
-
-func checkHelp(c *Context) bool {
- found := false
- if HelpFlag.GetName() != "" {
- eachName(HelpFlag.GetName(), func(name string) {
- if c.GlobalBool(name) || c.Bool(name) {
- found = true
- }
- })
- }
- return found
-}
-
-func checkCommandHelp(c *Context, name string) bool {
- if c.Bool("h") || c.Bool("help") {
- ShowCommandHelp(c, name)
- return true
- }
-
- return false
-}
-
-func checkSubcommandHelp(c *Context) bool {
- if c.Bool("h") || c.Bool("help") {
- ShowSubcommandHelp(c)
- return true
- }
-
- return false
-}
-
-func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) {
- if !a.EnableBashCompletion {
- return false, arguments
- }
-
- pos := len(arguments) - 1
- lastArg := arguments[pos]
-
- if lastArg != "--"+BashCompletionFlag.GetName() {
- return false, arguments
- }
-
- return true, arguments[:pos]
-}
-
-func checkCompletions(c *Context) bool {
- if !c.shellComplete {
- return false
- }
-
- if args := c.Args(); args.Present() {
- name := args.First()
- if cmd := c.App.Command(name); cmd != nil {
- // let the command handle the completion
- return false
- }
- }
-
- ShowCompletions(c)
- return true
-}
-
-func checkCommandCompletions(c *Context, name string) bool {
- if !c.shellComplete {
- return false
- }
-
- ShowCommandCompletions(c, name)
- return true
-}
diff --git a/vendor/github.com/urfave/cli/sort.go b/vendor/github.com/urfave/cli/sort.go
deleted file mode 100644
index 23d1c2f77..000000000
--- a/vendor/github.com/urfave/cli/sort.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package cli
-
-import "unicode"
-
-// lexicographicLess compares strings alphabetically considering case.
-func lexicographicLess(i, j string) bool {
- iRunes := []rune(i)
- jRunes := []rune(j)
-
- lenShared := len(iRunes)
- if lenShared > len(jRunes) {
- lenShared = len(jRunes)
- }
-
- for index := 0; index < lenShared; index++ {
- ir := iRunes[index]
- jr := jRunes[index]
-
- if lir, ljr := unicode.ToLower(ir), unicode.ToLower(jr); lir != ljr {
- return lir < ljr
- }
-
- if ir != jr {
- return ir < jr
- }
- }
-
- return i < j
-}