Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
inclavare-containers
提交
15f17876
I
inclavare-containers
项目概览
openanolis
/
inclavare-containers
通知
4
Star
7
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
5
列表
看板
标记
里程碑
合并请求
0
分析
仓库
DevOps
项目成员
Pages
I
inclavare-containers
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
5
Issue
5
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
15f17876
编写于
6月 10, 2020
作者:
S
stormgbs
提交者:
GitHub
6月 10, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #23 from jiazhiguang/master
execute sgx_sign in the occlum container
上级
ea9daf44
33a410ee
变更
36
显示空白变更内容
内联
并排
Showing
36 changed file
with
6407 addition
and
192 deletion
+6407
-192
shim/README.md
shim/README.md
+1
-1
shim/go.sum
shim/go.sum
+1
-0
shim/runtime/carrier/constants/constants.go
shim/runtime/carrier/constants/constants.go
+166
-41
shim/runtime/carrier/occlum/occlum.go
shim/runtime/carrier/occlum/occlum.go
+201
-126
shim/runtime/utils/utils.go
shim/runtime/utils/utils.go
+58
-0
shim/runtime/v2/rune/v2/rune.go
shim/runtime/v2/rune/v2/rune.go
+7
-10
shim/runtime/v2/rune/v2/service.go
shim/runtime/v2/rune/v2/service.go
+0
-14
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/client.go
...thub.com/containerd/containerd/cmd/ctr/commands/client.go
+58
-0
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/commands.go
...ub.com/containerd/containerd/cmd/ctr/commands/commands.go
+197
-0
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/commands_unix.go
...m/containerd/containerd/cmd/ctr/commands/commands_unix.go
+33
-0
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/commands_windows.go
...ontainerd/containerd/cmd/ctr/commands/commands_windows.go
+30
-0
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/resolver.go
...ub.com/containerd/containerd/cmd/ctr/commands/resolver.go
+110
-0
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/signals.go
...hub.com/containerd/containerd/cmd/ctr/commands/signals.go
+52
-0
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/utils.go
...ithub.com/containerd/containerd/cmd/ctr/commands/utils.go
+27
-0
shim/vendor/github.com/containerd/go-runc/monitor.go
shim/vendor/github.com/containerd/go-runc/monitor.go
+3
-0
shim/vendor/github.com/urfave/cli/.flake8
shim/vendor/github.com/urfave/cli/.flake8
+2
-0
shim/vendor/github.com/urfave/cli/.gitignore
shim/vendor/github.com/urfave/cli/.gitignore
+2
-0
shim/vendor/github.com/urfave/cli/.travis.yml
shim/vendor/github.com/urfave/cli/.travis.yml
+27
-0
shim/vendor/github.com/urfave/cli/CHANGELOG.md
shim/vendor/github.com/urfave/cli/CHANGELOG.md
+435
-0
shim/vendor/github.com/urfave/cli/LICENSE
shim/vendor/github.com/urfave/cli/LICENSE
+21
-0
shim/vendor/github.com/urfave/cli/README.md
shim/vendor/github.com/urfave/cli/README.md
+1391
-0
shim/vendor/github.com/urfave/cli/app.go
shim/vendor/github.com/urfave/cli/app.go
+509
-0
shim/vendor/github.com/urfave/cli/appveyor.yml
shim/vendor/github.com/urfave/cli/appveyor.yml
+26
-0
shim/vendor/github.com/urfave/cli/category.go
shim/vendor/github.com/urfave/cli/category.go
+44
-0
shim/vendor/github.com/urfave/cli/cli.go
shim/vendor/github.com/urfave/cli/cli.go
+22
-0
shim/vendor/github.com/urfave/cli/command.go
shim/vendor/github.com/urfave/cli/command.go
+304
-0
shim/vendor/github.com/urfave/cli/context.go
shim/vendor/github.com/urfave/cli/context.go
+278
-0
shim/vendor/github.com/urfave/cli/errors.go
shim/vendor/github.com/urfave/cli/errors.go
+115
-0
shim/vendor/github.com/urfave/cli/flag-types.json
shim/vendor/github.com/urfave/cli/flag-types.json
+93
-0
shim/vendor/github.com/urfave/cli/flag.go
shim/vendor/github.com/urfave/cli/flag.go
+807
-0
shim/vendor/github.com/urfave/cli/flag_generated.go
shim/vendor/github.com/urfave/cli/flag_generated.go
+627
-0
shim/vendor/github.com/urfave/cli/funcs.go
shim/vendor/github.com/urfave/cli/funcs.go
+41
-0
shim/vendor/github.com/urfave/cli/generate-flag-types
shim/vendor/github.com/urfave/cli/generate-flag-types
+255
-0
shim/vendor/github.com/urfave/cli/help.go
shim/vendor/github.com/urfave/cli/help.go
+339
-0
shim/vendor/github.com/urfave/cli/runtests
shim/vendor/github.com/urfave/cli/runtests
+122
-0
shim/vendor/modules.txt
shim/vendor/modules.txt
+3
-0
未找到文件。
shim/README.md
浏览文件 @
15f17876
...
...
@@ -16,7 +16,7 @@ Carrier is a abstract framework to build an enclave for the specified enclave ru
## Build requirements
Go 1.1
4
.x or above.
Go 1.1
3
.x or above.
## How to build and install
...
...
shim/go.sum
浏览文件 @
15f17876
...
...
@@ -238,6 +238,7 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5 h1:MCfT24H3f//U5+UCrZp1/riVO3B50BovxtDiNn0XKkk=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
...
...
shim/runtime/carrier/constants/constants.go
浏览文件 @
15f17876
...
...
@@ -89,45 +89,170 @@ function start() {
start $@`
//FIXME
BuildOcclumEnclaveScript
=
`#!/bin/bash
set -xe
data_dir=/data
rootfs=/rootfs
work_dir=%s
entry_point=%s
occlum_config_path=${rootfs}/%s
occlum_workspace=${data_dir}/../occlum_workspace
CarrierScript
=
`#!/bin/bash
set -xe
base_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
occlum_workspace=/occlum_workspace
temp=$(getopt -a -o a:r:w:p:c:e:u:m:s:k:n: -l action:,rootfs:,work_dir:,entry_point:,occlum_config_path:,enclave_config_path:,\
unsigned_encalve_path:,unsigned_material_path:,signed_enclave_path:,public_key_path:,signature_path: -- "$@")
eval set -- "$temp"
while true
do
case "$1" in
-a|--action)
action=$2; shift;;
-r|--rootfs)
rootfs=$2; shift;;
-w|--work_dir)
work_dir=$2; shift;;
-p|--entry_point)
entry_point=$2; shift;;
-c|--occlum_config_path)
occlum_config_path=$2; shift;;
-e|--enclave_config_path)
enclave_config_path=$2; shift;;
-u|--unsigned_encalve_path)
unsigned_encalve_path=$2; shift;;
-m|--unsigned_material_path)
unsigned_material_path=$2; shift;;
-s|--signed_enclave_path)
signed_enclave_path=$2; shift;;
-k|--public_key_path)
public_key_path=$2; shift;;
-n|--signature_path)
signature_path=$2; shift;;
--)
shift
break
;;
*)
echo "Unknown argument: $1"; shift;;
esac
shift
done
function copyOcclumLiberaries() {
pushd ${rootfs}/${work_dir}
local lib_dir=${rootfs}/lib
/bin/cp -f /usr/lib/x86_64-linux-gnu/libprotobuf.so ${lib_dir}
/bin/cp -f /lib/x86_64-linux-gnu/libseccomp.so.2 ${lib_dir}
/bin/cp -f /usr/lib/libsgx_u*.so* ${lib_dir}
/bin/cp -f /usr/lib/libsgx_enclave_common.so.1 ${lib_dir}
/bin/cp -f /usr/lib/libsgx_launch.so.1 ${lib_dir}
ln -sfn .occlum/build/lib/libocclum-pal.so liberpal-occlum.so
# ==== fixme: the file /sbin/ldconfig maybe not exist in customer's image
chroot ${rootfs} /sbin/ldconfig
popd
}
function buildUnsignedEnclave(){
if [[ "${entry_point}" == "" || "${rootfs}" == "" || "${work_dir}" == "" ]]; then
echo "BuildUnsignedEnclave:: the argumentes should not be empty: entry_point, rootfs, work_dir"
exit 1
fi
rm -fr ${occlum_workspace}
mkdir -p ${occlum_workspace}
pushd ${occlum_workspace}
# occlum init
occlum init
# replace Occlum.json with user-supplied Occlum.json
if [[ "${occlum_config_path}" != "" && -f ${occlum_config_path} ]];then
/bin/cp -f ${occlum_config_path} Occlum.json
fi
# set occlum entrypoint
sed -i "s#/bin#${entry_point}#g" Occlum.json
/bin/bash ${data_dir}/replace_occlum_image.sh ${rootfs} image
# build occlum image
/bin/bash ${base_dir}/replace_occlum_image.sh ${rootfs} image
# occlum build
occlum build
rm -f ${rootfs}/${work_dir}/.occlum/build/lib/libocclum-libos.signed.so
mkdir -p ${rootfs}/${work_dir} || true
/bin/cp -fr .occlum ${rootfs}/${work_dir}
/bin/cp -f Enclave.xml ${rootfs}/${work_dir}
# ===fixme debug====
/bin/cp -fr image ${rootfs}/${work_dir}
/bin/cp -f Occlum.json ${rootfs}/${work_dir}
# ==================
/bin/cp -f Enclave.xml ${data_dir}
# copy occlum liberaries to rootfs
copyOcclumLiberaries
popd
pushd ${rootfs}/${work_dir}
# ==== copy sgxsdk libs =======
lib_dir=${rootfs}/lib
/bin/cp -f /usr/lib/x86_64-linux-gnu/libprotobuf.so ${lib_dir}
/bin/cp -f /lib/x86_64-linux-gnu/libseccomp.so.2 ${lib_dir}
/bin/cp -f /usr/lib/libsgx_u*.so* ${lib_dir}
/bin/cp -f /usr/lib/libsgx_enclave_common.so.1 ${lib_dir}
/bin/cp -f /usr/lib/libsgx_launch.so.1 ${lib_dir}
# ==================
ln -sfn .occlum/build/lib/libocclum-pal.so liberpal-occlum.so
chroot ${rootfs} /sbin/ldconfig
popd
`
}
function generateSigningMaterial() {
if [[ "${enclave_config_path}" == "" || "${unsigned_encalve_path}" == "" || "${unsigned_material_path}" == "" ]]; then
echo "GenerateSigningMaterial:: the argumentes should not be empty: enclave_config_path, unsigned_encalve_path, unsigned_material_path"
exit 1
fi
/opt/intel/sgxsdk/bin/x64/sgx_sign gendata -enclave ${unsigned_encalve_path} -config ${enclave_config_path} -out ${unsigned_material_path}
}
function cascadeEnclaveSignature() {
if [[ "${enclave_config_path}" == "" || "${unsigned_encalve_path}" == "" || "${unsigned_material_path}" == "" \
|| "${signed_enclave_path}" == "" || "${public_key_path}" == "" || "${signature_path}" == "" ]]; then
echo "CascadeEnclaveSignature:: the argumentes should not be empty: enclave_config_path, unsigned_encalve_path, unsigned_material_path, signed_enclave_path, public_key_path, signature_path"
exit 1
fi
/opt/intel/sgxsdk/bin/x64/sgx_sign catsig -enclave ${unsigned_encalve_path} -config ${enclave_config_path} -out ${signed_enclave_path} -key ${public_key_path} \
-sig ${signature_path} -unsigned ${unsigned_material_path}
}
function mockSignature() {
if [[ "${public_key_path}" == "" || "${signature_path}" == "" || "${unsigned_material_path}" == "" ]]; then
echo "MockSignature:: the argumentes should not be empty: public_key_path, signature_path, unsigned_material_path"
exit 1
fi
dir=$(mktemp -d)
openssl genrsa -out ${dir}/privatekey.pem -3 3072
openssl rsa -in ${dir}/privatekey.pem -pubout -out ${public_key_path}
openssl dgst -sha256 -out ${signature_path} -sign ${dir}/privatekey.pem -keyform PEM ${unsigned_material_path}
rm -fr ${dir}
}
function doAction(){
if [ "${action}" == "" ]; then
echo "the argument should not be empty: action"
exit 1
fi
case ${action} in
buildUnsignedEnclave)
buildUnsignedEnclave
;;
generateSigningMaterial)
generateSigningMaterial
;;
cascadeEnclaveSignature)
cascadeEnclaveSignature
;;
mockSignature)
mockSignature
;;
*)
echo "unknown action: ${action}"
exit 1
;;
esac
}
doAction`
StartScript
=
`#!/bin/bash
function handle_TERM() {
echo "recevied signal SIGTERM, exit now"
exit 0
}
function handle_INT() {
echo "recevied signal SIGINT, exit now"
exit 0
}
trap 'handle_INT' SIGINT
trap 'handle_TERM' SIGTERM
while true
do
sleep 1
done`
)
shim/runtime/carrier/occlum/occlum.go
浏览文件 @
15f17876
...
...
@@ -2,51 +2,56 @@ package occlum
import
(
"context"
"encoding/hex"
"fmt"
"io/ioutil"
"math/rand"
"os"
"os/exec"
"path/filepath"
"strconv"
"syscall"
"time"
"github.com/BurntSushi/toml"
shim_config
"github.com/alibaba/inclavare-containers/shim/config"
"github.com/alibaba/inclavare-containers/shim/runtime/carrier"
carr_const
"github.com/alibaba/inclavare-containers/shim/runtime/carrier/constants"
"github.com/alibaba/inclavare-containers/shim/runtime/config"
"github.com/alibaba/inclavare-containers/shim/runtime/utils"
"github.com/alibaba/inclavare-containers/shim/runtime/v2/rune/constants"
"github.com/containerd/containerd"
"github.com/containerd/containerd/cio"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/oci"
"github.com/containerd/containerd/runtime/v2/task"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"github.com/BurntSushi/toml"
"github.com/alibaba/inclavare-containers/shim/runtime/config"
shim_config
"github.com/alibaba/inclavare-containers/shim/config"
"github.com/alibaba/inclavare-containers/shim/runtime/carrier"
"github.com/alibaba/inclavare-containers/shim/runtime/v2/rune/constants"
carr_const
"github.com/alibaba/inclavare-containers/shim/runtime/carrier/constants"
)
const
(
defaultNamespace
=
"default"
//occlumEnclaveBuilderImage = "docker.io/occlum/occlum:0.12.0-ubuntu18.04"
buildOcclumEnclaveFileName
=
"build_occulum_enclave.sh"
defaultNamespace
=
"k8s.io"
replaceOcclumImageScript
=
"replace_occlum_image.sh"
//containerdAddress = "/run/containerd/containerd.sock"
carrierScriptFileName
=
"carrier.sh"
startScriptFileName
=
"start.sh"
rootfsDirName
=
"rootfs"
encalveDataDir
=
"data"
//sgxToolSign = "/opt/intel/sgxsdk/bin/x64/sgx_sign"
enclaveDataDir
=
"data"
)
var
_
carrier
.
Carrier
=
&
occlum
{}
type
occlumBuildTask
struct
{
client
*
containerd
.
Client
container
*
containerd
.
Container
task
*
containerd
.
Task
}
type
occlum
struct
{
context
context
.
Context
bundle
string
workDirectory
string
entryPoints
[]
string
configPath
string
task
*
occlumBuildTask
spec
*
specs
.
Spec
shimConfig
*
shim_config
.
Config
}
...
...
@@ -64,6 +69,7 @@ func NewOcclumCarrier(ctx context.Context, bundle string) (carrier.Carrier, erro
context
:
ctx
,
bundle
:
bundle
,
shimConfig
:
&
cfg
,
task
:
&
occlumBuildTask
{},
},
nil
}
...
...
@@ -82,59 +88,55 @@ func (c *occlum) BuildUnsignedEnclave(req *task.CreateTaskRequest, args *carrier
}
namespace
,
ok
:=
namespaces
.
Namespace
(
c
.
context
)
logrus
.
Debugf
(
"BuildUnsignedEnclave: get namespace %s, containerdAddress: %s"
,
namespace
,
c
.
shimConfig
.
Containerd
.
Socket
)
if
!
ok
{
namespace
=
defaultNamespace
}
// Create a new client connected to the default socket path for containerd.
client
,
err
:=
containerd
.
New
(
c
.
shimConfig
.
Containerd
.
Socket
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"failed to create containerd client. error: %++v"
,
err
)
}
else
{
c
.
task
.
client
=
client
}
defer
client
.
Close
()
logrus
.
Debugf
(
"BuildUnsignedEnclave: get containerd client successfully"
)
// Create a new context with "k8s.io" namespace
ctx
,
cancle
:=
context
.
WithTimeout
(
context
.
Background
(),
time
.
Minute
*
10
)
defer
cancle
()
ctx
=
namespaces
.
WithNamespace
(
c
.
context
,
namespace
)
if
err
=
createNamespaceIfNotExist
(
client
,
namespace
);
err
!=
nil
{
logrus
.
Errorf
(
"BuildUnsignedEnclave: create namespace %s failed. error: %++v"
,
namespace
,
err
)
return
""
,
err
}
// pull the image t
o be
used to build enclave.
// pull the image t
hat
used to build enclave.
occlumEnclaveBuilderImage
:=
c
.
shimConfig
.
EnclaveRuntime
.
Occlum
.
BuildImage
image
,
err
:=
client
.
Pull
(
c
tx
,
occlumEnclaveBuilderImage
,
containerd
.
WithPullUnpack
)
image
,
err
:=
client
.
Pull
(
c
.
context
,
occlumEnclaveBuilderImage
,
containerd
.
WithPullUnpack
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"failed to pull image %s. error: %++v"
,
occlumEnclaveBuilderImage
,
err
)
}
logrus
.
Debugf
(
"BuildUnsignedEnclave: pull image %s successfully"
,
occlumEnclaveBuilderImage
)
// Generate the containerID.
// Generate the containerId and snapshotId.
// FIXME debug
rand
.
Seed
(
time
.
Now
()
.
UnixNano
())
containerId
:=
fmt
.
Sprintf
(
"occlum-enclave-builder-%s"
,
strconv
.
FormatInt
(
rand
.
Int63
(),
16
))
snapshotId
:=
fmt
.
Sprintf
(
"occlum-enclave-builder-snapshot-%s"
,
strconv
.
FormatInt
(
rand
.
Int63
(),
16
))
logrus
.
Debugf
(
"BuildUnsignedEnclave: containerId: %s, snapshotId: %s"
,
containerId
,
snapshotId
)
if
err
:=
os
.
Mkdir
(
filepath
.
Join
(
req
.
Bundle
,
enc
al
veDataDir
),
0755
);
err
!=
nil
{
if
err
:=
os
.
Mkdir
(
filepath
.
Join
(
req
.
Bundle
,
enc
la
veDataDir
),
0755
);
err
!=
nil
{
return
""
,
err
}
// Create a shell script which is used to build occlum enclave.
buildEnclaveScript
:=
filepath
.
Join
(
req
.
Bundle
,
encalveDataDir
,
buildOcclumEnclaveFileName
)
if
err
:=
ioutil
.
WriteFile
(
buildEnclaveScript
,
[]
byte
(
fmt
.
Sprintf
(
carr_const
.
BuildOcclumEnclaveScript
,
c
.
workDirectory
,
c
.
entryPoints
[
0
],
c
.
configPath
)),
os
.
ModePerm
);
err
!=
nil
{
replaceImagesScript
:=
filepath
.
Join
(
req
.
Bundle
,
enclaveDataDir
,
replaceOcclumImageScript
)
if
err
:=
ioutil
.
WriteFile
(
replaceImagesScript
,
[]
byte
(
carr_const
.
ReplaceOcclumImageScript
),
os
.
ModePerm
);
err
!=
nil
{
return
""
,
err
}
replaceImagesScript
:=
filepath
.
Join
(
req
.
Bundle
,
encalveDataDir
,
replaceOcclumImageScript
)
if
err
:=
ioutil
.
WriteFile
(
replaceImagesScript
,
[]
byte
(
carr_const
.
ReplaceOcclumImageScript
),
os
.
ModePerm
);
err
!=
nil
{
carrierScript
:=
filepath
.
Join
(
req
.
Bundle
,
enclaveDataDir
,
carrierScriptFileName
)
if
err
:=
ioutil
.
WriteFile
(
carrierScript
,
[]
byte
(
carr_const
.
CarrierScript
),
os
.
ModePerm
);
err
!=
nil
{
return
""
,
err
}
startScript
:=
filepath
.
Join
(
req
.
Bundle
,
enclaveDataDir
,
startScriptFileName
)
if
err
:=
ioutil
.
WriteFile
(
startScript
,
[]
byte
(
carr_const
.
StartScript
),
os
.
ModePerm
);
err
!=
nil
{
return
""
,
err
}
...
...
@@ -147,9 +149,9 @@ func (c *occlum) BuildUnsignedEnclave(req *task.CreateTaskRequest, args *carrier
Options
:
[]
string
{
"rbind"
,
"rw"
},
}
dataMount
:=
specs
.
Mount
{
Destination
:
filepath
.
Join
(
"/"
,
enc
al
veDataDir
),
Destination
:
filepath
.
Join
(
"/"
,
enc
la
veDataDir
),
Type
:
"bind"
,
Source
:
filepath
.
Join
(
req
.
Bundle
,
enc
al
veDataDir
),
Source
:
filepath
.
Join
(
req
.
Bundle
,
enc
la
veDataDir
),
Options
:
[]
string
{
"rbind"
,
"rw"
},
}
...
...
@@ -159,14 +161,12 @@ func (c *occlum) BuildUnsignedEnclave(req *task.CreateTaskRequest, args *carrier
mounts
=
append
(
mounts
,
rootfsMount
,
dataMount
)
// create a container
container
,
err
:=
client
.
NewContainer
(
c
tx
,
c
.
context
,
containerId
,
containerd
.
WithImage
(
image
),
containerd
.
WithNewSnapshot
(
snapshotId
,
image
),
containerd
.
WithNewSpec
(
oci
.
WithImageConfig
(
image
),
oci
.
WithProcessArgs
(
"/bin/bash"
,
filepath
.
Join
(
"/"
,
encalveDataDir
,
buildOcclumEnclaveFileName
)),
//FIXME debug
//oci.WithProcessArgs("sleep", "infinity"),
oci
.
WithProcessArgs
(
"/bin/bash"
,
filepath
.
Join
(
"/"
,
enclaveDataDir
,
startScriptFileName
)),
oci
.
WithPrivileged
,
oci
.
WithMounts
(
mounts
),
),
...
...
@@ -174,40 +174,40 @@ func (c *occlum) BuildUnsignedEnclave(req *task.CreateTaskRequest, args *carrier
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"failed to create container by image %s. error: %++v"
,
occlumEnclaveBuilderImage
,
err
)
}
else
{
c
.
task
.
container
=
&
container
}
defer
container
.
Delete
(
ctx
,
containerd
.
WithSnapshotCleanup
)
// Create a task from the container.
t
ask
,
err
:=
container
.
NewTask
(
ctx
,
cio
.
NewCreator
(
cio
.
WithStdio
))
t
,
err
:=
container
.
NewTask
(
c
.
context
,
cio
.
NewCreator
(
cio
.
WithStdio
))
if
err
!=
nil
{
return
""
,
err
}
else
{
c
.
task
.
task
=
&
t
}
defer
task
.
Delete
(
ctx
)
logrus
.
Debugf
(
"BuildUnsignedEnclave: create task successfully"
)
// Wait before calling start
exitStatusC
,
err
:=
task
.
Wait
(
ctx
)
if
err
!=
nil
{
if
err
:=
t
.
Start
(
c
.
context
);
err
!=
nil
{
logrus
.
Errorf
(
"BuildUnsignedEnclave: start task failed. error: %++v"
,
err
)
return
""
,
err
}
// Call start() on the task to execute the building scripts.
if
err
:=
task
.
Start
(
ctx
);
err
!=
nil
{
return
""
,
err
cmd
:=
[]
string
{
"/bin/bash"
,
filepath
.
Join
(
"/"
,
enclaveDataDir
,
carrierScriptFileName
),
"--action"
,
"buildUnsignedEnclave"
,
"--entry_point"
,
c
.
entryPoints
[
0
],
"--work_dir"
,
c
.
workDirectory
,
"--rootfs"
,
filepath
.
Join
(
"/"
,
rootfsDirName
),
}
// Wait for the process to fully exit and print out the exit status
status
:=
<-
exitStatusC
code
,
_
,
err
:=
status
.
Result
()
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"container exited abnormaly with exit code %d. error: %++v"
,
code
,
err
)
}
else
if
code
!=
0
{
return
""
,
fmt
.
Errorf
(
"container exited abnormaly with exit code %d"
,
code
)
if
c
.
configPath
!=
""
{
cmd
=
append
(
cmd
,
"--occlum_config_path"
,
filepath
.
Join
(
"/"
,
rootfsDirName
,
c
.
configPath
))
}
enclavePath
:=
filepath
.
Join
(
req
.
Bundle
,
rootfsDirName
,
c
.
workDirectory
,
".occlum/build/lib/libocclum-libos.so"
)
logrus
.
Debugf
(
"BuildUnsignedEnclave: exit code: %d. enclavePath: %s"
,
code
,
enclavePath
)
logrus
.
Debugf
(
"BuildUnsignedEnclave: command: %v"
,
cmd
)
if
err
:=
c
.
execTask
(
cmd
...
);
err
!=
nil
{
logrus
.
Errorf
(
"BuildUnsignedEnclave: exec failed. error: %++v"
,
err
)
return
""
,
err
}
enclavePath
:=
filepath
.
Join
(
"/"
,
rootfsDirName
,
c
.
workDirectory
,
".occlum/build/lib/libocclum-libos.so"
)
return
enclavePath
,
nil
}
...
...
@@ -215,69 +215,107 @@ func (c *occlum) BuildUnsignedEnclave(req *task.CreateTaskRequest, args *carrier
// GenerateSigningMaterial impl Carrier.
func
(
c
*
occlum
)
GenerateSigningMaterial
(
req
*
task
.
CreateTaskRequest
,
args
*
carrier
.
CommonArgs
)
(
signingMaterial
string
,
err
error
)
{
signingMaterial
=
filepath
.
Join
(
req
.
Bundle
,
encalveDataDir
,
"enclave_sig.dat"
)
args
.
Config
=
filepath
.
Join
(
req
.
Bundle
,
encalveDataDir
,
"Enclave.xml"
)
sgxToolSign
:=
c
.
shimConfig
.
SgxToolSign
logrus
.
Debugf
(
"GenerateSigningMaterial cmmmand: %s gendata -enclave %s -config %s -out %s"
,
sgxToolSign
,
args
.
Enclave
,
args
.
Config
,
signingMaterial
)
gendataArgs
:=
[]
string
{
"gendata"
,
"-enclave"
,
args
.
Enclave
,
"-config"
,
args
.
Config
,
"-out"
,
signingMaterial
,
signingMaterial
=
filepath
.
Join
(
"/"
,
rootfsDirName
,
c
.
workDirectory
,
"enclave_sig.dat"
)
args
.
Config
=
filepath
.
Join
(
"/"
,
rootfsDirName
,
c
.
workDirectory
,
"Enclave.xml"
)
cmd
:=
[]
string
{
"/bin/bash"
,
filepath
.
Join
(
"/"
,
enclaveDataDir
,
carrierScriptFileName
),
"--action"
,
"generateSigningMaterial"
,
"--enclave_config_path"
,
args
.
Config
,
"--unsigned_encalve_path"
,
args
.
Enclave
,
"--unsigned_material_path"
,
signingMaterial
,
}
cmd
:=
exec
.
Command
(
sgxToolSign
,
gendataArgs
...
)
if
result
,
err
:=
cmd
.
Output
();
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"GenerateSigningMaterial: sgx_sign gendata failed. error: %v %s"
,
err
,
string
(
result
))
logrus
.
Debugf
(
"GenerateSigningMaterial: sgx_sign gendata command: %v"
,
cmd
)
if
err
:=
c
.
execTask
(
cmd
...
);
err
!=
nil
{
logrus
.
Errorf
(
"GenerateSigningMaterial: sgx_sign gendata failed. error: %++v"
,
err
)
return
""
,
err
}
logrus
.
Debugf
(
"GenerateSigningMaterial: sgx_sign gendata successfully"
)
return
signingMaterial
,
nil
}
// CascadeEnclaveSignature impl Carrier.
func
(
c
*
occlum
)
CascadeEnclaveSignature
(
req
*
task
.
CreateTaskRequest
,
args
*
carrier
.
CascadeEnclaveSignatureArgs
)
(
signedEnclave
string
,
err
error
)
{
signedEnclave
=
filepath
.
Join
(
req
.
Bundle
,
rootfsDirName
,
c
.
workDirectory
,
".occlum/build/lib/libocclum-libos.signed.so"
)
sgxToolSign
:=
c
.
shimConfig
.
SgxToolSign
logrus
.
Debugf
(
"CascadeEnclaveSignature cmmmand: %s catsig -enclave %s -config %s -out %s -key %s -sig %s -unsigned %s"
,
sgxToolSign
,
args
.
Enclave
,
args
.
Config
,
signedEnclave
,
args
.
Key
,
args
.
Signature
,
args
.
SigningMaterial
)
catsigArgs
:=
[]
string
{
"catsig"
,
"-enclave"
,
args
.
Enclave
,
"-config"
,
args
.
Config
,
"-out"
,
signedEnclave
,
"-key"
,
args
.
Key
,
"-sig"
,
args
.
Signature
,
"-unsigned"
,
args
.
SigningMaterial
,
}
cmd
:=
exec
.
Command
(
sgxToolSign
,
catsigArgs
...
)
if
result
,
err
:=
cmd
.
Output
();
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"CascadeEnclaveSignature: sgx_sign catsig failed. error: %v %s"
,
err
,
string
(
result
))
var
bufferSize
int64
=
1024
*
4
signedEnclave
=
filepath
.
Join
(
"/"
,
rootfsDirName
,
c
.
workDirectory
,
".occlum/build/lib/libocclum-libos.signed.so"
)
publicKey
:=
filepath
.
Join
(
"/"
,
enclaveDataDir
,
"public_key.pem"
)
signature
:=
filepath
.
Join
(
"/"
,
enclaveDataDir
,
"signature.dat"
)
if
err
:=
utils
.
CopyFile
(
args
.
Key
,
filepath
.
Join
(
req
.
Bundle
,
publicKey
),
bufferSize
);
err
!=
nil
{
logrus
.
Errorf
(
"CascadeEnclaveSignature copy file %s to %s failed. err: %++v"
,
args
.
Key
,
publicKey
,
err
)
return
""
,
err
}
if
err
:=
utils
.
CopyFile
(
args
.
Signature
,
filepath
.
Join
(
req
.
Bundle
,
signature
),
bufferSize
);
err
!=
nil
{
logrus
.
Errorf
(
"CascadeEnclaveSignature copy file %s to %s failed. err: %++v"
,
args
.
Signature
,
signature
,
err
)
return
""
,
err
}
cmd
:=
[]
string
{
"/bin/bash"
,
filepath
.
Join
(
"/"
,
enclaveDataDir
,
carrierScriptFileName
),
"--action"
,
"cascadeEnclaveSignature"
,
"--enclave_config_path"
,
args
.
Config
,
"--unsigned_encalve_path"
,
args
.
Enclave
,
"--unsigned_material_path"
,
args
.
SigningMaterial
,
"--signed_enclave_path"
,
signedEnclave
,
"--public_key_path"
,
publicKey
,
"--signature_path"
,
signature
,
}
logrus
.
Debugf
(
"CascadeEnclaveSignature: sgx_sign catsig command: %v"
,
cmd
)
if
err
:=
c
.
execTask
(
cmd
...
);
err
!=
nil
{
logrus
.
Errorf
(
"CascadeEnclaveSignature: sgx_sign catsig failed. error: %++v"
,
err
)
return
""
,
err
}
logrus
.
Debugf
(
"CascadeEnclaveSignature: sgx_sign catsig successfully"
)
return
signedEnclave
,
nil
}
// Cleanup impl Carrier.
func
(
c
*
occlum
)
Cleanup
()
error
{
//TODO
defer
func
()
{
if
c
.
task
.
client
!=
nil
{
c
.
task
.
client
.
Close
()
}
}()
defer
func
()
{
if
c
.
task
.
container
!=
nil
{
container
:=
*
c
.
task
.
container
if
err
:=
container
.
Delete
(
c
.
context
,
containerd
.
WithSnapshotCleanup
);
err
!=
nil
{
logrus
.
Errorf
(
"Cleanup: delete container %s failed. err: %++v"
,
container
.
ID
(),
err
)
}
logrus
.
Debugf
(
"Cleanup: delete container %s successfully."
,
container
.
ID
())
}
}()
if
c
.
task
.
task
==
nil
{
return
nil
}
t
:=
*
c
.
task
.
task
if
err
:=
t
.
Kill
(
c
.
context
,
syscall
.
SIGTERM
);
err
!=
nil
{
logrus
.
Errorf
(
"Cleanup: kill task %s failed. err: %++v"
,
t
.
ID
(),
err
)
return
err
}
for
{
status
,
err
:=
t
.
Status
(
c
.
context
)
if
err
!=
nil
{
logrus
.
Errorf
(
"Cleanup: get task %s status failed. error: %++v"
,
t
.
ID
(),
err
)
return
err
}
if
status
.
ExitStatus
!=
0
{
logrus
.
Errorf
(
"Cleanup: task %s exit abnormally. exit code: %d, task status: %s"
,
t
.
ID
(),
status
.
ExitStatus
,
status
.
Status
)
return
fmt
.
Errorf
(
"task %s exit abnormally. exit code: %d, task status: %s"
,
t
.
ID
(),
status
.
ExitStatus
,
status
.
Status
)
}
if
status
.
Status
!=
containerd
.
Stopped
{
logrus
.
Debugf
(
"Cleanup: task %s status: %s"
,
t
.
ID
(),
status
.
Status
)
time
.
Sleep
(
time
.
Second
)
continue
}
break
}
if
_
,
err
:=
t
.
Delete
(
c
.
context
);
err
!=
nil
{
logrus
.
Errorf
(
"Cleanup: delete task %s failed. error: %++v"
,
t
.
ID
(),
err
)
return
err
}
logrus
.
Debugf
(
"Cleanup: clean occlum container and task successfully"
)
return
nil
}
...
...
@@ -295,17 +333,14 @@ func (c *occlum) initBundleConfig() error {
carr_const
.
EnclaveTypeKeyName
:
string
(
carr_const
.
IntelSGX
),
carr_const
.
EnclaveRuntimeArgsKeyName
:
carr_const
.
DefaultEnclaveRuntimeArgs
,
}
if
o
cclumConfigPath
,
ok
:=
config
.
GetEnv
(
spec
,
carr_const
.
OcclumConfigPathKeyName
);
o
k
{
occlumConfigPath
,
ok
:=
config
.
GetEnv
(
spec
,
carr_const
.
OcclumConfigPathKeyName
)
if
ok
{
c
.
configPath
=
occlumConfigPath
}
c
.
spec
=
spec
if
err
:=
config
.
UpdateEnvs
(
spec
,
envs
,
false
);
err
!=
nil
{
return
err
}
return
config
.
SaveSpec
(
configPath
,
spec
)
}
...
...
@@ -328,13 +363,6 @@ func createNamespaceIfNotExist(client *containerd.Client, namespace string) erro
return
svc
.
Create
(
ctx
,
namespace
,
nil
)
}
// generateID generates a random unique id.
func
generateID
()
string
{
b
:=
make
([]
byte
,
32
)
rand
.
Read
(
b
)
return
hex
.
EncodeToString
(
b
)
}
func
setLogLevel
(
level
string
)
{
switch
level
{
case
"debug"
:
...
...
@@ -349,3 +377,50 @@ func setLogLevel(level string) {
logrus
.
SetLevel
(
logrus
.
InfoLevel
)
}
}
func
(
c
*
occlum
)
execTask
(
args
...
string
)
error
{
container
:=
*
c
.
task
.
container
t
:=
*
c
.
task
.
task
if
container
==
nil
||
t
==
nil
{
return
fmt
.
Errorf
(
"task is not exist"
)
}
spec
,
err
:=
container
.
Spec
(
c
.
context
)
if
err
!=
nil
{
logrus
.
Errorf
(
"execTask: get container spec failed. error: %++v"
,
err
)
return
err
}
pspec
:=
spec
.
Process
pspec
.
Terminal
=
false
pspec
.
Args
=
args
cioOpts
:=
[]
cio
.
Opt
{
cio
.
WithStdio
,
cio
.
WithFIFODir
(
"/run/containerd/fifo"
)}
ioCreator
:=
cio
.
NewCreator
(
cioOpts
...
)
process
,
err
:=
t
.
Exec
(
c
.
context
,
utils
.
GenerateID
(),
pspec
,
ioCreator
)
if
err
!=
nil
{
logrus
.
Errorf
(
"execTask: exec process in task failed. error: %++v"
,
err
)
return
err
}
defer
process
.
Delete
(
c
.
context
)
statusC
,
err
:=
process
.
Wait
(
c
.
context
)
if
err
!=
nil
{
return
err
}
sigc
:=
commands
.
ForwardAllSignals
(
c
.
context
,
process
)
defer
commands
.
StopCatch
(
sigc
)
if
err
:=
process
.
Start
(
c
.
context
);
err
!=
nil
{
logrus
.
Errorf
(
"execTask: start process failed. error: %++v"
,
err
)
return
err
}
status
:=
<-
statusC
code
,
_
,
err
:=
status
.
Result
()
if
err
!=
nil
{
logrus
.
Errorf
(
"execTask: exec process failed. error: %++v"
,
err
)
return
err
}
if
code
!=
0
{
return
fmt
.
Errorf
(
"process exit abnormaly. exitCode: %d, error: %++v"
,
code
,
status
.
Error
())
}
logrus
.
Debugf
(
"execTask: exec successfully."
)
return
nil
}
shim/runtime/utils/utils.go
0 → 100644
浏览文件 @
15f17876
package
utils
import
(
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"os"
)
func
CopyFile
(
src
,
dst
string
,
bufferSize
int64
)
error
{
sourceFileStat
,
err
:=
os
.
Stat
(
src
)
if
err
!=
nil
{
return
err
}
if
!
sourceFileStat
.
Mode
()
.
IsRegular
()
{
return
fmt
.
Errorf
(
"%s is not a regular file."
,
src
)
}
source
,
err
:=
os
.
Open
(
src
)
if
err
!=
nil
{
return
err
}
defer
source
.
Close
()
_
,
err
=
os
.
Stat
(
dst
)
if
err
==
nil
{
return
fmt
.
Errorf
(
"File %s already exists."
,
dst
)
}
destination
,
err
:=
os
.
Create
(
dst
)
if
err
!=
nil
{
return
err
}
defer
destination
.
Close
()
if
err
!=
nil
{
panic
(
err
)
}
buf
:=
make
([]
byte
,
bufferSize
)
for
{
n
,
err
:=
source
.
Read
(
buf
)
if
err
!=
nil
&&
err
!=
io
.
EOF
{
return
err
}
if
n
==
0
{
break
}
if
_
,
err
:=
destination
.
Write
(
buf
[
:
n
]);
err
!=
nil
{
return
err
}
}
return
err
}
// GenerateID generates a random unique id.
func
GenerateID
()
string
{
b
:=
make
([]
byte
,
32
)
rand
.
Read
(
b
)
return
hex
.
EncodeToString
(
b
)
}
shim/runtime/v2/rune/v2/rune.go
浏览文件 @
15f17876
...
...
@@ -31,9 +31,7 @@ func (s *service) carrierMain(req *taskAPI.CreateTaskRequest) (carrier.Carrier,
var
carr
carrier
.
Carrier
defer
func
()
{
if
err
!=
nil
&&
carr
!=
nil
{
carr
.
Cleanup
()
}
}()
found
,
carrierKind
,
err
:=
getCarrierKind
(
req
.
Bundle
)
...
...
@@ -98,8 +96,13 @@ func (s *service) carrierMain(req *taskAPI.CreateTaskRequest) (carrier.Carrier,
/*publicKey, signature, err := remoteSign("https://10.0.8.126:8443/api/v1/signature", commonArgs.Enclave)
defer os.RemoveAll(path.Dir(publicKey))*/
//FIXME mock signature
publicKey
,
signature
,
err
:=
mockSign
(
signingMaterial
)
materialRealPath
:=
signingMaterial
if
carrierKind
==
rune
.
Occlum
{
materialRealPath
=
filepath
.
Join
(
req
.
Bundle
,
signingMaterial
)
}
publicKey
,
signature
,
err
:=
mockSign
(
materialRealPath
)
if
err
!=
nil
{
logrus
.
Errorf
(
"carrierMain: mock sign failed. error: %++v"
,
err
)
return
carr
,
err
}
defer
os
.
RemoveAll
(
path
.
Dir
(
publicKey
))
...
...
@@ -115,12 +118,6 @@ func (s *service) carrierMain(req *taskAPI.CreateTaskRequest) (carrier.Carrier,
return
carr
,
err
}
logrus
.
Debugf
(
"Finished carrier: %v, signedEnclave: %s"
,
carr
,
signedEnclave
)
//FIXME debug
//if carrierKind == rune.Occlum {
// time.Sleep(time.Minute * 3)
//}
return
carr
,
nil
}
...
...
shim/runtime/v2/rune/v2/service.go
浏览文件 @
15f17876
...
...
@@ -305,12 +305,9 @@ func setOCIRuntime(ctx context.Context, r *taskAPI.CreateTaskRequest) (err error
// Create a new initial process and container with the underlying OCI runtime
func
(
s
*
service
)
Create
(
ctx
context
.
Context
,
r
*
taskAPI
.
CreateTaskRequest
)
(
_
*
taskAPI
.
CreateTaskResponse
,
err
error
)
{
logrus
.
Infof
(
"xxxx debug 0 =============="
)
s
.
mu
.
Lock
()
defer
s
.
mu
.
Unlock
()
logrus
.
Infof
(
"xxxx debug 1 =============="
)
err
=
setOCIRuntime
(
ctx
,
r
)
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -318,7 +315,6 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
carr
,
err
:=
s
.
carrierMain
(
r
)
if
err
!=
nil
{
logrus
.
Infof
(
"xxxx debug 2 =============="
)
return
nil
,
err
}
...
...
@@ -328,7 +324,6 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
container
,
err
:=
runc
.
NewContainer
(
ctx
,
s
.
platform
,
r
)
if
err
!=
nil
{
logrus
.
Errorf
(
"rune Create NewContainer error: %++v"
,
err
)
logrus
.
Infof
(
"xxxx debug 3 =============="
)
return
nil
,
err
}
...
...
@@ -381,7 +376,6 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
// log.G(ctx).Infof("Attestation Failed!")
//}
}
logrus
.
Infof
(
"xxxx debug 4 =============="
)
return
&
taskAPI
.
CreateTaskResponse
{
Pid
:
uint32
(
container
.
Pid
()),
},
nil
...
...
@@ -389,35 +383,28 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
// Start a process
func
(
s
*
service
)
Start
(
ctx
context
.
Context
,
r
*
taskAPI
.
StartRequest
)
(
*
taskAPI
.
StartResponse
,
error
)
{
logrus
.
Infof
(
"xxxx debug 5 =============="
)
container
,
err
:=
s
.
getContainer
(
r
.
ID
)
if
err
!=
nil
{
logrus
.
Infof
(
"xxxx debug 6 =============="
)
return
nil
,
err
}
// hold the send lock so that the start events are sent before any exit events in the error case
s
.
eventSendMu
.
Lock
()
p
,
err
:=
container
.
Start
(
ctx
,
r
)
logrus
.
Infof
(
"xxxx debug 7 =============="
)
if
err
!=
nil
{
s
.
eventSendMu
.
Unlock
()
logrus
.
Infof
(
"xxxx debug 8 ==============. error: %++v"
,
err
)
return
nil
,
errdefs
.
ToGRPC
(
err
)
}
switch
r
.
ExecID
{
case
""
:
if
err
:=
s
.
ep
.
Add
(
container
.
ID
,
container
.
Cgroup
());
err
!=
nil
{
logrus
.
Infof
(
"xxxx debug 9 =============="
)
logrus
.
WithError
(
err
)
.
Error
(
"add cg to OOM monitor"
)
}
logrus
.
Infof
(
"xxxx debug 10 =============="
)
s
.
send
(
&
eventstypes
.
TaskStart
{
ContainerID
:
container
.
ID
,
Pid
:
uint32
(
p
.
Pid
()),
})
default
:
logrus
.
Infof
(
"xxxx debug 11 =============="
)
s
.
send
(
&
eventstypes
.
TaskExecStarted
{
ContainerID
:
container
.
ID
,
ExecID
:
r
.
ExecID
,
...
...
@@ -425,7 +412,6 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.
})
}
s
.
eventSendMu
.
Unlock
()
logrus
.
Infof
(
"xxxx debug 12 =============="
)
return
&
taskAPI
.
StartResponse
{
Pid
:
uint32
(
p
.
Pid
()),
},
nil
...
...
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/client.go
0 → 100644
浏览文件 @
15f17876
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
commands
import
(
gocontext
"context"
"github.com/containerd/containerd"
"github.com/containerd/containerd/namespaces"
"github.com/urfave/cli"
)
// AppContext returns the context for a command. Should only be called once per
// command, near the start.
//
// This will ensure the namespace is picked up and set the timeout, if one is
// defined.
func
AppContext
(
context
*
cli
.
Context
)
(
gocontext
.
Context
,
gocontext
.
CancelFunc
)
{
var
(
ctx
=
gocontext
.
Background
()
timeout
=
context
.
GlobalDuration
(
"timeout"
)
namespace
=
context
.
GlobalString
(
"namespace"
)
cancel
gocontext
.
CancelFunc
)
ctx
=
namespaces
.
WithNamespace
(
ctx
,
namespace
)
if
timeout
>
0
{
ctx
,
cancel
=
gocontext
.
WithTimeout
(
ctx
,
timeout
)
}
else
{
ctx
,
cancel
=
gocontext
.
WithCancel
(
ctx
)
}
return
ctx
,
cancel
}
// NewClient returns a new containerd client
func
NewClient
(
context
*
cli
.
Context
,
opts
...
containerd
.
ClientOpt
)
(
*
containerd
.
Client
,
gocontext
.
Context
,
gocontext
.
CancelFunc
,
error
)
{
timeoutOpt
:=
containerd
.
WithTimeout
(
context
.
GlobalDuration
(
"connect-timeout"
))
opts
=
append
(
opts
,
timeoutOpt
)
client
,
err
:=
containerd
.
New
(
context
.
GlobalString
(
"address"
),
opts
...
)
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
ctx
,
cancel
:=
AppContext
(
context
)
return
client
,
ctx
,
cancel
,
nil
}
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/commands.go
0 → 100644
浏览文件 @
15f17876
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
commands
import
(
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/containerd/containerd/defaults"
"github.com/urfave/cli"
)
var
(
// SnapshotterFlags are cli flags specifying snapshotter names
SnapshotterFlags
=
[]
cli
.
Flag
{
cli
.
StringFlag
{
Name
:
"snapshotter"
,
Usage
:
"snapshotter name. Empty value stands for the default value."
,
EnvVar
:
"CONTAINERD_SNAPSHOTTER"
,
},
}
// LabelFlag is a cli flag specifying labels
LabelFlag
=
cli
.
StringSliceFlag
{
Name
:
"label"
,
Usage
:
"labels to attach to the image"
,
}
// RegistryFlags are cli flags specifying registry options
RegistryFlags
=
[]
cli
.
Flag
{
cli
.
BoolFlag
{
Name
:
"skip-verify,k"
,
Usage
:
"skip SSL certificate validation"
,
},
cli
.
BoolFlag
{
Name
:
"plain-http"
,
Usage
:
"allow connections using plain HTTP"
,
},
cli
.
StringFlag
{
Name
:
"user,u"
,
Usage
:
"user[:password] Registry user and password"
,
},
cli
.
StringFlag
{
Name
:
"refresh"
,
Usage
:
"refresh token for authorization server"
,
},
}
// ContainerFlags are cli flags specifying container options
ContainerFlags
=
[]
cli
.
Flag
{
cli
.
StringFlag
{
Name
:
"config,c"
,
Usage
:
"path to the runtime-specific spec config file"
,
},
cli
.
StringFlag
{
Name
:
"cwd"
,
Usage
:
"specify the working directory of the process"
,
},
cli
.
StringSliceFlag
{
Name
:
"env"
,
Usage
:
"specify additional container environment variables (i.e. FOO=bar)"
,
},
cli
.
StringFlag
{
Name
:
"env-file"
,
Usage
:
"specify additional container environment variables in a file(i.e. FOO=bar, one per line)"
,
},
cli
.
StringSliceFlag
{
Name
:
"label"
,
Usage
:
"specify additional labels (i.e. foo=bar)"
,
},
cli
.
StringSliceFlag
{
Name
:
"mount"
,
Usage
:
"specify additional container mount (ex: type=bind,src=/tmp,dst=/host,options=rbind:ro)"
,
},
cli
.
BoolFlag
{
Name
:
"net-host"
,
Usage
:
"enable host networking for the container"
,
},
cli
.
BoolFlag
{
Name
:
"privileged"
,
Usage
:
"run privileged container"
,
},
cli
.
BoolFlag
{
Name
:
"read-only"
,
Usage
:
"set the containers filesystem as readonly"
,
},
cli
.
StringFlag
{
Name
:
"runtime"
,
Usage
:
"runtime name"
,
Value
:
defaults
.
DefaultRuntime
,
},
cli
.
BoolFlag
{
Name
:
"tty,t"
,
Usage
:
"allocate a TTY for the container"
,
},
cli
.
StringSliceFlag
{
Name
:
"with-ns"
,
Usage
:
"specify existing Linux namespaces to join at container runtime (format '<nstype>:<path>')"
,
},
cli
.
StringFlag
{
Name
:
"pid-file"
,
Usage
:
"file path to write the task's pid"
,
},
cli
.
IntFlag
{
Name
:
"gpus"
,
Usage
:
"add gpus to the container"
,
},
cli
.
BoolFlag
{
Name
:
"allow-new-privs"
,
Usage
:
"turn off OCI spec's NoNewPrivileges feature flag"
,
},
cli
.
Uint64Flag
{
Name
:
"memory-limit"
,
Usage
:
"memory limit (in bytes) for the container"
,
},
cli
.
StringSliceFlag
{
Name
:
"device"
,
Usage
:
"add a device to a container"
,
},
cli
.
BoolFlag
{
Name
:
"seccomp"
,
Usage
:
"enable the default seccomp profile"
,
},
}
)
// ObjectWithLabelArgs returns the first arg and a LabelArgs object
func
ObjectWithLabelArgs
(
clicontext
*
cli
.
Context
)
(
string
,
map
[
string
]
string
)
{
var
(
first
=
clicontext
.
Args
()
.
First
()
labelStrings
=
clicontext
.
Args
()
.
Tail
()
)
return
first
,
LabelArgs
(
labelStrings
)
}
// LabelArgs returns a map of label key,value pairs
func
LabelArgs
(
labelStrings
[]
string
)
map
[
string
]
string
{
labels
:=
make
(
map
[
string
]
string
,
len
(
labelStrings
))
for
_
,
label
:=
range
labelStrings
{
parts
:=
strings
.
SplitN
(
label
,
"="
,
2
)
key
:=
parts
[
0
]
value
:=
"true"
if
len
(
parts
)
>
1
{
value
=
parts
[
1
]
}
labels
[
key
]
=
value
}
return
labels
}
// PrintAsJSON prints input in JSON format
func
PrintAsJSON
(
x
interface
{})
{
b
,
err
:=
json
.
MarshalIndent
(
x
,
""
,
" "
)
if
err
!=
nil
{
fmt
.
Fprintf
(
os
.
Stderr
,
"can't marshal %+v as a JSON string: %v
\n
"
,
x
,
err
)
}
fmt
.
Println
(
string
(
b
))
}
// WritePidFile writes the pid atomically to a file
func
WritePidFile
(
path
string
,
pid
int
)
error
{
path
,
err
:=
filepath
.
Abs
(
path
)
if
err
!=
nil
{
return
err
}
tempPath
:=
filepath
.
Join
(
filepath
.
Dir
(
path
),
fmt
.
Sprintf
(
".%s"
,
filepath
.
Base
(
path
)))
f
,
err
:=
os
.
OpenFile
(
tempPath
,
os
.
O_RDWR
|
os
.
O_CREATE
|
os
.
O_EXCL
|
os
.
O_SYNC
,
0666
)
if
err
!=
nil
{
return
err
}
_
,
err
=
fmt
.
Fprintf
(
f
,
"%d"
,
pid
)
f
.
Close
()
if
err
!=
nil
{
return
err
}
return
os
.
Rename
(
tempPath
,
path
)
}
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/commands_unix.go
0 → 100644
浏览文件 @
15f17876
// +build !windows
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
commands
import
(
"github.com/urfave/cli"
)
func
init
()
{
ContainerFlags
=
append
(
ContainerFlags
,
cli
.
BoolFlag
{
Name
:
"rootfs"
,
Usage
:
"use custom rootfs that is not managed by containerd snapshotter"
,
},
cli
.
BoolFlag
{
Name
:
"no-pivot"
,
Usage
:
"disable use of pivot-root (linux only)"
,
})
}
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/commands_windows.go
0 → 100644
浏览文件 @
15f17876
// +build windows
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
commands
import
(
"github.com/urfave/cli"
)
func
init
()
{
ContainerFlags
=
append
(
ContainerFlags
,
cli
.
Uint64Flag
{
Name
:
"cpu-count"
,
Usage
:
"number of CPUs available to the container"
,
})
}
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/resolver.go
0 → 100644
浏览文件 @
15f17876
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
commands
import
(
"bufio"
gocontext
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"strings"
"time"
"github.com/containerd/console"
"github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
// PushTracker returns a new InMemoryTracker which tracks the ref status
var
PushTracker
=
docker
.
NewInMemoryTracker
()
func
passwordPrompt
()
(
string
,
error
)
{
c
:=
console
.
Current
()
defer
c
.
Reset
()
if
err
:=
c
.
DisableEcho
();
err
!=
nil
{
return
""
,
errors
.
Wrap
(
err
,
"failed to disable echo"
)
}
line
,
_
,
err
:=
bufio
.
NewReader
(
c
)
.
ReadLine
()
if
err
!=
nil
{
return
""
,
errors
.
Wrap
(
err
,
"failed to read line"
)
}
return
string
(
line
),
nil
}
// GetResolver prepares the resolver from the environment and options
func
GetResolver
(
ctx
gocontext
.
Context
,
clicontext
*
cli
.
Context
)
(
remotes
.
Resolver
,
error
)
{
username
:=
clicontext
.
String
(
"user"
)
var
secret
string
if
i
:=
strings
.
IndexByte
(
username
,
':'
);
i
>
0
{
secret
=
username
[
i
+
1
:
]
username
=
username
[
0
:
i
]
}
options
:=
docker
.
ResolverOptions
{
PlainHTTP
:
clicontext
.
Bool
(
"plain-http"
),
Tracker
:
PushTracker
,
}
if
username
!=
""
{
if
secret
==
""
{
fmt
.
Printf
(
"Password: "
)
var
err
error
secret
,
err
=
passwordPrompt
()
if
err
!=
nil
{
return
nil
,
err
}
fmt
.
Print
(
"
\n
"
)
}
}
else
if
rt
:=
clicontext
.
String
(
"refresh"
);
rt
!=
""
{
secret
=
rt
}
tr
:=
&
http
.
Transport
{
Proxy
:
http
.
ProxyFromEnvironment
,
DialContext
:
(
&
net
.
Dialer
{
Timeout
:
30
*
time
.
Second
,
KeepAlive
:
30
*
time
.
Second
,
DualStack
:
true
,
})
.
DialContext
,
MaxIdleConns
:
10
,
IdleConnTimeout
:
30
*
time
.
Second
,
TLSHandshakeTimeout
:
10
*
time
.
Second
,
TLSClientConfig
:
&
tls
.
Config
{
InsecureSkipVerify
:
clicontext
.
Bool
(
"skip-verify"
),
},
ExpectContinueTimeout
:
5
*
time
.
Second
,
}
options
.
Client
=
&
http
.
Client
{
Transport
:
tr
,
}
credentials
:=
func
(
host
string
)
(
string
,
string
,
error
)
{
// Only one host
return
username
,
secret
,
nil
}
authOpts
:=
[]
docker
.
AuthorizerOpt
{
docker
.
WithAuthClient
(
options
.
Client
),
docker
.
WithAuthCreds
(
credentials
)}
options
.
Authorizer
=
docker
.
NewDockerAuthorizer
(
authOpts
...
)
return
docker
.
NewResolver
(
options
),
nil
}
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/signals.go
0 → 100644
浏览文件 @
15f17876
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
commands
import
(
gocontext
"context"
"os"
"os/signal"
"syscall"
"github.com/containerd/containerd"
"github.com/sirupsen/logrus"
)
type
killer
interface
{
Kill
(
gocontext
.
Context
,
syscall
.
Signal
,
...
containerd
.
KillOpts
)
error
}
// ForwardAllSignals forwards signals
func
ForwardAllSignals
(
ctx
gocontext
.
Context
,
task
killer
)
chan
os
.
Signal
{
sigc
:=
make
(
chan
os
.
Signal
,
128
)
signal
.
Notify
(
sigc
)
go
func
()
{
for
s
:=
range
sigc
{
logrus
.
Debug
(
"forwarding signal "
,
s
)
if
err
:=
task
.
Kill
(
ctx
,
s
.
(
syscall
.
Signal
));
err
!=
nil
{
logrus
.
WithError
(
err
)
.
Errorf
(
"forward signal %s"
,
s
)
}
}
}()
return
sigc
}
// StopCatch stops and closes a channel
func
StopCatch
(
sigc
chan
os
.
Signal
)
{
signal
.
Stop
(
sigc
)
close
(
sigc
)
}
shim/vendor/github.com/containerd/containerd/cmd/ctr/commands/utils.go
0 → 100644
浏览文件 @
15f17876
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
commands
// IntToInt32Array converts an array of int's to int32's
func
IntToInt32Array
(
in
[]
int
)
[]
int32
{
var
ret
[]
int32
for
_
,
v
:=
range
in
{
ret
=
append
(
ret
,
int32
(
v
))
}
return
ret
}
shim/vendor/github.com/containerd/go-runc/monitor.go
浏览文件 @
15f17876
...
...
@@ -74,3 +74,6 @@ func (m *defaultMonitor) Wait(c *exec.Cmd, ec chan Exit) (int, error) {
e
:=
<-
ec
return
e
.
Status
,
nil
}
shim/vendor/github.com/urfave/cli/.flake8
0 → 100644
浏览文件 @
15f17876
[flake8]
max-line-length = 120
shim/vendor/github.com/urfave/cli/.gitignore
0 → 100644
浏览文件 @
15f17876
*.coverprofile
node_modules/
shim/vendor/github.com/urfave/cli/.travis.yml
0 → 100644
浏览文件 @
15f17876
language
:
go
sudo
:
false
dist
:
trusty
osx_image
:
xcode8.3
go
:
1.8.x
os
:
-
linux
-
osx
cache
:
directories
:
-
node_modules
before_script
:
-
go get github.com/urfave/gfmrun/... ||
true
-
go get golang.org/x/tools/cmd/goimports
-
if [ ! -f node_modules/.bin/markdown-toc ] ; then
npm install markdown-toc ;
fi
script
:
-
./runtests gen
-
./runtests vet
-
./runtests test
-
./runtests gfmrun
-
./runtests toc
shim/vendor/github.com/urfave/cli/CHANGELOG.md
0 → 100644
浏览文件 @
15f17876
# Change Log
**ATTN**
: This project uses
[
semantic versioning
](
http://semver.org/
)
.
## [Unreleased]
## 1.20.0 - 2017-08-10
### Fixed
*
`HandleExitCoder`
is now correctly iterates over all errors in
a
`MultiError`
. The exit code is the exit code of the last error or
`1`
if
there are no
`ExitCoder`
s in the
`MultiError`
.
*
Fixed YAML file loading on Windows (previously would fail validate the file path)
*
Subcommand
`Usage`
,
`Description`
,
`ArgsUsage`
,
`OnUsageError`
correctly
propogated
*
`ErrWriter`
is now passed downwards through command structure to avoid the
need to redefine it
*
Pass
`Command`
context into
`OnUsageError`
rather than parent context so that
all fields are avaiable
*
Errors occuring in
`Before`
funcs are no longer double printed
*
Use
`UsageText`
in the help templates for commands and subcommands if
defined; otherwise build the usage as before (was previously ignoring this
field)
*
`IsSet`
and
`GlobalIsSet`
now correctly return whether a flag is set if
a program calls
`Set`
or
`GlobalSet`
directly after flag parsing (would
previously only return
`true`
if the flag was set during parsing)
### Changed
*
No longer exit the program on command/subcommand error if the error raised is
not an
`OsExiter`
. This exiting behavior was introduced in 1.19.0, but was
determined to be a regression in functionality. See
[
the
PR
](
https://github.com/urfave/cli/pull/595
)
for discussion.
### Added
*
`CommandsByName`
type was added to make it easy to sort
`Command`
s by name,
alphabetically
*
`altsrc`
now handles loading of string and int arrays from TOML
*
Support for definition of custom help templates for
`App`
via
`CustomAppHelpTemplate`
*
Support for arbitrary key/value fields on
`App`
to be used with
`CustomAppHelpTemplate`
via
`ExtraInfo`
*
`HelpFlag`
,
`VersionFlag`
, and
`BashCompletionFlag`
changed to explictly be
`cli.Flag`
s allowing for the use of custom flags satisfying the
`cli.Flag`
interface to be used.
## [1.19.1] - 2016-11-21
### Fixed
-
Fixes regression introduced in 1.19.0 where using an
`ActionFunc`
as
the
`Action`
for a command would cause it to error rather than calling the
function. Should not have a affected declarative cases using
`func(c
*cli.Context) err)`
.
-
Shell completion now handles the case where the user specifies
`--generate-bash-completion`
immediately after a flag that takes an argument.
Previously it call the application with
`--generate-bash-completion`
as the
flag value.
## [1.19.0] - 2016-11-19
### Added
-
`FlagsByName`
was added to make it easy to sort flags (e.g.
`sort.Sort(cli.FlagsByName(app.Flags))`
)
-
A
`Description`
field was added to
`App`
for a more detailed description of
the application (similar to the existing
`Description`
field on
`Command`
)
-
Flag type code generation via
`go generate`
-
Write to stderr and exit 1 if action returns non-nil error
-
Added support for TOML to the
`altsrc`
loader
-
`SkipArgReorder`
was added to allow users to skip the argument reordering.
This is useful if you want to consider all "flags" after an argument as
arguments rather than flags (the default behavior of the stdlib
`flag`
library). This is backported functionality from the
[
removal of the flag
reordering
](
https://github.com/urfave/cli/pull/398
)
in the unreleased version
2
-
For formatted errors (those implementing
`ErrorFormatter`
), the errors will
be formatted during output. Compatible with
`pkg/errors`
.
### Changed
-
Raise minimum tested/supported Go version to 1.2+
### Fixed
-
Consider empty environment variables as set (previously environment variables
with the equivalent of
`""`
would be skipped rather than their value used).
-
Return an error if the value in a given environment variable cannot be parsed
as the flag type. Previously these errors were silently swallowed.
-
Print full error when an invalid flag is specified (which includes the invalid flag)
-
`App.Writer`
defaults to
`stdout`
when
`nil`
-
If no action is specified on a command or app, the help is now printed instead of
`panic`
ing
-
`App.Metadata`
is initialized automatically now (previously was
`nil`
unless initialized)
-
Correctly show help message if
`-h`
is provided to a subcommand
-
`context.(Global)IsSet`
now respects environment variables. Previously it
would return
`false`
if a flag was specified in the environment rather than
as an argument
-
Removed deprecation warnings to STDERR to avoid them leaking to the end-user
-
`altsrc`
s import paths were updated to use
`gopkg.in/urfave/cli.v1`
. This
fixes issues that occurred when
`gopkg.in/urfave/cli.v1`
was imported as well
as
`altsrc`
where Go would complain that the types didn't match
## [1.18.1] - 2016-08-28
### Fixed
-
Removed deprecation warnings to STDERR to avoid them leaking to the end-user (backported)
## [1.18.0] - 2016-06-27
### Added
-
`./runtests`
test runner with coverage tracking by default
-
testing on OS X
-
testing on Windows
-
`UintFlag`
,
`Uint64Flag`
, and
`Int64Flag`
types and supporting code
### Changed
-
Use spaces for alignment in help/usage output instead of tabs, making the
output alignment consistent regardless of tab width
### Fixed
-
Printing of command aliases in help text
-
Printing of visible flags for both struct and struct pointer flags
-
Display the
`help`
subcommand when using
`CommandCategories`
-
No longer swallows
`panic`
s that occur within the
`Action`
s themselves when
detecting the signature of the
`Action`
field
## [1.17.1] - 2016-08-28
### Fixed
-
Removed deprecation warnings to STDERR to avoid them leaking to the end-user
## [1.17.0] - 2016-05-09
### Added
-
Pluggable flag-level help text rendering via
`cli.DefaultFlagStringFunc`
-
`context.GlobalBoolT`
was added as an analogue to
`context.GlobalBool`
-
Support for hiding commands by setting
`Hidden: true`
-- this will hide the
commands in help output
### Changed
-
`Float64Flag`
,
`IntFlag`
, and
`DurationFlag`
default values are no longer
quoted in help text output.
-
All flag types now include
`(default: {value})`
strings following usage when a
default value can be (reasonably) detected.
-
`IntSliceFlag`
and
`StringSliceFlag`
usage strings are now more consistent
with non-slice flag types
-
Apps now exit with a code of 3 if an unknown subcommand is specified
(previously they printed "No help topic for...", but still exited 0. This
makes it easier to script around apps built using
`cli`
since they can trust
that a 0 exit code indicated a successful execution.
-
cleanups based on
[
Go Report Card
feedback
](
https://goreportcard.com/report/github.com/urfave/cli
)
## [1.16.1] - 2016-08-28
### Fixed
-
Removed deprecation warnings to STDERR to avoid them leaking to the end-user
## [1.16.0] - 2016-05-02
### Added
-
`Hidden`
field on all flag struct types to omit from generated help text
### Changed
-
`BashCompletionFlag`
(
`--enable-bash-completion`
) is now omitted from
generated help text via the
`Hidden`
field
### Fixed
-
handling of error values in
`HandleAction`
and
`HandleExitCoder`
## [1.15.0] - 2016-04-30
### Added
-
This file!
-
Support for placeholders in flag usage strings
-
`App.Metadata`
map for arbitrary data/state management
-
`Set`
and
`GlobalSet`
methods on
`*cli.Context`
for altering values after
parsing.
-
Support for nested lookup of dot-delimited keys in structures loaded from
YAML.
### Changed
-
The
`App.Action`
and
`Command.Action`
now prefer a return signature of
`func(*cli.Context) error`
, as defined by
`cli.ActionFunc`
. If a non-nil
`error`
is returned, there may be two outcomes:
-
If the error fulfills
`cli.ExitCoder`
, then
`os.Exit`
will be called
automatically
-
Else the error is bubbled up and returned from
`App.Run`
-
Specifying an
`Action`
with the legacy return signature of
`func(*cli.Context)`
will produce a deprecation message to stderr
-
Specifying an
`Action`
that is not a
`func`
type will produce a non-zero exit
from
`App.Run`
-
Specifying an
`Action`
func that has an invalid (input) signature will
produce a non-zero exit from
`App.Run`
### Deprecated
-
<a
name=
"deprecated-cli-app-runandexitonerror"
></a>
`cli.App.RunAndExitOnError`
, which should now be done by returning an error
that fulfills
`cli.ExitCoder`
to
`cli.App.Run`
.
-
<a
name=
"deprecated-cli-app-action-signature"
></a>
the legacy signature for
`cli.App.Action`
of
`func(*cli.Context)`
, which should now have a return
signature of
`func(*cli.Context) error`
, as defined by
`cli.ActionFunc`
.
### Fixed
-
Added missing
`*cli.Context.GlobalFloat64`
method
## [1.14.0] - 2016-04-03 (backfilled 2016-04-25)
### Added
-
Codebeat badge
-
Support for categorization via
`CategorizedHelp`
and
`Categories`
on app.
### Changed
-
Use
`filepath.Base`
instead of
`path.Base`
in
`Name`
and
`HelpName`
.
### Fixed
-
Ensure version is not shown in help text when
`HideVersion`
set.
## [1.13.0] - 2016-03-06 (backfilled 2016-04-25)
### Added
-
YAML file input support.
-
`NArg`
method on context.
## [1.12.0] - 2016-02-17 (backfilled 2016-04-25)
### Added
-
Custom usage error handling.
-
Custom text support in
`USAGE`
section of help output.
-
Improved help messages for empty strings.
-
AppVeyor CI configuration.
### Changed
-
Removed
`panic`
from default help printer func.
-
De-duping and optimizations.
### Fixed
-
Correctly handle
`Before`
/
`After`
at command level when no subcommands.
-
Case of literal
`-`
argument causing flag reordering.
-
Environment variable hints on Windows.
-
Docs updates.
## [1.11.1] - 2015-12-21 (backfilled 2016-04-25)
### Changed
-
Use
`path.Base`
in
`Name`
and
`HelpName`
-
Export
`GetName`
on flag types.
### Fixed
-
Flag parsing when skipping is enabled.
-
Test output cleanup.
-
Move completion check to account for empty input case.
## [1.11.0] - 2015-11-15 (backfilled 2016-04-25)
### Added
-
Destination scan support for flags.
-
Testing against
`tip`
in Travis CI config.
### Changed
-
Go version in Travis CI config.
### Fixed
-
Removed redundant tests.
-
Use correct example naming in tests.
## [1.10.2] - 2015-10-29 (backfilled 2016-04-25)
### Fixed
-
Remove unused var in bash completion.
## [1.10.1] - 2015-10-21 (backfilled 2016-04-25)
### Added
-
Coverage and reference logos in README.
### Fixed
-
Use specified values in help and version parsing.
-
Only display app version and help message once.
## [1.10.0] - 2015-10-06 (backfilled 2016-04-25)
### Added
-
More tests for existing functionality.
-
`ArgsUsage`
at app and command level for help text flexibility.
### Fixed
-
Honor
`HideHelp`
and
`HideVersion`
in
`App.Run`
.
-
Remove juvenile word from README.
## [1.9.0] - 2015-09-08 (backfilled 2016-04-25)
### Added
-
`FullName`
on command with accompanying help output update.
-
Set default
`$PROG`
in bash completion.
### Changed
-
Docs formatting.
### Fixed
-
Removed self-referential imports in tests.
## [1.8.0] - 2015-06-30 (backfilled 2016-04-25)
### Added
-
Support for
`Copyright`
at app level.
-
`Parent`
func at context level to walk up context lineage.
### Fixed
-
Global flag processing at top level.
## [1.7.1] - 2015-06-11 (backfilled 2016-04-25)
### Added
-
Aggregate errors from
`Before`
/
`After`
funcs.
-
Doc comments on flag structs.
-
Include non-global flags when checking version and help.
-
Travis CI config updates.
### Fixed
-
Ensure slice type flags have non-nil values.
-
Collect global flags from the full command hierarchy.
-
Docs prose.
## [1.7.0] - 2015-05-03 (backfilled 2016-04-25)
### Changed
-
`HelpPrinter`
signature includes output writer.
### Fixed
-
Specify go 1.1+ in docs.
-
Set
`Writer`
when running command as app.
## [1.6.0] - 2015-03-23 (backfilled 2016-04-25)
### Added
-
Multiple author support.
-
`NumFlags`
at context level.
-
`Aliases`
at command level.
### Deprecated
-
`ShortName`
at command level.
### Fixed
-
Subcommand help output.
-
Backward compatible support for deprecated
`Author`
and
`Email`
fields.
-
Docs regarding
`Names`
/
`Aliases`
.
## [1.5.0] - 2015-02-20 (backfilled 2016-04-25)
### Added
-
`After`
hook func support at app and command level.
### Fixed
-
Use parsed context when running command as subcommand.
-
Docs prose.
## [1.4.1] - 2015-01-09 (backfilled 2016-04-25)
### Added
-
Support for hiding
`-h / --help`
flags, but not
`help`
subcommand.
-
Stop flag parsing after
`--`
.
### Fixed
-
Help text for generic flags to specify single value.
-
Use double quotes in output for defaults.
-
Use
`ParseInt`
instead of
`ParseUint`
for int environment var values.
-
Use
`0`
as base when parsing int environment var values.
## [1.4.0] - 2014-12-12 (backfilled 2016-04-25)
### Added
-
Support for environment variable lookup "cascade".
-
Support for
`Stdout`
on app for output redirection.
### Fixed
-
Print command help instead of app help in
`ShowCommandHelp`
.
## [1.3.1] - 2014-11-13 (backfilled 2016-04-25)
### Added
-
Docs and example code updates.
### Changed
-
Default
`-v / --version`
flag made optional.
## [1.3.0] - 2014-08-10 (backfilled 2016-04-25)
### Added
-
`FlagNames`
at context level.
-
Exposed
`VersionPrinter`
var for more control over version output.
-
Zsh completion hook.
-
`AUTHOR`
section in default app help template.
-
Contribution guidelines.
-
`DurationFlag`
type.
## [1.2.0] - 2014-08-02
### Added
-
Support for environment variable defaults on flags plus tests.
## [1.1.0] - 2014-07-15
### Added
-
Bash completion.
-
Optional hiding of built-in help command.
-
Optional skipping of flag parsing at command level.
-
`Author`
,
`Email`
, and
`Compiled`
metadata on app.
-
`Before`
hook func support at app and command level.
-
`CommandNotFound`
func support at app level.
-
Command reference available on context.
-
`GenericFlag`
type.
-
`Float64Flag`
type.
-
`BoolTFlag`
type.
-
`IsSet`
flag helper on context.
-
More flag lookup funcs at context level.
-
More tests
&
docs.
### Changed
-
Help template updates to account for presence/absence of flags.
-
Separated subcommand help template.
-
Exposed
`HelpPrinter`
var for more control over help output.
## [1.0.0] - 2013-11-01
### Added
-
`help`
flag in default app flag set and each command flag set.
-
Custom handling of argument parsing errors.
-
Command lookup by name at app level.
-
`StringSliceFlag`
type and supporting
`StringSlice`
type.
-
`IntSliceFlag`
type and supporting
`IntSlice`
type.
-
Slice type flag lookups by name at context level.
-
Export of app and command help functions.
-
More tests
&
docs.
## 0.1.0 - 2013-07-22
### Added
-
Initial implementation.
[
Unreleased
]:
https://github.com/urfave/cli/compare/v1.18.0...HEAD
[
1.18.0
]:
https://github.com/urfave/cli/compare/v1.17.0...v1.18.0
[
1.17.0
]:
https://github.com/urfave/cli/compare/v1.16.0...v1.17.0
[
1.16.0
]:
https://github.com/urfave/cli/compare/v1.15.0...v1.16.0
[
1.15.0
]:
https://github.com/urfave/cli/compare/v1.14.0...v1.15.0
[
1.14.0
]:
https://github.com/urfave/cli/compare/v1.13.0...v1.14.0
[
1.13.0
]:
https://github.com/urfave/cli/compare/v1.12.0...v1.13.0
[
1.12.0
]:
https://github.com/urfave/cli/compare/v1.11.1...v1.12.0
[
1.11.1
]:
https://github.com/urfave/cli/compare/v1.11.0...v1.11.1
[
1.11.0
]:
https://github.com/urfave/cli/compare/v1.10.2...v1.11.0
[
1.10.2
]:
https://github.com/urfave/cli/compare/v1.10.1...v1.10.2
[
1.10.1
]:
https://github.com/urfave/cli/compare/v1.10.0...v1.10.1
[
1.10.0
]:
https://github.com/urfave/cli/compare/v1.9.0...v1.10.0
[
1.9.0
]:
https://github.com/urfave/cli/compare/v1.8.0...v1.9.0
[
1.8.0
]:
https://github.com/urfave/cli/compare/v1.7.1...v1.8.0
[
1.7.1
]:
https://github.com/urfave/cli/compare/v1.7.0...v1.7.1
[
1.7.0
]:
https://github.com/urfave/cli/compare/v1.6.0...v1.7.0
[
1.6.0
]:
https://github.com/urfave/cli/compare/v1.5.0...v1.6.0
[
1.5.0
]:
https://github.com/urfave/cli/compare/v1.4.1...v1.5.0
[
1.4.1
]:
https://github.com/urfave/cli/compare/v1.4.0...v1.4.1
[
1.4.0
]:
https://github.com/urfave/cli/compare/v1.3.1...v1.4.0
[
1.3.1
]:
https://github.com/urfave/cli/compare/v1.3.0...v1.3.1
[
1.3.0
]:
https://github.com/urfave/cli/compare/v1.2.0...v1.3.0
[
1.2.0
]:
https://github.com/urfave/cli/compare/v1.1.0...v1.2.0
[
1.1.0
]:
https://github.com/urfave/cli/compare/v1.0.0...v1.1.0
[
1.0.0
]:
https://github.com/urfave/cli/compare/v0.1.0...v1.0.0
shim/vendor/github.com/urfave/cli/LICENSE
0 → 100644
浏览文件 @
15f17876
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.
shim/vendor/github.com/urfave/cli/README.md
0 → 100644
浏览文件 @
15f17876
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)
**Notice:**
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 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
)
-
[
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": ["
--
help"],
"output": "A new cli application"
} -->
```
go
package
main
import
(
"os"
"github.com/urfave/cli"
)
func
main
()
{
cli
.
NewApp
()
.
Run
(
os
.
Args
)
}
```
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"
"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
}
app
.
Run
(
os
.
Args
)
}
```
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"
"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
}
app
.
Run
(
os
.
Args
)
}
```
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"
"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
}
app
.
Run
(
os
.
Args
)
}
```
### Flags
Setting and querying flags is simple.
<!-- {
"output": "Hello Nefertiti"
} -->
```
go
package
main
import
(
"fmt"
"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
}
app
.
Run
(
os
.
Args
)
}
```
You can also set a destination variable for a flag, to which the content will be
scanned.
<!-- {
"output": "Hello someone"
} -->
```
go
package
main
import
(
"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
}
app
.
Run
(
os
.
Args
)
}
```
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": ["
--
help"],
"output": "
--
config FILE,
-
c FILE"
} -->
```
go
package
main
import
(
"os"
"github.com/urfave/cli"
)
func
main
()
{
app
:=
cli
.
NewApp
()
app
.
Flags
=
[]
cli
.
Flag
{
cli
.
StringFlag
{
Name
:
"config, c"
,
Usage
:
"Load configuration from `FILE`"
,
},
}
app
.
Run
(
os
.
Args
)
}
```
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": ["
--
help"],
"output": "
--
lang value,
-
l value.
*language for the greeting.*
default:
\"
english
\"
"
} -->
```
go
package
main
import
(
"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"
,
},
}
app
.
Run
(
os
.
Args
)
}
```
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": ["
--
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
(
"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
))
app
.
Run
(
os
.
Args
)
}
```
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": ["
--
help"],
"output": "language for the greeting.
*
APP_LANG"
} -->
```
go
package
main
import
(
"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"
,
},
}
app
.
Run
(
os
.
Args
)
}
```
The
`EnvVar`
may also be given as a comma-delimited "cascade", where the first
environment variable that resolves is used as the default.
<!-- {
"args": ["
--
help"],
"output": "language for the greeting.
*LEGACY_COMPAT_LANG.*
APP_LANG.
*
LANG"
} -->
```
go
package
main
import
(
"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"
,
},
}
app
.
Run
(
os
.
Args
)
}
```
#### 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 the aboved specified formats 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", "
--
help"],
"output": "
--
test value.
*
default: 0"
} -->
```
go
package
notmain
import
(
"fmt"
"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
app
.
Run
(
os
.
Args
)
}
```
#### 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"
"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
},
},
},
},
}
app
.
Run
(
os
.
Args
)
}
```
### 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
(
"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"
,
},
}
app
.
Run
(
os
.
Args
)
}
```
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
(
"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
}
app
.
Run
(
os
.
Args
)
}
```
### 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", "
--
generate
-
bash
-
completion"],
"output": "laundry"
} -->
```
go
package
main
import
(
"fmt"
"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
)
}
},
},
}
app
.
Run
(
os
.
Args
)
}
```
#### 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": ["
--
compgen"],
"output": "wat
\n
help
\n
h"
} -->
```
go
package
main
import
(
"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"
,
},
}
app
.
Run
(
os
.
Args
)
}
```
### 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"
"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"
)
}
cli
.
NewApp
()
.
Run
(
os
.
Args
)
}
```
The default flag may be customized to something other than
`-h/--help`
by
setting
`cli.HelpFlag`
, e.g.:
<!-- {
"args": ["
-
-halp"],
"output": "haaaaalp.
*
HALP"
} -->
```
go
package
main
import
(
"os"
"github.com/urfave/cli"
)
func
main
()
{
cli
.
HelpFlag
=
cli
.
BoolFlag
{
Name
:
"halp, haaaaalp"
,
Usage
:
"HALP"
,
EnvVar
:
"SHOW_HALP,HALPPLZ"
,
}
cli
.
NewApp
()
.
Run
(
os
.
Args
)
}
```
### 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": ["
-
-print-version"],
"output": "partay version 19
\\
.99
\\
.0"
} -->
```
go
package
main
import
(
"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"
app
.
Run
(
os
.
Args
)
}
```
Alternatively, the version printer at
`cli.VersionPrinter`
may be overridden, e.g.:
<!-- {
"args": ["
-
-version"],
"output": "version=19
\\
.99
\\
.0 revision=fafafaf"
} -->
```
go
package
main
import
(
"fmt"
"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"
app
.
Run
(
os
.
Args
)
}
```
#### 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!
\n
Phew!"
} -->
```
go
package
main
import
(
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"time"
"github.com/urfave/cli"
)
func
init
()
{
cli
.
AppHelpTemplate
+=
"
\n
CUSTOMIZED: you bet ur muffins
\n
"
cli
.
CommandHelpTemplate
+=
"
\n
YMMV
\n
"
cli
.
SubcommandHelpTemplate
+=
"
\n
or 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
\n
kiss
\n
me
\n
lipstick
\n
ringo
\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
ec
}
if
os
.
Getenv
(
"HEXY"
)
!=
""
{
app
.
Writer
=
&
hexWriter
{}
app
.
ErrWriter
=
&
hexWriter
{}
}
app
.
Metadata
=
map
[
string
]
interface
{}{
"layers"
:
"many"
,
"explicable"
:
false
,
"whatever-values"
:
19.99
,
}
app
.
Run
(
os
.
Args
)
}
func
wopAction
(
c
*
cli
.
Context
)
error
{
fmt
.
Fprintf
(
c
.
App
.
Writer
,
":wave: over here, eh
\n
"
)
return
nil
}
```
## Contribution Guidelines
Feel free to put up a pull request to fix a bug or maybe add a feature. I will
give it a code review and make sure that it does not break backwards
compatibility. If I or any other collaborators agree that it is in line with
the vision of the project, we will work with you to get the code into
a mergeable state and merge it into the master branch.
If you have contributed something significant to the project, we will most
likely add you as a collaborator. As a collaborator you are given the ability
to merge others pull requests. It is very important that new code does not
break existing code, so be careful about what code you do choose to merge.
If you feel like you have contributed to the project but have not yet been
added as a collaborator, we probably forgot to add you, please open an issue.
shim/vendor/github.com/urfave/cli/app.go
0 → 100644
浏览文件 @
15f17876
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
}
shim/vendor/github.com/urfave/cli/appveyor.yml
0 → 100644
浏览文件 @
15f17876
version
:
"
{build}"
os
:
Windows Server
2016
image
:
Visual Studio
2017
clone_folder
:
c:\gopath\src\github.com\urfave\cli
environment
:
GOPATH
:
C:\gopath
GOVERSION
:
1.8.x
PYTHON
:
C:\Python36-x64
PYTHON_VERSION
:
3.6.x
PYTHON_ARCH
:
64
install
:
-
set PATH=%GOPATH%\bin;C:\go\bin;%PATH%
-
go version
-
go env
-
go get github.com/urfave/gfmrun/...
-
go get -v -t ./...
build_script
:
-
python runtests vet
-
python runtests test
-
python runtests gfmrun
shim/vendor/github.com/urfave/cli/category.go
0 → 100644
浏览文件 @
15f17876
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
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
}
shim/vendor/github.com/urfave/cli/cli.go
0 → 100644
浏览文件 @
15f17876
// 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
shim/vendor/github.com/urfave/cli/command.go
0 → 100644
浏览文件 @
15f17876
package
cli
import
(
"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
// 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
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
:=
flagSet
(
c
.
Name
,
c
.
Flags
)
if
err
!=
nil
{
return
err
}
set
.
SetOutput
(
ioutil
.
Discard
)
if
c
.
SkipFlagParsing
{
err
=
set
.
Parse
(
append
([]
string
{
"--"
},
ctx
.
Args
()
.
Tail
()
...
))
}
else
if
!
c
.
SkipArgReorder
{
firstFlagIndex
:=
-
1
terminatorIndex
:=
-
1
for
index
,
arg
:=
range
ctx
.
Args
()
{
if
arg
==
"--"
{
terminatorIndex
=
index
break
}
else
if
arg
==
"-"
{
// Do nothing. A dash alone is not really a flag.
continue
}
else
if
strings
.
HasPrefix
(
arg
,
"-"
)
&&
firstFlagIndex
==
-
1
{
firstFlagIndex
=
index
}
}
if
firstFlagIndex
>
-
1
{
args
:=
ctx
.
Args
()
regularArgs
:=
make
([]
string
,
len
(
args
[
1
:
firstFlagIndex
]))
copy
(
regularArgs
,
args
[
1
:
firstFlagIndex
])
var
flagArgs
[]
string
if
terminatorIndex
>
-
1
{
flagArgs
=
args
[
firstFlagIndex
:
terminatorIndex
]
regularArgs
=
append
(
regularArgs
,
args
[
terminatorIndex
:
]
...
)
}
else
{
flagArgs
=
args
[
firstFlagIndex
:
]
}
err
=
set
.
Parse
(
append
(
flagArgs
,
regularArgs
...
))
}
else
{
err
=
set
.
Parse
(
ctx
.
Args
()
.
Tail
())
}
}
else
{
err
=
set
.
Parse
(
ctx
.
Args
()
.
Tail
())
}
nerr
:=
normalizeFlags
(
c
.
Flags
,
set
)
if
nerr
!=
nil
{
fmt
.
Fprintln
(
ctx
.
App
.
Writer
,
nerr
)
fmt
.
Fprintln
(
ctx
.
App
.
Writer
)
ShowCommandHelp
(
ctx
,
c
.
Name
)
return
nerr
}
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
}
// 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
)
}
shim/vendor/github.com/urfave/cli/context.go
0 → 100644
浏览文件 @
15f17876
package
cli
import
(
"errors"
"flag"
"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
()
}
envVarValue
:=
val
.
FieldByName
(
"EnvVar"
)
if
!
envVarValue
.
IsValid
()
{
return
}
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
}
shim/vendor/github.com/urfave/cli/errors.go
0 → 100644
浏览文件 @
15f17876
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
}
shim/vendor/github.com/urfave/cli/flag-types.json
0 → 100644
浏览文件 @
15f17876
[
{
"name"
:
"Bool"
,
"type"
:
"bool"
,
"value"
:
false
,
"context_default"
:
"false"
,
"parser"
:
"strconv.ParseBool(f.Value.String())"
},
{
"name"
:
"BoolT"
,
"type"
:
"bool"
,
"value"
:
false
,
"doctail"
:
" that is true by default"
,
"context_default"
:
"false"
,
"parser"
:
"strconv.ParseBool(f.Value.String())"
},
{
"name"
:
"Duration"
,
"type"
:
"time.Duration"
,
"doctail"
:
" (see https://golang.org/pkg/time/#ParseDuration)"
,
"context_default"
:
"0"
,
"parser"
:
"time.ParseDuration(f.Value.String())"
},
{
"name"
:
"Float64"
,
"type"
:
"float64"
,
"context_default"
:
"0"
,
"parser"
:
"strconv.ParseFloat(f.Value.String(), 64)"
},
{
"name"
:
"Generic"
,
"type"
:
"Generic"
,
"dest"
:
false
,
"context_default"
:
"nil"
,
"context_type"
:
"interface{}"
},
{
"name"
:
"Int64"
,
"type"
:
"int64"
,
"context_default"
:
"0"
,
"parser"
:
"strconv.ParseInt(f.Value.String(), 0, 64)"
},
{
"name"
:
"Int"
,
"type"
:
"int"
,
"context_default"
:
"0"
,
"parser"
:
"strconv.ParseInt(f.Value.String(), 0, 64)"
,
"parser_cast"
:
"int(parsed)"
},
{
"name"
:
"IntSlice"
,
"type"
:
"*IntSlice"
,
"dest"
:
false
,
"context_default"
:
"nil"
,
"context_type"
:
"[]int"
,
"parser"
:
"(f.Value.(*IntSlice)).Value(), error(nil)"
},
{
"name"
:
"Int64Slice"
,
"type"
:
"*Int64Slice"
,
"dest"
:
false
,
"context_default"
:
"nil"
,
"context_type"
:
"[]int64"
,
"parser"
:
"(f.Value.(*Int64Slice)).Value(), error(nil)"
},
{
"name"
:
"String"
,
"type"
:
"string"
,
"context_default"
:
"
\"\"
"
,
"parser"
:
"f.Value.String(), error(nil)"
},
{
"name"
:
"StringSlice"
,
"type"
:
"*StringSlice"
,
"dest"
:
false
,
"context_default"
:
"nil"
,
"context_type"
:
"[]string"
,
"parser"
:
"(f.Value.(*StringSlice)).Value(), error(nil)"
},
{
"name"
:
"Uint64"
,
"type"
:
"uint64"
,
"context_default"
:
"0"
,
"parser"
:
"strconv.ParseUint(f.Value.String(), 0, 64)"
},
{
"name"
:
"Uint"
,
"type"
:
"uint"
,
"context_default"
:
"0"
,
"parser"
:
"strconv.ParseUint(f.Value.String(), 0, 64)"
,
"parser_cast"
:
"uint(parsed)"
}
]
shim/vendor/github.com/urfave/cli/flag.go
0 → 100644
浏览文件 @
15f17876
package
cli
import
(
"flag"
"fmt"
"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
// 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
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
envVar
);
ok
{
if
err
:=
val
.
Set
(
envVal
);
err
!=
nil
{
return
fmt
.
Errorf
(
"could not parse %s as value for flag %s: %s"
,
envVal
,
f
.
Name
,
err
)
}
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
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
)
}
}
f
.
Value
=
newVal
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
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
)
}
}
f
.
Value
=
newVal
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
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
)
}
}
f
.
Value
=
newVal
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
envVar
);
ok
{
if
envVal
==
""
{
val
=
false
break
}
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
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
envVar
);
ok
{
if
envVal
==
""
{
val
=
false
break
}
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
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
envVar
);
ok
{
f
.
Value
=
envVal
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
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
)
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
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
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
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
)
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
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
)
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
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
break
}
}
}
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
f
.
EnvVar
!=
""
{
for
_
,
envVar
:=
range
strings
.
Split
(
f
.
EnvVar
,
","
)
{
envVar
=
strings
.
TrimSpace
(
envVar
)
if
envVal
,
ok
:=
syscall
.
Getenv
(
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
)
break
}
}
}
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
=
fmt
.
Sprintf
(
" [%s%s%s]"
,
prefix
,
strings
.
Join
(
strings
.
Split
(
envVar
,
","
),
sep
),
suffix
)
}
return
str
+
envText
}
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
FlagEnvHinter
(
fv
.
FieldByName
(
"EnvVar"
)
.
String
(),
stringifyIntSliceFlag
(
f
.
(
IntSliceFlag
)))
case
Int64SliceFlag
:
return
FlagEnvHinter
(
fv
.
FieldByName
(
"EnvVar"
)
.
String
(),
stringifyInt64SliceFlag
(
f
.
(
Int64SliceFlag
)))
case
StringSliceFlag
:
return
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
(
fmt
.
Sprintf
(
"%s%s"
,
usage
,
defaultValueString
))
return
FlagEnvHinter
(
fv
.
FieldByName
(
"EnvVar"
)
.
String
(),
fmt
.
Sprintf
(
"%s
\t
%s"
,
FlagNamePrefixer
(
fv
.
FieldByName
(
"Name"
)
.
String
(),
placeholder
),
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
,
fmt
.
Sprintf
(
"%d"
,
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
,
fmt
.
Sprintf
(
"%d"
,
i
))
}
}
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
,
fmt
.
Sprintf
(
"%q"
,
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
(
fmt
.
Sprintf
(
"%s%s"
,
usage
,
defaultVal
))
return
fmt
.
Sprintf
(
"%s
\t
%s"
,
FlagNamePrefixer
(
name
,
placeholder
),
usageWithDefault
)
}
shim/vendor/github.com/urfave/cli/flag_generated.go
0 → 100644
浏览文件 @
15f17876
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
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
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
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
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
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
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
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
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
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
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
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
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
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
}
shim/vendor/github.com/urfave/cli/funcs.go
0 → 100644
浏览文件 @
15f17876
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
shim/vendor/github.com/urfave/cli/generate-flag-types
0 → 100644
浏览文件 @
15f17876
#
!/usr/bin/env python
"""
The flag types that ship with the cli library have many things in common, and
so we can take advantage of the `go generate` command to create much of the
source code from a list of definitions. These definitions attempt to cover
the parts that vary between flag types, and should evolve as needed.
An example of the minimum definition needed is:
{
"
name
": "
SomeType
",
"
type
": "
sometype
",
"
context_default
": "
nil
"
}
In this example, the code generated for the `cli` package will include a type
named `SomeTypeFlag` that is expected to wrap a value of type `sometype`.
Fetching values by name via `*cli.Context` will default to a value of `nil`.
A more complete, albeit somewhat redundant, example showing all available
definition keys is:
{
"
name
": "
VeryMuchType
",
"
type
": "
*
VeryMuchType
",
"
value
": true,
"
dest
": false,
"
doctail
": "
which
really
only
wraps
a
[]
float64
,
oh
well
!",
"context_type"
:
"[]float64"
,
"context_default"
:
"nil"
,
"parser"
:
"parseVeryMuchType(f.Value.String())"
,
"parser_cast"
:
"[]float64(parsed)"
}
The
meaning
of
each
field
is
as
follows
:
name
(
string
)
-
The
type
"name"
,
which
will
be
suffixed
with
`
Flag
`
when
generating
the
type
definition
for
`
cli
`
and
the
wrapper
type
for
`
altsrc
`
type
(
string
)
-
The
type
that
the
generated
`
Flag
`
type
for
`
cli
`
is
expected
to
"contain"
as
its
`.
Value
`
member
value
(
bool
)
-
Should
the
generated
`
cli
`
type
have
a
`
Value
`
member
?
dest
(
bool
)
-
Should
the
generated
`
cli
`
type
support
a
destination
pointer
?
doctail
(
string
)
-
Additional
docs
for
the
`
cli
`
flag
type
comment
context_type
(
string
)
-
The
literal
type
used
in
the
`*
cli
.
Context
`
reader
func
signature
context_default
(
string
)
-
The
literal
value
used
as
the
default
by
the
`*
cli
.
Context
`
reader
funcs
when
no
value
is
present
parser
(
string
)
-
Literal
code
used
to
parse
the
flag
`
f
`,
expected
to
have
a
return
signature
of
(
value
,
error
)
parser_cast
(
string
)
-
Literal
code
used
to
cast
the
`
parsed
`
value
returned
from
the
`
parser
`
code
"""
from __future__ import print_function, unicode_literals
import argparse
import json
import os
import subprocess
import sys
import tempfile
import textwrap
class _FancyFormatter(argparse.ArgumentDefaultsHelpFormatter,
argparse.RawDescriptionHelpFormatter):
pass
def main(sysargs=sys.argv[:]):
parser = argparse.ArgumentParser(
description='Generate flag type code!',
formatter_class=_FancyFormatter)
parser.add_argument(
'package',
type=str, default='cli', choices=_WRITEFUNCS.keys(),
help='Package for which flag types will be generated'
)
parser.add_argument(
'-i', '--in-json',
type=argparse.FileType('r'),
default=sys.stdin,
help='Input JSON file which defines each type to be generated'
)
parser.add_argument(
'-o', '--out-go',
type=argparse.FileType('w'),
default=sys.stdout,
help='Output file/stream to which generated source will be written'
)
parser.epilog = __doc__
args = parser.parse_args(sysargs[1:])
_generate_flag_types(_WRITEFUNCS[args.package], args.out_go, args.in_json)
return 0
def _generate_flag_types(writefunc, output_go, input_json):
types = json.load(input_json)
tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False)
writefunc(tmp, types)
tmp.close()
new_content = subprocess.check_output(
['goimports', tmp.name]
).decode('utf-8')
print(new_content, file=output_go, end='')
output_go.flush()
os.remove(tmp.name)
def _set_typedef_defaults(typedef):
typedef.setdefault('doctail', '')
typedef.setdefault('context_type', typedef['type'])
typedef.setdefault('dest', True)
typedef.setdefault('value', True)
typedef.setdefault('parser', 'f.Value, error(nil)')
typedef.setdefault('parser_cast', 'parsed')
def _write_cli_flag_types(outfile, types):
_fwrite(outfile, """
\
package
cli
//
WARNING
:
This
file
is
generated
!
""")
for typedef in types:
_set_typedef_defaults(typedef)
_fwrite(outfile, """
\
//
{
name
}
Flag
is
a
flag
with
type
{
type
}{
doctail
}
type
{
name
}
Flag
struct
{{
Name
string
Usage
string
EnvVar
string
Hidden
bool
""".format(**typedef))
if typedef['value']:
_fwrite(outfile, """
\
Value
{
type
}
""".format(**typedef))
if typedef['dest']:
_fwrite(outfile, """
\
Destination
*{
type
}
""".format(**typedef))
_fwrite(outfile, "
\
n
}\
n
\
n
")
_fwrite(outfile, """
\
//
String
returns
a
readable
representation
of
this
value
//
(
for
usage
defaults
)
func
(
f
{
name
}
Flag
)
String
()
string
{{
return
FlagStringer
(
f
)
}}
//
GetName
returns
the
name
of
the
flag
func
(
f
{
name
}
Flag
)
GetName
()
string
{{
return
f
.
Name
}}
//
{
name
}
looks
up
the
value
of
a
local
{
name
}
Flag
,
returns
//
{
context_default
}
if
not
found
func
(
c
*
Context
)
{
name
}(
name
string
)
{
context_type
}
{{
return
lookup
{
name
}(
name
,
c
.
flagSet
)
}}
//
Global
{
name
}
looks
up
the
value
of
a
global
{
name
}
Flag
,
returns
//
{
context_default
}
if
not
found
func
(
c
*
Context
)
Global
{
name
}(
name
string
)
{
context_type
}
{{
if
fs
:=
lookupGlobalFlagSet
(
name
,
c
);
fs
!= nil {{
return
lookup
{
name
}(
name
,
fs
)
}}
return
{
context_default
}
}}
func
lookup
{
name
}(
name
string
,
set
*
flag
.
FlagSet
)
{
context_type
}
{{
f
:=
set
.
Lookup
(
name
)
if
f
!= nil {{
parsed
,
err
:=
{
parser
}
if
err
!= nil {{
return
{
context_default
}
}}
return
{
parser_cast
}
}}
return
{
context_default
}
}}
""".format(**typedef))
def _write_altsrc_flag_types(outfile, types):
_fwrite(outfile, """
\
package
altsrc
import
(
"gopkg.in/urfave/cli.v1"
)
//
WARNING
:
This
file
is
generated
!
""")
for typedef in types:
_set_typedef_defaults(typedef)
_fwrite(outfile, """
\
//
{
name
}
Flag
is
the
flag
type
that
wraps
cli
.{
name
}
Flag
to
allow
//
for
other
values
to
be
specified
type
{
name
}
Flag
struct
{{
cli
.{
name
}
Flag
set
*
flag
.
FlagSet
}}
//
New
{
name
}
Flag
creates
a
new
{
name
}
Flag
func
New
{
name
}
Flag
(
fl
cli
.{
name
}
Flag
)
*{
name
}
Flag
{{
return
&{
name
}
Flag
{{{
name
}
Flag
:
fl
,
set
:
nil
}}
}}
//
Apply
saves
the
flagSet
for
later
usage
calls
,
then
calls
the
//
wrapped
{
name
}
Flag
.
Apply
func
(
f
*{
name
}
Flag
)
Apply
(
set
*
flag
.
FlagSet
)
{{
f
.
set
=
set
f
.{
name
}
Flag
.
Apply
(
set
)
}}
//
ApplyWithError
saves
the
flagSet
for
later
usage
calls
,
then
calls
the
//
wrapped
{
name
}
Flag
.
ApplyWithError
func
(
f
*{
name
}
Flag
)
ApplyWithError
(
set
*
flag
.
FlagSet
)
error
{{
f
.
set
=
set
return
f
.{
name
}
Flag
.
ApplyWithError
(
set
)
}}
""".format(**typedef))
def _fwrite(outfile, text):
print(textwrap.dedent(text), end='', file=outfile)
_WRITEFUNCS = {
'cli': _write_cli_flag_types,
'altsrc': _write_altsrc_flag_types
}
if __name__ == '__main__':
sys.exit(main())
shim/vendor/github.com/urfave/cli/help.go
0 → 100644
浏览文件 @
15f17876
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
}
for
_
,
name
:=
range
command
.
Names
()
{
fmt
.
Fprintln
(
c
.
App
.
Writer
,
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
}
shim/vendor/github.com/urfave/cli/runtests
0 → 100644
浏览文件 @
15f17876
#!/usr/bin/env python
from
__future__
import
print_function
import
argparse
import
os
import
sys
import
tempfile
from
subprocess
import
check_call
,
check_output
PACKAGE_NAME
=
os
.
environ
.
get
(
'CLI_PACKAGE_NAME'
,
'github.com/urfave/cli'
)
def
main
(
sysargs
=
sys
.
argv
[:]):
targets
=
{
'vet'
:
_vet
,
'test'
:
_test
,
'gfmrun'
:
_gfmrun
,
'toc'
:
_toc
,
'gen'
:
_gen
,
}
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
'target'
,
nargs
=
'?'
,
choices
=
tuple
(
targets
.
keys
()),
default
=
'test'
)
args
=
parser
.
parse_args
(
sysargs
[
1
:])
targets
[
args
.
target
]()
return
0
def
_test
():
if
check_output
(
'go version'
.
split
()).
split
()[
2
]
<
'go1.2'
:
_run
(
'go test -v .'
)
return
coverprofiles
=
[]
for
subpackage
in
[
''
,
'altsrc'
]:
coverprofile
=
'cli.coverprofile'
if
subpackage
!=
''
:
coverprofile
=
'{}.coverprofile'
.
format
(
subpackage
)
coverprofiles
.
append
(
coverprofile
)
_run
(
'go test -v'
.
split
()
+
[
'-coverprofile={}'
.
format
(
coverprofile
),
(
'{}/{}'
.
format
(
PACKAGE_NAME
,
subpackage
)).
rstrip
(
'/'
)
])
combined_name
=
_combine_coverprofiles
(
coverprofiles
)
_run
(
'go tool cover -func={}'
.
format
(
combined_name
))
os
.
remove
(
combined_name
)
def
_gfmrun
():
go_version
=
check_output
(
'go version'
.
split
()).
split
()[
2
]
if
go_version
<
'go1.3'
:
print
(
'runtests: skip on {}'
.
format
(
go_version
),
file
=
sys
.
stderr
)
return
_run
([
'gfmrun'
,
'-c'
,
str
(
_gfmrun_count
()),
'-s'
,
'README.md'
])
def
_vet
():
_run
(
'go vet ./...'
)
def
_toc
():
_run
(
'node_modules/.bin/markdown-toc -i README.md'
)
_run
(
'git diff --exit-code'
)
def
_gen
():
go_version
=
check_output
(
'go version'
.
split
()).
split
()[
2
]
if
go_version
<
'go1.5'
:
print
(
'runtests: skip on {}'
.
format
(
go_version
),
file
=
sys
.
stderr
)
return
_run
(
'go generate ./...'
)
_run
(
'git diff --exit-code'
)
def
_run
(
command
):
if
hasattr
(
command
,
'split'
):
command
=
command
.
split
()
print
(
'runtests: {}'
.
format
(
' '
.
join
(
command
)),
file
=
sys
.
stderr
)
check_call
(
command
)
def
_gfmrun_count
():
with
open
(
'README.md'
)
as
infile
:
lines
=
infile
.
read
().
splitlines
()
return
len
(
filter
(
_is_go_runnable
,
lines
))
def
_is_go_runnable
(
line
):
return
line
.
startswith
(
'package main'
)
def
_combine_coverprofiles
(
coverprofiles
):
combined
=
tempfile
.
NamedTemporaryFile
(
suffix
=
'.coverprofile'
,
delete
=
False
)
combined
.
write
(
'mode: set
\n
'
)
for
coverprofile
in
coverprofiles
:
with
open
(
coverprofile
,
'r'
)
as
infile
:
for
line
in
infile
.
readlines
():
if
not
line
.
startswith
(
'mode: '
):
combined
.
write
(
line
)
combined
.
flush
()
name
=
combined
.
name
combined
.
close
()
return
name
if
__name__
==
'__main__'
:
sys
.
exit
(
main
())
shim/vendor/modules.txt
浏览文件 @
15f17876
...
...
@@ -47,6 +47,7 @@ github.com/containerd/containerd/api/types/task
github.com/containerd/containerd/archive
github.com/containerd/containerd/archive/compression
github.com/containerd/containerd/cio
github.com/containerd/containerd/cmd/ctr/commands
github.com/containerd/containerd/containers
github.com/containerd/containerd/content
github.com/containerd/containerd/content/proxy
...
...
@@ -189,6 +190,8 @@ github.com/stretchr/testify/assert
github.com/syndtr/gocapability/capability
# github.com/ugorji/go/codec v1.1.7
github.com/ugorji/go/codec
# github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5
github.com/urfave/cli
# go.opencensus.io v0.22.0
go.opencensus.io
go.opencensus.io/internal
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录