diff --git a/Makefile b/Makefile index db028a02b..c35fab60d 100644 --- a/Makefile +++ b/Makefile @@ -10,11 +10,19 @@ GOARCH=amd64 ifneq ($(GOOS),linux) CROSS=-e GOOS=$(GOOS) -e GOARCH=$(GOARCH) endif +ifeq ($(GOOS),darwin) +default: bin/infrakit-instance-hyperkit +endif bin/moby: $(MOBY_DEPS) | bin tar cf - vendor src/initrd src/pad4 -C src/cmd/moby . | docker run --rm --net=none --log-driver=none -i $(CROSS) $(GO_COMPILE) --package github.com/docker/moby -o $@ | tar xf - touch $@ +MOBY_DEPS=$(wildcard src/cmd/infrakit-instance-hyperkit/*.go) +bin/infrakit-instance-hyperkit: $(INFRAKIT_DEPS) | bin + tar cf - vendor -C src/cmd/infrakit-instance-hyperkit . | docker run --rm --net=none --log-driver=none -i $(CROSS) $(GO_COMPILE) --package github.com/docker/moby -o $@ | tar xf - + touch $@ + moby-initrd.img: bin/moby moby.yaml bin/moby build moby.yaml diff --git a/tools/infrakit.hyperkit/README.md b/docs/infrakit.md similarity index 85% rename from tools/infrakit.hyperkit/README.md rename to docs/infrakit.md index ab9a02724..8ed47c469 100644 --- a/tools/infrakit.hyperkit/README.md +++ b/docs/infrakit.md @@ -1,8 +1,9 @@ ## Hyperkit/Moby Infrakit plugin -This is a Hyper/Kit Moby instance plugin for infrakit. The instance -plugin is capable to start/manage several hyperkit instances with with -different configurations and Moby configurations. +There is a HyperKit Moby instance plugin for infrakit in +`src/cmd/infrakit-instance-hyperkit`. The instance plugin is capable +to start/manage several hyperkit instances with with different +configurations and Moby configurations. The plugin keeps state in a local directory (default `.infrakit/hyperkit-vms`) where each instance keeps some state in a @@ -12,9 +13,9 @@ command line using the `--vm-dir` option. ## Building ```sh -make +make bin/infrakit-instance-hyperkit ``` -(you need a working docker installation, such as Docker for Mac) + ## Quickstart @@ -31,7 +32,7 @@ infrakit-flavor-vanilla Then start the hyperkit plugin: ```shell -./build/infrakit-instance-hyperkit +./bin/infrakit-instance-hyperkit ``` Next, you can commit a new configuration. There is a sample infrakit config file in `hyperkit.json`. It assumes that you have a default moby build in the top-level directory. The `Moby` property needs to be of the form `/` and assumes that the kernel and initrd images are called `-bzImage` and `-initrd.img` respectively (this is the convention used by the `moby` tool). diff --git a/tools/infrakit.hyperkit/hyperkit.json b/src/cmd/infrakit-instance-hyperkit/hyperkit.json similarity index 100% rename from tools/infrakit.hyperkit/hyperkit.json rename to src/cmd/infrakit-instance-hyperkit/hyperkit.json diff --git a/tools/infrakit.hyperkit/cmd/instance.go b/src/cmd/infrakit-instance-hyperkit/instance.go similarity index 100% rename from tools/infrakit.hyperkit/cmd/instance.go rename to src/cmd/infrakit-instance-hyperkit/instance.go diff --git a/tools/infrakit.hyperkit/cmd/main.go b/src/cmd/infrakit-instance-hyperkit/main.go similarity index 100% rename from tools/infrakit.hyperkit/cmd/main.go rename to src/cmd/infrakit-instance-hyperkit/main.go diff --git a/tools/infrakit.hyperkit/.gitignore b/tools/infrakit.hyperkit/.gitignore deleted file mode 100644 index 2cbda4717..000000000 --- a/tools/infrakit.hyperkit/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -vmlib/ -vms/ diff --git a/tools/infrakit.hyperkit/Dockerfile.build b/tools/infrakit.hyperkit/Dockerfile.build deleted file mode 100644 index 0ea8b29ab..000000000 --- a/tools/infrakit.hyperkit/Dockerfile.build +++ /dev/null @@ -1,10 +0,0 @@ -FROM mobylinux/go-compile:3afebc59c5cde31024493c3f91e6102d584a30b9@sha256:e0786141ea7df8ba5735b63f2a24b4ade9eae5a02b0e04c4fca33b425ec69b0a - -ENV GOPATH=/go -ENV PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -# The project sources -VOLUME ["/go/src/github.com/docker/infrakit.hyperkit"] -WORKDIR /go/src/github.com/docker/infrakit.hyperkit - -ENTRYPOINT ["make"] diff --git a/tools/infrakit.hyperkit/Makefile b/tools/infrakit.hyperkit/Makefile deleted file mode 100644 index b9d4a04d7..000000000 --- a/tools/infrakit.hyperkit/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -.PHONY: build-in-container build-local -DEPS:=$(wildcard cmd/*.go) Dockerfile.build Makefile - -# Version/Revision information -VERSION ?= $(shell git describe --match 'v[0-9]*' --dirty='.m' --always || echo "Unknown") -REVISION ?= $(shell git rev-list -1 HEAD || echo "Unknown") - -build-in-container: $(DEPS) clean - @echo "+ $@" - @docker build -t infrakit-hyperkit-build -f ./Dockerfile.build . - @docker run --rm \ - -v ${CURDIR}:/go/src/github.com/docker/infrakit.hyperkit \ - infrakit-hyperkit-build build-local VERSION=${VERSION} REVISION=${REVISION} - -build-local: build/infrakit-instance-hyperkit - -build/infrakit-instance-hyperkit: $(DEPS) - @echo "+ $@" - GOOS=darwin GOARCH=amd64 \ - go build -o $@ \ - --ldflags '-extldflags "-fno-PIC" -X github.com/docker/diagkit/pkg/gather.Version=$(VERSION) -X github.com/docker/diagkit/pkg/gather.Revision=$(REVISION)' \ - cmd/main.go cmd/instance.go -clean: - rm -rf build - -fmt: - @echo "+ $@" - @gofmt -s -l . 2>&1 | grep -v ^vendor/ | xargs gofmt -s -l -w - -lint: - @echo "+ $@" - $(if $(shell which golint || echo ''), , \ - $(error Please install golint)) - @test -z "$$(golint ./... 2>&1 | grep -v ^vendor/ | grep -v mock/ | tee /dev/stderr)" - -# this will blow away the vendored code and update it to latest -.PHONY: revendor revendor-local -revendor: - @echo "+ $@" - @rm -rf vendor.conf vendor - @docker build -t infrakit-hyperkit-build -f ./Dockerfile.build . - @docker run --rm \ - -v ${CURDIR}:/go/src/github.com/docker/infrakit.hyperkit \ - infrakit-hyperkit-build revendor-local VERSION=${VERSION} REVISION=${REVISION} - -revendor-local: - @echo "+ $@" - @go get github.com/LK4D4/vndr - @vndr init diff --git a/tools/infrakit.hyperkit/vendor.conf b/tools/infrakit.hyperkit/vendor.conf deleted file mode 100644 index 2537f46d6..000000000 --- a/tools/infrakit.hyperkit/vendor.conf +++ /dev/null @@ -1,20 +0,0 @@ -github.com/Masterminds/semver 312afcd0e81e5cf81fdc3cfd0e8504ae031521c8 -github.com/Masterminds/sprig 01a849f546a584d7b29bfee253e7db0aed44f7ba -github.com/Sirupsen/logrus 10f801ebc38b33738c9d17d50860f484a0988ff5 -github.com/aokoli/goutils 9c37978a95bd5c709a15883b6242714ea6709e64 -github.com/armon/go-radix 4239b77079c7b5d1243b7b4736304ce8ddb6f0f2 -github.com/docker/hyperkit 874e68dbb7a2a7a2794dbd8648c2f4be1e7a8bb3 -github.com/docker/infrakit 208d114478ed94ee9015083e13946ca1caaad790 -github.com/gorilla/context 08b5f424b9271eedf6f9f0ce86cb9396ed337a42 -github.com/gorilla/mux 599cba5e7b6137d46ddf58fb1765f5d928e69604 -github.com/gorilla/rpc 22c016f3df3febe0c1f6727598b6389507e03a18 -github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 -github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d -github.com/mitchellh/go-ps 4fdf99ab29366514c69ccccddab5dc58b8d84062 -github.com/rneugeba/iso9660wrap 9c7eaf5ac74b2416be8b7b8d1f35b9af44a6e4fa -github.com/satori/go.uuid b061729afc07e77a8aa4fad0a2fd840958f1942a -github.com/spf13/cobra 7be4beda01ec05d0b93d80b3facd2b6f44080d94 -github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7 -golang.org/x/crypto 459e26527287adbc2adcc5d0d49abff9a5f315a7 -golang.org/x/sys 99f16d856c9836c42d24e7ab64ea72916925fa97 -gopkg.in/tylerb/graceful.v1 4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb diff --git a/tools/infrakit.hyperkit/vendor/github.com/Masterminds/sprig b/tools/infrakit.hyperkit/vendor/github.com/Masterminds/sprig deleted file mode 160000 index 2d2df7bd8..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/Masterminds/sprig +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2d2df7bd8bda53b5a55ed04422173cedd50500ea diff --git a/tools/infrakit.hyperkit/vendor/github.com/Sirupsen/logrus b/tools/infrakit.hyperkit/vendor/github.com/Sirupsen/logrus deleted file mode 160000 index 7f4b1adc7..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/Sirupsen/logrus +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7f4b1adc791766938c29457bed0703fb9134421a diff --git a/tools/infrakit.hyperkit/vendor/github.com/aokoli/goutils b/tools/infrakit.hyperkit/vendor/github.com/aokoli/goutils deleted file mode 160000 index 9c37978a9..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/aokoli/goutils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9c37978a95bd5c709a15883b6242714ea6709e64 diff --git a/tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/README.md b/tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/README.md deleted file mode 100644 index 17c44ae11..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/README.md +++ /dev/null @@ -1,115 +0,0 @@ -## [HyperKit](http://github.com/docker/hyperkit) - -![Build Status OSX](https://circleci.com/gh/docker/hyperkit.svg?style=shield&circle-token=cf8379b302eab2bbf33821cafe164dbefb71982d) - -*HyperKit* is a toolkit for embedding hypervisor capabilities in your application. It includes a complete hypervisor, based on [xhyve](https://github.com/mist64/xhyve)/[bhyve](http://bhyve.org), which is optimized for lightweight virtual machines and container deployment. It is designed to be interfaced with higher-level components such as the [VPNKit](https://github.com/docker/vpnkit) and [DataKit](https://github.com/docker/datakit). - -HyperKit currently only supports Mac OS X using the [Hypervisor.framework](https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/Hypervisor/index.html). It is a core component of Docker For Mac. - - -## Requirements - -* OS X 10.10.3 Yosemite or later -* a 2010 or later Mac (i.e. a CPU that supports EPT) - -## Reporting Bugs - -If you are using a version of Hyperkit which is embedded into a higher level application (e.g. [Docker for Mac](https://github.com/docker/for-mac)) then please report any issues against that higher level application in the first instance. That way the relevant team can triage and determine if the issue lies in Hyperkit and assign as necessary. - -If you are using Hyperkit directly then please report issues against this repository. - -## Usage - - $ hyperkit -h - -## Building - - $ git clone https://github.com/docker/hyperkit - $ cd hyperkit - $ make - -The resulting binary will be in `build/hyperkit` - -To enable qcow support in the block backend an OCaml [OPAM](https://opam.ocaml.org) development -environment is required with the qcow module available. A -suitable environment can be setup by installing `opam` and `libev` -via `brew` and using `opam` to install the appropriate libraries: - - $ brew install opam libev - $ opam init - $ eval `opam config env` - $ opam install uri qcow.0.8.1 mirage-block-unix.2.6.0 conf-libev logs fmt mirage-unix - -Notes: - -- `opam config env` must be evaluated each time prior to building - hyperkit so the build will find the ocaml environment. -- Any previous pin of `mirage-block-unix` or `qcow` - should be removed with the commands: - - ```sh - $ opam update - $ opam pin remove mirage-block-unix - $ opam pin remove qcow - ``` - -## Tracing - -HyperKit defines a number of static DTrace probes to simplify investigation of -performance problems. To list the probes supported by your version of HyperKit, -type the following command while HyperKit VM is running: - - $ sudo dtrace -l -P 'hyperkit$target' -p $(pgrep hyperkit) - -Refer to scripts in dtrace/ directory for examples of possible usage and -available probes. - -### Relationship to xhyve and bhyve - -HyperKit includes a hypervisor derived from [xhyve](http://www.xhyve.org), which in turn -was derived from [bhyve](http://www.bhyve.org). See the [original xhyve -README](README.xhyve.md) which incorporates the bhyve README. - -We try to avoid deviating from these upstreams unnecessarily in order -to more easily share code, for example the various device -models/emulations should be easily shareable. - -### Reporting security issues - -The maintainers take security seriously. If you discover a security issue, -please bring it to their attention right away! - -Please **DO NOT** file a public issue, instead send your report privately to -[security@docker.com](mailto:security@docker.com). - -Security reports are greatly appreciated and we will publicly thank you for it. -We also like to send gifts—if you're into Docker schwag, make sure to let -us know. We currently do not offer a paid security bounty program, but are not -ruling it out in the future. - - -## Copyright and license - -Copyright the authors and contributors. See individual source files -for details. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. diff --git a/tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/README.xhyve.md b/tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/README.xhyve.md deleted file mode 100644 index 760746ef3..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/README.xhyve.md +++ /dev/null @@ -1,224 +0,0 @@ -# [xhyve.org](http://www.xhyve.org) - -![](./xhyve_logo.png) - - -About ------ - -The *xhyve hypervisor* is a port of [bhyve](http://www.bhyve.org) to OS X. It is built on top of [Hypervisor.framework](https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/Hypervisor/index.html) in OS X 10.10 Yosemite and higher, runs entirely in userspace, and has no other dependencies. It can run FreeBSD and vanilla Linux distributions and may gain support for other guest operating systems in the future. - -License: BSD - -Introduction: [http://www.pagetable.com/?p=831](http://www.pagetable.com/?p=831) - -Requirements ------------- - -* OS X 10.10.3 Yosemite or later -* a 2010 or later Mac (i.e. a CPU that supports EPT) - -Installation ------------- - -If you have homebrew, then simply: - - $ brew update - $ brew install --HEAD xhyve - -The `--HEAD` in the brew command ensures that you always get the latest changes, even if the homebrew database is not yet updated. If for any reason you don't want that simply do `brew install xhyve` . - -if not then: - -Building --------- - $ git clone https://github.com/mist64/xhyve - $ cd xhyve - $ make - -The resulting binary will be in build/xhyve - -Usage ------ - - $ xhyve -h - - -What is bhyve? --------------- - -bhyve is the FreeBSD hypervisor, roughly analogous to KVM + QEMU on Linux. It has a focus on simplicity and being legacy free. - -It exposes the following peripherals to virtual machines: - - - Local x(2)APIC - - IO-APIC - - 8259A PIC - - 8253/8254 PIT - - HPET - - PM Timer - - RTC - - PCI - - host bridge - - passthrough - - UART - - AHCI (i.e. HDD and CD) - - VirtIO block device - - VirtIO networking - - VirtIO RNG - -Notably absent are sound, USB, HID and any kind of graphics support. With a focus on server virtualization this is not strictly a requirement. bhyve may gain desktop virtualization capabilities in the future but this doesn't seem to be a priority. - -Unlike QEMU, bhyve also currently lacks any kind of guest-side firmware (QEMU uses the GPL3 [SeaBIOS](http://www.seabios.org)), but aims to provide a compatible [OVMF EFI](http://www.linux-kvm.org/page/OVMF) in the near future. It does however provide ACPI, SMBIOS and MP Tables. - -bhyve architecture ------------------- - Linux - I/O VM control FreeBSD NetBSD - OpenBSD - | A | A | | - V | V | V V - +-------------++-------------++-------------++-------------+ - | || || || | - | bhyve || bhyvectl || bhyveload || grub2-bhyve | - | || || || | - | || || || | - +-------------++-------------++-------------++-------------+ - +----------------------------------------------------------+ - | libvmmapi | - +----------------------------------------------------------+ - A - | user - ------------------------------┼------------------------------ - | ioctl FreeBSD kernel - V - +----------------------------+ - | VMX/SVM host | - | VMX/SVM guest | - | VMX/SVM nested paging | - | Timers | - | Interrupts | - +----------------------------+ - vmm.ko - - -**vmm.ko** - -The bhyve FreeBSD kernel module. Manages VM and vCPU objects, the guest physical address space and handles guest interaction with PIC, PIT, HPET, PM Timer, x(2)APIC and I/O-APIC. Contains a minimal x86 emulator to decode guest MMIO. Executes the two innermost vCPU runloops (VMX/SVM and interrupts/timers/paging). Has backends for Intel VMX and AMD SVM. Provides an ioctl and mmap API to userspace. - -**libvmmapi** - -Thin abstraction layer between the vmm.ko ioctl interface and the userspace C API. - -**bhyve** - -The userspace bhyve component (kind of a very light-weight QEMU) that executes virtual machines. Runs the guest I/O vCPU runloops. Manages ACPI, PCI and all non in-kernel devices. Interacts with vmm.ko through libvmmapi. - -**bhyvectl** - -Somewhat superfluous utility to introspect and manage the life cycle of virtual machines. Virtual machines and vCPUs can exist as kernel objects independently of a bhyve host process. Typically used to delete VM objects after use. Odd architectural choice. - -**bhyveload** - -Userspace port of the FreeBSD bootloader. Since bhyve still lacks a firmware this is a cumbersome workaround to bootstrap a guest operating system. It creates a VM object, loads the FreeBSD kernel into guest memory, sets up the initial vCPU state and then exits. Only then a VM can be executed by bhyve. - -**grub2-bhyve** - -Performs the same function as bhyveload but is a userspace port of [GRUB2](http://github.com/grehan-freebsd/grub2-bhyve). It is used to bootstrap guest operating systems other than FreeBSD, i.e. Linux, OpenBSD and NetBSD. - -Support for Windows guests is work in progress and dependent on the EFI port. - - -xhyve architecture ------------------- - +----------------------------------------------------------+ - | xhyve | - | | - | I/O | - | | - | | - | | - |+--------------------------------------------------------+| - || vmm VMX guest || - || Timers || - || Interrupts || - |+--------------------------------------------------------+| - +----------------------------------------------------------+ - +----------------------------------------------------------+ - | Hypervisor.framework | - +----------------------------------------------------------+ - A - | user - ------------------------------┼------------------------------ - |syscall xnu kernel - V - - VMX host - VMX nested paging - - -xhyve shares most of the code with bhyve but is architecturally very different. Hypervisor.framework provides an interface to the VMX VMCS guest state and a safe subset of the VMCS control fields, thus making userspace hypervisors without any additional kernel extensions possible. The VMX host state and all aspects of nested paging are handled by the OS X kernel, you can manage the guest physical address space simply through mapping of regions of your own address space. - -*xhyve* is equivalent to the *bhyve* process but gains a subset of a userspace port of the vmm kernel module. SVM, PCI passthrough and the VMX host and EPT aspects are dropped. The vmm component provides a libvmmapi compatible interface to xhyve. Hypervisor.framework seems to enforce a strict 1:1 relationship between a host process/VM and host thread/vCPU, that means VMs and vCPUs can only be interacted with by the processes and threads that created them. Therefore, unlike bhyve, xhyve needs to adhere to a single process model. Multiple virtual machines can be created by launching multiple instances of xhyve. xhyve retains most of the bhyve command line interface. - -*bhyvectl*, *bhyveload* and *grub2-bhyve* are incompatible with a single process model and are dropped. As a stop-gap solution until we have a proper firmware xhyve supports the Linux [kexec protocol](http://www.kernel.org/doc/Documentation/x86/boot.txt), a very simple and straightforward way to bootstrap a Linux kernel. It takes a bzImage and optionally initrd image and kernel parameter string as input. - -Networking ------- -If you want the same IP address across VM reboots, assign a UUID to a particular VM: - - $ xhyve [-U uuid] - -**Optional:** - -If you need more advanced networking and already have a configured [TAP](http://tuntaposx.sourceforge.net) device you can use it with: - - virtio-tap,tapX - -instead of: - - virtio-net - -Where *X* is your tap device, i.e. */dev/tapX*. - -Issues ------- -If you are, or were, running any version of VirtualBox, prior to 4.3.30 or 5.0, -and attempt to run xhyve your system will immediately crash as a kernel panic is -triggered. This is due to a VirtualBox bug (that got fixed in newest VirtualBox -versions) as VirtualBox wasn't playing nice with OSX's Hypervisor.framework used -by xhyve. - -To get around this you either have to update to newest VirtualBox 4.3 or 5.0 or, -if you for some reason are unable to update, to reboot -your Mac after using VirtualBox and before attempting to use xhyve. -(see issues [#5](https://github.com/mist64/xhyve/issues/5) and -[#9](https://github.com/mist64/xhyve/issues/9) for the full context) - -TODO ----- - -- vmm: - - enable APIC access page to speed up APIC emulation (**performance**) - - enable x2APIC MSRs (even faster) (**performance**) - - vmm_callout: - - is a quick'n'dirty implementation of the FreeBSD kernel callout mechanism - - seems to be racy - - fix races or perhaps replace with something better - - use per vCPU timer event thread (**performance**)? - - use hardware VMX preemption timer instead of `pthread_cond_wait` (**performance**) - - some 32-bit guests are broken (support PAE paging in VMCS) - - PCID guest support (**performance**) -- block_if: - - OS X does not support `preadv`/`pwritev`, we need to serialize reads and writes for the time being until we find a better solution. (**performance**) - - support block devices other than plain files -- virtio_net: - - unify TAP and vmnet backends - - vmnet: make it not require root - - vmnet: send/receive more than a single packet at a time (**performance**) -- virtio_rnd: - - is untested -- remove explicit state transitions: - - since only the owning task/thread can modify the VM/vCPUs a lot of the synchronization might be unnecessary (**performance**) -- performance, performance and performance -- remove vestigial code, cleanup diff --git a/tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/go/hyperkit.go b/tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/go/hyperkit.go deleted file mode 100644 index 09e3ee6ed..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/docker/hyperkit/go/hyperkit.go +++ /dev/null @@ -1,534 +0,0 @@ -// +build darwin - -// Package hyperkit provides a Go wrapper around the hyperkit -// command. It currently shells out to start hyperkit with the -// provided configuration. -// -// Most of the arguments should be self explanatory, but console -// handling deserves a mention. If the Console is configured with -// ConsoleStdio, the hyperkit is started with stdin, stdout, and -// stderr plumbed through to the VM console. If Console is set to -// ConsoleFile hyperkit the console output is redirected to a file and -// console input is disabled. For this mode StateDir has to be set and -// the interactive console is accessible via a 'tty' file created -// there. -// -// Currently this module has some limitations: -// - Only supports zero or one disk image -// - Only support zero or one network interface connected to VPNKit -// - Only kexec boot -// -// This package is currently implemented by shelling out a hyperkit -// process. In the future we may change this to become a wrapper -// around the hyperkit library. -package hyperkit - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "log" - "os" - "os/exec" - "os/user" - "path/filepath" - "strconv" - "strings" - - "github.com/mitchellh/go-ps" - "github.com/rneugeba/iso9660wrap" -) - -const ( - // ConsoleStdio configures console to use Stdio - ConsoleStdio = iota - // ConsoleFile configures console to a tty and output to a file - ConsoleFile - - defaultVPNKitSock = "Library/Containers/com.docker.docker/Data/s50" - defaultDiskImage = "disk.img" - - defaultCPUs = 1 - defaultMemory = 1024 // 1G - - jsonFile = "hyperkit.json" - pidFile = "hyperkit.pid" -) - -var defaultHyperKits = []string{"hyperkit", - "com.docker.hyperkit", - "/usr/local/bin/hyperkit", - "/Applications/Docker.app/Contents/Resources/bin/hyperkit", - "/Applications/Docker.app/Contents/MacOS/com.docker.hyperkit"} - -// HyperKit contains the configuration of the hyperkit VM -type HyperKit struct { - // HyperKit is the path to the hyperkit binary - HyperKit string `json:"hyperkit"` - // StateDir is the directory where runtime state is kept. If left empty, no state will be kept. - StateDir string `json:"state_dir"` - // VPNKitSock is the location of the VPNKit socket used for networking. - VPNKitSock string `json:"vpnkit_sock"` - // DiskImage is the path to the disk image to use - DiskImage string `json:"disk"` - // ISOImage is the (optional) path to a ISO image to attach - ISOImage string `json:"iso"` - - // Kernel is the path to the kernel image to boot - Kernel string `json:"kernel"` - // Initrd is the path to the initial ramdisk to boot off - Initrd string `json:"initrd"` - - // CPUs is the number CPUs to configure - CPUs int `json:"cpus"` - // Memory is the amount of megabytes of memory for the VM - Memory int `json:"memory"` - // DiskSize is the size of the disk image in megabytes. If zero and DiskImage does not exist, no disk will be attached. - DiskSize int `json:"disk_size"` - - // Console defines where the console of the VM should be - // connected to. ConsoleStdio and ConsoleFile are supported. - Console int `json:"console"` - - // UserData, if non empty, will be added to a ISO under the - // filename `config` and passed to the VM. - UserData string `json:"user_data"` - - // Below here are internal members, but they are exported so - // that they are written to the state json file, if configured. - - // Pid of the hyperkit process - Pid int `json:"pid"` - // Arguments used to execute the hyperkit process - Arguments []string `json:"arguments"` - // CmdLine is a single string of the command line - CmdLine string `json:"cmdline"` - - process *os.Process - background bool - log *log.Logger -} - -// New creates a template config structure. -// - If hyperkit can't be found an error is returned. -// - If vpnkitsock is empty no networking is configured. If it is set -// to "auto" it tries to re-use the Docker for Mac VPNKit connection. -// - If statedir is "" no state is written to disk. -func New(hyperkit, statedir, vpnkitsock, diskimage string) (*HyperKit, error) { - h := HyperKit{} - var err error - - h.HyperKit, err = checkHyperKit(hyperkit) - if err != nil { - return nil, err - } - h.StateDir = statedir - h.VPNKitSock, err = checkVPNKitSock(vpnkitsock) - if err != nil { - return nil, err - } - h.DiskImage = diskimage - - h.CPUs = defaultCPUs - h.Memory = defaultMemory - - h.Console = ConsoleStdio - h.UserData = "" - - return &h, nil -} - -// FromState reads a json file from statedir and populates a HyperKit structure. -func FromState(statedir string) (*HyperKit, error) { - b, err := ioutil.ReadFile(filepath.Join(statedir, jsonFile)) - if err != nil { - return nil, fmt.Errorf("Can't read json file: ", err) - } - h := &HyperKit{} - err = json.Unmarshal(b, h) - if err != nil { - return nil, fmt.Errorf("Can't parse json file: ", err) - } - - // Make sure the pid written by hyperkit is the same as in the json - d, err := ioutil.ReadFile(filepath.Join(statedir, pidFile)) - if err != nil { - return nil, err - } - pid, err := strconv.Atoi(string(d[:])) - if err != nil { - return nil, err - } - if h.Pid != pid { - return nil, fmt.Errorf("pids do not match %d != %d", h.Pid, pid) - } - - h.process, err = os.FindProcess(h.Pid) - if err != nil { - return nil, err - } - - return h, nil -} - -// SetLogger sets the log instance to use for the output of the hyperkit process itself (not the console of the VM). -// This is only relevant when Console is set to ConsoleFile -func (h *HyperKit) SetLogger(logger *log.Logger) { - h.log = logger -} - -// Run the VM with a given command line until it exits -func (h *HyperKit) Run(cmdline string) error { - h.background = false - return h.execute(cmdline) -} - -// Start the VM with a given command line in the background -func (h *HyperKit) Start(cmdline string) error { - h.background = true - return h.execute(cmdline) -} - -func (h *HyperKit) execute(cmdline string) error { - var err error - // Sanity checks on configuration - if h.Console == ConsoleFile && h.StateDir == "" { - return fmt.Errorf("If ConsoleFile is set, StateDir was be specified") - } - if h.UserData != "" && h.ISOImage != "" { - return fmt.Errorf("If UserData is supplied, ISOImage must not be set") - } - if h.ISOImage != "" { - if _, err = os.Stat(h.ISOImage); os.IsNotExist(err) { - return fmt.Errorf("ISO %s does not exist", h.ISOImage) - } - } - if h.UserData != "" && h.StateDir == "" { - return fmt.Errorf("If UserData is supplied, StateDir was be specified") - } - if _, err = os.Stat(h.Kernel); os.IsNotExist(err) { - return fmt.Errorf("Kernel %s does not exist", h.Kernel) - } - if _, err = os.Stat(h.Initrd); os.IsNotExist(err) { - return fmt.Errorf("initrd %s does not exist", h.Initrd) - } - if h.DiskImage == "" && h.StateDir == "" && h.DiskSize != 0 { - return fmt.Errorf("Can't create disk, because neither DiskImage nor StateDir is set") - } - - // Create files - if h.StateDir != "" { - err = os.MkdirAll(h.StateDir, 0755) - if err != nil { - return err - } - } - if h.DiskImage == "" && h.DiskSize != 0 { - h.DiskImage = filepath.Join(h.StateDir, "disk.img") - } - if _, err = os.Stat(h.DiskImage); os.IsNotExist(err) { - if h.DiskSize != 0 { - err = CreateDiskImage(h.DiskImage, h.DiskSize) - if err != nil { - return err - } - } - } - if h.UserData != "" { - h.ISOImage, err = createUserDataISO(h.StateDir, h.UserData) - if err != nil { - return err - } - } - - // Run - h.buildArgs(cmdline) - err = h.execHyperKit() - if err != nil { - return err - } - - return nil -} - -// Stop the running VM -func (h *HyperKit) Stop() error { - if h.process == nil { - return fmt.Errorf("hyperkit process not known") - } - if !h.IsRunning() { - return nil - } - err := h.process.Kill() - if err != nil { - return err - } - - return nil -} - -// IsRunning returns true if the hyperkit process is running. -func (h *HyperKit) IsRunning() bool { - // os.FindProcess on Unix always returns a process object even - // if the process does not exists. There does not seem to be - // a call to find out if the process is running either, so we - // use another package to find out. - proc, err := ps.FindProcess(h.Pid) - if err != nil { - return false - } - if proc == nil { - return false - } - return true -} - -// Remove deletes all statefiles if present. -// This also removes the StateDir if empty. -// If keepDisk is set, the diskimage will not get removed. -func (h *HyperKit) Remove(keepDisk bool) error { - if h.IsRunning() { - return fmt.Errorf("Can't remove state as process is running") - } - if h.StateDir == "" { - // If there is not state directory we don't mess with the disk - return nil - } - - if !keepDisk { - return os.RemoveAll(h.StateDir) - } - - files, _ := ioutil.ReadDir(h.StateDir) - for _, f := range files { - fn := filepath.Clean(filepath.Join(h.StateDir, f.Name())) - if fn == h.DiskImage { - continue - } - err := os.Remove(fn) - if err != nil { - return err - } - } - return nil -} - -// Convert to json string -func (h *HyperKit) String() string { - s, err := json.Marshal(h) - if err != nil { - return err.Error() - } - return string(s) -} - -// CreateDiskImage creates a empty file suitable for use as a disk image for a hyperkit VM. -func CreateDiskImage(location string, sizeMB int) error { - f, err := os.Create(location) - if err != nil { - return err - } - defer f.Close() - - buf := make([]byte, 1048676) - for i := 0; i < sizeMB; i++ { - f.Write(buf) - } - return nil -} - -func (h *HyperKit) buildArgs(cmdline string) { - a := []string{"-A", "-u"} - if h.StateDir != "" { - a = append(a, "-F", filepath.Join(h.StateDir, pidFile)) - } - - a = append(a, "-c", fmt.Sprintf("%d", h.CPUs)) - a = append(a, "-m", fmt.Sprintf("%dM", h.Memory)) - - a = append(a, "-s", "0:0,hostbridge") - if h.VPNKitSock != "" { - a = append(a, "-s", fmt.Sprintf("1:0,virtio-vpnkit,path=%s", h.VPNKitSock)) - } - if h.DiskImage != "" { - a = append(a, "-s", fmt.Sprintf("2:0,virtio-blk,%s", h.DiskImage)) - } - if h.ISOImage != "" { - a = append(a, "-s", fmt.Sprintf("4,ahci-cd,%s", h.ISOImage)) - } - - a = append(a, "-s", "10,virtio-rnd") - a = append(a, "-s", "31,lpc") - - if h.Console == ConsoleFile { - a = append(a, "-l", fmt.Sprintf("com1,autopty=%s/tty,log=%s/console-ring", h.StateDir, h.StateDir)) - } else { - a = append(a, "-l", "com1,stdio") - } - - kernArgs := fmt.Sprintf("kexec,%s,%s,earlyprintk=serial %s", h.Kernel, h.Initrd, cmdline) - a = append(a, "-f", kernArgs) - - h.Arguments = a - h.CmdLine = h.HyperKit + " " + strings.Join(a, " ") -} - -// Execute hyperkit and plumb stdin/stdout/stderr. -func (h *HyperKit) execHyperKit() error { - - cmd := exec.Command(h.HyperKit, h.Arguments...) - cmd.Env = os.Environ() - - // Plumb in stdin/stdout/stderr. If ConsoleStdio is configured - // plumb them to the system streams. If a logger is specified, - // use it for stdout/stderr logging. Otherwise use the default - // /dev/null. - if h.Console == ConsoleStdio { - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - } else if h.log != nil { - stdoutChan := make(chan string) - stderrChan := make(chan string) - stdout, err := cmd.StdoutPipe() - if err != nil { - return err - } - stderr, err := cmd.StderrPipe() - if err != nil { - return err - } - stream(stdout, stdoutChan) - stream(stderr, stderrChan) - - done := make(chan struct{}) - go func() { - for { - select { - case stderrl := <-stderrChan: - log.Printf("%s", stderrl) - case stdoutl := <-stdoutChan: - log.Printf("%s", stdoutl) - case <-done: - return - } - } - }() - } - - err := cmd.Start() - if err != nil { - return err - } - h.Pid = cmd.Process.Pid - h.process = cmd.Process - err = h.writeState() - if err != nil { - h.process.Kill() - return err - } - if !h.background { - err = cmd.Wait() - if err != nil { - return err - } - } - return nil -} - -// writeState write the state to a JSON file -func (h *HyperKit) writeState() error { - if h.StateDir == "" { - // This is not an error - return nil - } - - s, err := json.Marshal(h) - if err != nil { - return err - } - return ioutil.WriteFile(filepath.Join(h.StateDir, jsonFile), []byte(s), 0644) -} - -func stream(r io.ReadCloser, dest chan<- string) { - go func() { - defer r.Close() - reader := bufio.NewReader(r) - for { - line, err := reader.ReadString('\n') - if err != nil { - return - } - dest <- line - } - }() -} - -// Create a ISO with Userdata in the specified directory -func createUserDataISO(dir string, init string) (string, error) { - cfgName := filepath.Join(dir, "config") - isoName := cfgName + ".iso" - - if err := ioutil.WriteFile(cfgName, []byte(init), 0644); err != nil { - return "", err - } - - outfh, err := os.OpenFile(isoName, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644) - if err != nil { - return "", err - } - infh, err := os.Open(cfgName) - if err != nil { - return "", err - } - err = iso9660wrap.WriteFile(outfh, infh) - if err != nil { - return "", err - } - - return isoName, nil -} - -// checkHyperKit tries to find and/or validate the path of hyperkit -func checkHyperKit(hyperkit string) (string, error) { - if hyperkit != "" { - p, err := exec.LookPath(hyperkit) - if err != nil { - return "", fmt.Errorf("Could not find hyperkit executable: ", hyperkit) - } - return p, nil - } - - // Look in a number of default locations - for _, hyperkit := range defaultHyperKits { - p, err := exec.LookPath(hyperkit) - if err == nil { - return p, nil - } - } - - return "", fmt.Errorf("Could not find hyperkit executable") -} - -// checkVPNKitSock tries to find and/or validate the path of the VPNKit socket -func checkVPNKitSock(vpnkitsock string) (string, error) { - if vpnkitsock == "auto" { - vpnkitsock = filepath.Join(getHome(), defaultVPNKitSock) - } - - vpnkitsock = filepath.Clean(vpnkitsock) - _, err := os.Stat(vpnkitsock) - if err != nil { - return "", err - } - return vpnkitsock, nil -} - -func getHome() string { - if usr, err := user.Current(); err == nil { - return usr.HomeDir - } - return os.Getenv("HOME") -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/docker/infrakit b/tools/infrakit.hyperkit/vendor/github.com/docker/infrakit deleted file mode 160000 index 6516ace03..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/docker/infrakit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6516ace03d405955f738f8965abde5d9ab37fef6 diff --git a/tools/infrakit.hyperkit/vendor/github.com/gorilla/context b/tools/infrakit.hyperkit/vendor/github.com/gorilla/context deleted file mode 160000 index 08b5f424b..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/gorilla/context +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 08b5f424b9271eedf6f9f0ce86cb9396ed337a42 diff --git a/tools/infrakit.hyperkit/vendor/github.com/gorilla/mux b/tools/infrakit.hyperkit/vendor/github.com/gorilla/mux deleted file mode 160000 index 999ef73f5..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/gorilla/mux +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 999ef73f5d50979cf6d12afed1726325b63f9570 diff --git a/tools/infrakit.hyperkit/vendor/github.com/gorilla/rpc b/tools/infrakit.hyperkit/vendor/github.com/gorilla/rpc deleted file mode 160000 index 22c016f3d..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/gorilla/rpc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 22c016f3df3febe0c1f6727598b6389507e03a18 diff --git a/tools/infrakit.hyperkit/vendor/github.com/inconshreveable/mousetrap b/tools/infrakit.hyperkit/vendor/github.com/inconshreveable/mousetrap deleted file mode 160000 index 76626ae9c..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/inconshreveable/mousetrap +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 diff --git a/tools/infrakit.hyperkit/vendor/github.com/jmespath/go-jmespath b/tools/infrakit.hyperkit/vendor/github.com/jmespath/go-jmespath deleted file mode 160000 index bd40a432e..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/jmespath/go-jmespath +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d diff --git a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/README.md b/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/README.md deleted file mode 100644 index 8e8baf9d2..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Process List Library for Go - -go-ps is a library for Go that implements OS-specific APIs to list and -manipulate processes in a platform-safe way. The library can find and -list processes on Linux, Mac OS X, Solaris, and Windows. - -If you're new to Go, this library has a good amount of advanced Go educational -value as well. It uses some advanced features of Go: build tags, accessing -DLL methods for Windows, cgo for Darwin, etc. - -How it works: - - * **Darwin** uses the `sysctl` syscall to retrieve the process table. - * **Unix** uses the procfs at `/proc` to inspect the process tree. - * **Windows** uses the Windows API, and methods such as - `CreateToolhelp32Snapshot` to get a point-in-time snapshot of - the process table. - -## Installation - -Install using standard `go get`: - -``` -$ go get github.com/mitchellh/go-ps -... -``` - -## TODO - -Want to contribute? Here is a short TODO list of things that aren't -implemented for this library that would be nice: - - * FreeBSD support - * Plan9 support diff --git a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process.go b/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process.go deleted file mode 100644 index 2b5e8ed23..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process.go +++ /dev/null @@ -1,40 +0,0 @@ -// ps provides an API for finding and listing processes in a platform-agnostic -// way. -// -// NOTE: If you're reading these docs online via GoDocs or some other system, -// you might only see the Unix docs. This project makes heavy use of -// platform-specific implementations. We recommend reading the source if you -// are interested. -package ps - -// Process is the generic interface that is implemented on every platform -// and provides common operations for processes. -type Process interface { - // Pid is the process ID for this process. - Pid() int - - // PPid is the parent process ID for this process. - PPid() int - - // Executable name running this process. This is not a path to the - // executable. - Executable() string -} - -// Processes returns all processes. -// -// This of course will be a point-in-time snapshot of when this method was -// called. Some operating systems don't provide snapshot capability of the -// process table, in which case the process table returned might contain -// ephemeral entities that happened to be running when this was called. -func Processes() ([]Process, error) { - return processes() -} - -// FindProcess looks up a single process by pid. -// -// Process will be nil and error will be nil if a matching process is -// not found. -func FindProcess(pid int) (Process, error) { - return findProcess(pid) -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_darwin.go b/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_darwin.go deleted file mode 100644 index 5ee87fb68..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_darwin.go +++ /dev/null @@ -1,138 +0,0 @@ -// +build darwin - -package ps - -import ( - "bytes" - "encoding/binary" - "syscall" - "unsafe" -) - -type DarwinProcess struct { - pid int - ppid int - binary string -} - -func (p *DarwinProcess) Pid() int { - return p.pid -} - -func (p *DarwinProcess) PPid() int { - return p.ppid -} - -func (p *DarwinProcess) Executable() string { - return p.binary -} - -func findProcess(pid int) (Process, error) { - ps, err := processes() - if err != nil { - return nil, err - } - - for _, p := range ps { - if p.Pid() == pid { - return p, nil - } - } - - return nil, nil -} - -func processes() ([]Process, error) { - buf, err := darwinSyscall() - if err != nil { - return nil, err - } - - procs := make([]*kinfoProc, 0, 50) - k := 0 - for i := _KINFO_STRUCT_SIZE; i < buf.Len(); i += _KINFO_STRUCT_SIZE { - proc := &kinfoProc{} - err = binary.Read(bytes.NewBuffer(buf.Bytes()[k:i]), binary.LittleEndian, proc) - if err != nil { - return nil, err - } - - k = i - procs = append(procs, proc) - } - - darwinProcs := make([]Process, len(procs)) - for i, p := range procs { - darwinProcs[i] = &DarwinProcess{ - pid: int(p.Pid), - ppid: int(p.PPid), - binary: darwinCstring(p.Comm), - } - } - - return darwinProcs, nil -} - -func darwinCstring(s [16]byte) string { - i := 0 - for _, b := range s { - if b != 0 { - i++ - } else { - break - } - } - - return string(s[:i]) -} - -func darwinSyscall() (*bytes.Buffer, error) { - mib := [4]int32{_CTRL_KERN, _KERN_PROC, _KERN_PROC_ALL, 0} - size := uintptr(0) - - _, _, errno := syscall.Syscall6( - syscall.SYS___SYSCTL, - uintptr(unsafe.Pointer(&mib[0])), - 4, - 0, - uintptr(unsafe.Pointer(&size)), - 0, - 0) - - if errno != 0 { - return nil, errno - } - - bs := make([]byte, size) - _, _, errno = syscall.Syscall6( - syscall.SYS___SYSCTL, - uintptr(unsafe.Pointer(&mib[0])), - 4, - uintptr(unsafe.Pointer(&bs[0])), - uintptr(unsafe.Pointer(&size)), - 0, - 0) - - if errno != 0 { - return nil, errno - } - - return bytes.NewBuffer(bs[0:size]), nil -} - -const ( - _CTRL_KERN = 1 - _KERN_PROC = 14 - _KERN_PROC_ALL = 0 - _KINFO_STRUCT_SIZE = 648 -) - -type kinfoProc struct { - _ [40]byte - Pid int32 - _ [199]byte - Comm [16]byte - _ [301]byte - PPid int32 - _ [84]byte -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_freebsd.go b/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_freebsd.go deleted file mode 100644 index 0212b66ac..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_freebsd.go +++ /dev/null @@ -1,260 +0,0 @@ -// +build freebsd,amd64 - -package ps - -import ( - "bytes" - "encoding/binary" - "syscall" - "unsafe" -) - -// copied from sys/sysctl.h -const ( - CTL_KERN = 1 // "high kernel": proc, limits - KERN_PROC = 14 // struct: process entries - KERN_PROC_PID = 1 // by process id - KERN_PROC_PROC = 8 // only return procs - KERN_PROC_PATHNAME = 12 // path to executable -) - -// copied from sys/user.h -type Kinfo_proc struct { - Ki_structsize int32 - Ki_layout int32 - Ki_args int64 - Ki_paddr int64 - Ki_addr int64 - Ki_tracep int64 - Ki_textvp int64 - Ki_fd int64 - Ki_vmspace int64 - Ki_wchan int64 - Ki_pid int32 - Ki_ppid int32 - Ki_pgid int32 - Ki_tpgid int32 - Ki_sid int32 - Ki_tsid int32 - Ki_jobc [2]byte - Ki_spare_short1 [2]byte - Ki_tdev int32 - Ki_siglist [16]byte - Ki_sigmask [16]byte - Ki_sigignore [16]byte - Ki_sigcatch [16]byte - Ki_uid int32 - Ki_ruid int32 - Ki_svuid int32 - Ki_rgid int32 - Ki_svgid int32 - Ki_ngroups [2]byte - Ki_spare_short2 [2]byte - Ki_groups [64]byte - Ki_size int64 - Ki_rssize int64 - Ki_swrss int64 - Ki_tsize int64 - Ki_dsize int64 - Ki_ssize int64 - Ki_xstat [2]byte - Ki_acflag [2]byte - Ki_pctcpu int32 - Ki_estcpu int32 - Ki_slptime int32 - Ki_swtime int32 - Ki_cow int32 - Ki_runtime int64 - Ki_start [16]byte - Ki_childtime [16]byte - Ki_flag int64 - Ki_kiflag int64 - Ki_traceflag int32 - Ki_stat [1]byte - Ki_nice [1]byte - Ki_lock [1]byte - Ki_rqindex [1]byte - Ki_oncpu [1]byte - Ki_lastcpu [1]byte - Ki_ocomm [17]byte - Ki_wmesg [9]byte - Ki_login [18]byte - Ki_lockname [9]byte - Ki_comm [20]byte - Ki_emul [17]byte - Ki_sparestrings [68]byte - Ki_spareints [36]byte - Ki_cr_flags int32 - Ki_jid int32 - Ki_numthreads int32 - Ki_tid int32 - Ki_pri int32 - Ki_rusage [144]byte - Ki_rusage_ch [144]byte - Ki_pcb int64 - Ki_kstack int64 - Ki_udata int64 - Ki_tdaddr int64 - Ki_spareptrs [48]byte - Ki_spareint64s [96]byte - Ki_sflag int64 - Ki_tdflags int64 -} - -// UnixProcess is an implementation of Process that contains Unix-specific -// fields and information. -type UnixProcess struct { - pid int - ppid int - state rune - pgrp int - sid int - - binary string -} - -func (p *UnixProcess) Pid() int { - return p.pid -} - -func (p *UnixProcess) PPid() int { - return p.ppid -} - -func (p *UnixProcess) Executable() string { - return p.binary -} - -// Refresh reloads all the data associated with this process. -func (p *UnixProcess) Refresh() error { - - mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PID, int32(p.pid)} - - buf, length, err := call_syscall(mib) - if err != nil { - return err - } - proc_k := Kinfo_proc{} - if length != uint64(unsafe.Sizeof(proc_k)) { - return err - } - - k, err := parse_kinfo_proc(buf) - if err != nil { - return err - } - - p.ppid, p.pgrp, p.sid, p.binary = copy_params(&k) - return nil -} - -func copy_params(k *Kinfo_proc) (int, int, int, string) { - n := -1 - for i, b := range k.Ki_comm { - if b == 0 { - break - } - n = i + 1 - } - comm := string(k.Ki_comm[:n]) - - return int(k.Ki_ppid), int(k.Ki_pgid), int(k.Ki_sid), comm -} - -func findProcess(pid int) (Process, error) { - mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, int32(pid)} - - _, _, err := call_syscall(mib) - if err != nil { - return nil, err - } - - return newUnixProcess(pid) -} - -func processes() ([]Process, error) { - results := make([]Process, 0, 50) - - mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0} - buf, length, err := call_syscall(mib) - if err != nil { - return results, err - } - - // get kinfo_proc size - k := Kinfo_proc{} - procinfo_len := int(unsafe.Sizeof(k)) - count := int(length / uint64(procinfo_len)) - - // parse buf to procs - for i := 0; i < count; i++ { - b := buf[i*procinfo_len : i*procinfo_len+procinfo_len] - k, err := parse_kinfo_proc(b) - if err != nil { - continue - } - p, err := newUnixProcess(int(k.Ki_pid)) - if err != nil { - continue - } - p.ppid, p.pgrp, p.sid, p.binary = copy_params(&k) - - results = append(results, p) - } - - return results, nil -} - -func parse_kinfo_proc(buf []byte) (Kinfo_proc, error) { - var k Kinfo_proc - br := bytes.NewReader(buf) - err := binary.Read(br, binary.LittleEndian, &k) - if err != nil { - return k, err - } - - return k, nil -} - -func call_syscall(mib []int32) ([]byte, uint64, error) { - miblen := uint64(len(mib)) - - // get required buffer size - length := uint64(0) - _, _, err := syscall.RawSyscall6( - syscall.SYS___SYSCTL, - uintptr(unsafe.Pointer(&mib[0])), - uintptr(miblen), - 0, - uintptr(unsafe.Pointer(&length)), - 0, - 0) - if err != 0 { - b := make([]byte, 0) - return b, length, err - } - if length == 0 { - b := make([]byte, 0) - return b, length, err - } - // get proc info itself - buf := make([]byte, length) - _, _, err = syscall.RawSyscall6( - syscall.SYS___SYSCTL, - uintptr(unsafe.Pointer(&mib[0])), - uintptr(miblen), - uintptr(unsafe.Pointer(&buf[0])), - uintptr(unsafe.Pointer(&length)), - 0, - 0) - if err != 0 { - return buf, length, err - } - - return buf, length, nil -} - -func newUnixProcess(pid int) (*UnixProcess, error) { - p := &UnixProcess{pid: pid} - return p, p.Refresh() -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_linux.go b/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_linux.go deleted file mode 100644 index c1558f783..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_linux.go +++ /dev/null @@ -1,35 +0,0 @@ -// +build linux - -package ps - -import ( - "fmt" - "io/ioutil" - "strings" -) - -// Refresh reloads all the data associated with this process. -func (p *UnixProcess) Refresh() error { - statPath := fmt.Sprintf("/proc/%d/stat", p.pid) - dataBytes, err := ioutil.ReadFile(statPath) - if err != nil { - return err - } - - // First, parse out the image name - data := string(dataBytes) - binStart := strings.IndexRune(data, '(') + 1 - binEnd := strings.IndexRune(data[binStart:], ')') - p.binary = data[binStart : binStart+binEnd] - - // Move past the image name and start parsing the rest - data = data[binStart+binEnd+2:] - _, err = fmt.Sscanf(data, - "%c %d %d %d", - &p.state, - &p.ppid, - &p.pgrp, - &p.sid) - - return err -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_solaris.go b/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_solaris.go deleted file mode 100644 index 014c41611..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_solaris.go +++ /dev/null @@ -1,96 +0,0 @@ -// +build solaris - -package ps - -import ( - "encoding/binary" - "fmt" - "os" -) - -type ushort_t uint16 - -type id_t int32 -type pid_t int32 -type uid_t int32 -type gid_t int32 - -type dev_t uint64 -type size_t uint64 -type uintptr_t uint64 - -type timestruc_t [16]byte - -// This is copy from /usr/include/sys/procfs.h -type psinfo_t struct { - Pr_flag int32 /* process flags (DEPRECATED; do not use) */ - Pr_nlwp int32 /* number of active lwps in the process */ - Pr_pid pid_t /* unique process id */ - Pr_ppid pid_t /* process id of parent */ - Pr_pgid pid_t /* pid of process group leader */ - Pr_sid pid_t /* session id */ - Pr_uid uid_t /* real user id */ - Pr_euid uid_t /* effective user id */ - Pr_gid gid_t /* real group id */ - Pr_egid gid_t /* effective group id */ - Pr_addr uintptr_t /* address of process */ - Pr_size size_t /* size of process image in Kbytes */ - Pr_rssize size_t /* resident set size in Kbytes */ - Pr_pad1 size_t - Pr_ttydev dev_t /* controlling tty device (or PRNODEV) */ - - // Guess this following 2 ushort_t values require a padding to properly - // align to the 64bit mark. - Pr_pctcpu ushort_t /* % of recent cpu time used by all lwps */ - Pr_pctmem ushort_t /* % of system memory used by process */ - Pr_pad64bit [4]byte - - Pr_start timestruc_t /* process start time, from the epoch */ - Pr_time timestruc_t /* usr+sys cpu time for this process */ - Pr_ctime timestruc_t /* usr+sys cpu time for reaped children */ - Pr_fname [16]byte /* name of execed file */ - Pr_psargs [80]byte /* initial characters of arg list */ - Pr_wstat int32 /* if zombie, the wait() status */ - Pr_argc int32 /* initial argument count */ - Pr_argv uintptr_t /* address of initial argument vector */ - Pr_envp uintptr_t /* address of initial environment vector */ - Pr_dmodel [1]byte /* data model of the process */ - Pr_pad2 [3]byte - Pr_taskid id_t /* task id */ - Pr_projid id_t /* project id */ - Pr_nzomb int32 /* number of zombie lwps in the process */ - Pr_poolid id_t /* pool id */ - Pr_zoneid id_t /* zone id */ - Pr_contract id_t /* process contract */ - Pr_filler int32 /* reserved for future use */ - Pr_lwp [128]byte /* information for representative lwp */ -} - -func (p *UnixProcess) Refresh() error { - var psinfo psinfo_t - - path := fmt.Sprintf("/proc/%d/psinfo", p.pid) - fh, err := os.Open(path) - if err != nil { - return err - } - defer fh.Close() - - err = binary.Read(fh, binary.LittleEndian, &psinfo) - if err != nil { - return err - } - - p.ppid = int(psinfo.Pr_ppid) - p.binary = toString(psinfo.Pr_fname[:], 16) - return nil -} - -func toString(array []byte, len int) string { - for i := 0; i < len; i++ { - if array[i] == 0 { - return string(array[:i]) - } - } - return string(array[:]) -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_unix.go b/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_unix.go deleted file mode 100644 index 3b733cec4..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_unix.go +++ /dev/null @@ -1,101 +0,0 @@ -// +build linux solaris - -package ps - -import ( - "fmt" - "io" - "os" - "strconv" -) - -// UnixProcess is an implementation of Process that contains Unix-specific -// fields and information. -type UnixProcess struct { - pid int - ppid int - state rune - pgrp int - sid int - - binary string -} - -func (p *UnixProcess) Pid() int { - return p.pid -} - -func (p *UnixProcess) PPid() int { - return p.ppid -} - -func (p *UnixProcess) Executable() string { - return p.binary -} - -func findProcess(pid int) (Process, error) { - dir := fmt.Sprintf("/proc/%d", pid) - _, err := os.Stat(dir) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - - return nil, err - } - - return newUnixProcess(pid) -} - -func processes() ([]Process, error) { - d, err := os.Open("/proc") - if err != nil { - return nil, err - } - defer d.Close() - - results := make([]Process, 0, 50) - for { - fis, err := d.Readdir(10) - if err == io.EOF { - break - } - if err != nil { - return nil, err - } - - for _, fi := range fis { - // We only care about directories, since all pids are dirs - if !fi.IsDir() { - continue - } - - // We only care if the name starts with a numeric - name := fi.Name() - if name[0] < '0' || name[0] > '9' { - continue - } - - // From this point forward, any errors we just ignore, because - // it might simply be that the process doesn't exist anymore. - pid, err := strconv.ParseInt(name, 10, 0) - if err != nil { - continue - } - - p, err := newUnixProcess(int(pid)) - if err != nil { - continue - } - - results = append(results, p) - } - } - - return results, nil -} - -func newUnixProcess(pid int) (*UnixProcess, error) { - p := &UnixProcess{pid: pid} - return p, p.Refresh() -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_windows.go b/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_windows.go deleted file mode 100644 index f151974e3..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/process_windows.go +++ /dev/null @@ -1,119 +0,0 @@ -// +build windows - -package ps - -import ( - "fmt" - "syscall" - "unsafe" -) - -// Windows API functions -var ( - modKernel32 = syscall.NewLazyDLL("kernel32.dll") - procCloseHandle = modKernel32.NewProc("CloseHandle") - procCreateToolhelp32Snapshot = modKernel32.NewProc("CreateToolhelp32Snapshot") - procProcess32First = modKernel32.NewProc("Process32FirstW") - procProcess32Next = modKernel32.NewProc("Process32NextW") -) - -// Some constants from the Windows API -const ( - ERROR_NO_MORE_FILES = 0x12 - MAX_PATH = 260 -) - -// PROCESSENTRY32 is the Windows API structure that contains a process's -// information. -type PROCESSENTRY32 struct { - Size uint32 - CntUsage uint32 - ProcessID uint32 - DefaultHeapID uintptr - ModuleID uint32 - CntThreads uint32 - ParentProcessID uint32 - PriorityClassBase int32 - Flags uint32 - ExeFile [MAX_PATH]uint16 -} - -// WindowsProcess is an implementation of Process for Windows. -type WindowsProcess struct { - pid int - ppid int - exe string -} - -func (p *WindowsProcess) Pid() int { - return p.pid -} - -func (p *WindowsProcess) PPid() int { - return p.ppid -} - -func (p *WindowsProcess) Executable() string { - return p.exe -} - -func newWindowsProcess(e *PROCESSENTRY32) *WindowsProcess { - // Find when the string ends for decoding - end := 0 - for { - if e.ExeFile[end] == 0 { - break - } - end++ - } - - return &WindowsProcess{ - pid: int(e.ProcessID), - ppid: int(e.ParentProcessID), - exe: syscall.UTF16ToString(e.ExeFile[:end]), - } -} - -func findProcess(pid int) (Process, error) { - ps, err := processes() - if err != nil { - return nil, err - } - - for _, p := range ps { - if p.Pid() == pid { - return p, nil - } - } - - return nil, nil -} - -func processes() ([]Process, error) { - handle, _, _ := procCreateToolhelp32Snapshot.Call( - 0x00000002, - 0) - if handle < 0 { - return nil, syscall.GetLastError() - } - defer procCloseHandle.Call(handle) - - var entry PROCESSENTRY32 - entry.Size = uint32(unsafe.Sizeof(entry)) - ret, _, _ := procProcess32First.Call(handle, uintptr(unsafe.Pointer(&entry))) - if ret == 0 { - return nil, fmt.Errorf("Error retrieving process info.") - } - - results := make([]Process, 0, 50) - for { - results = append(results, newWindowsProcess(&entry)) - - ret, _, _ := procProcess32Next.Call(handle, uintptr(unsafe.Pointer(&entry))) - if ret == 0 { - break - } - } - - return results, nil -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/README.md b/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/README.md deleted file mode 100644 index 918b62aac..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/README.md +++ /dev/null @@ -1,4 +0,0 @@ -iso9660wrap -=========== -This turns the [iso9660wrap](https://github.com/johto/iso9660wrap) utility into a package. It provides a simple means to create an ISO9660 file containing a single file. - diff --git a/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/directories.go b/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/directories.go deleted file mode 100644 index 124cd188d..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/directories.go +++ /dev/null @@ -1,66 +0,0 @@ -package iso9660wrap - -import ( - "time" -) - -func WriteDirectoryRecord(w *SectorWriter, identifier string, firstSectorNum uint32) uint32 { - if len(identifier) > 30 { - Panicf("directory identifier length %d is out of bounds", len(identifier)) - } - recordLength := 33 + len(identifier) - - w.WriteByte(byte(recordLength)) - w.WriteByte(0) // number of sectors in extended attribute record - w.WriteBothEndianDWord(firstSectorNum) - w.WriteBothEndianDWord(SectorSize) // directory length - writeDirectoryRecordtimestamp(w, time.Now()) - w.WriteByte(byte(3)) // bitfield; directory - w.WriteByte(byte(0)) // file unit size for an interleaved file - w.WriteByte(byte(0)) // interleave gap size for an interleaved file - w.WriteBothEndianWord(1) // volume sequence number - w.WriteByte(byte(len(identifier))) - w.WriteString(identifier) - // optional padding to even length - if recordLength%2 == 1 { - recordLength++ - w.WriteByte(0) - } - return uint32(recordLength) -} - -func WriteFileRecordHeader(w *SectorWriter, identifier string, firstSectorNum uint32, fileSize uint32) uint32 { - if len(identifier) > 30 { - Panicf("directory identifier length %d is out of bounds", len(identifier)) - } - recordLength := 33 + len(identifier) - - w.WriteByte(byte(recordLength)) - w.WriteByte(0) // number of sectors in extended attribute record - w.WriteBothEndianDWord(firstSectorNum) // first sector - w.WriteBothEndianDWord(fileSize) - writeDirectoryRecordtimestamp(w, time.Now()) - w.WriteByte(byte(0)) // bitfield; normal file - w.WriteByte(byte(0)) // file unit size for an interleaved file - w.WriteByte(byte(0)) // interleave gap size for an interleaved file - w.WriteBothEndianWord(1) // volume sequence number - w.WriteByte(byte(len(identifier))) - w.WriteString(identifier) - // optional padding to even length - if recordLength%2 == 1 { - recordLength++ - w.WriteByte(0) - } - return uint32(recordLength) -} - -func writeDirectoryRecordtimestamp(w *SectorWriter, t time.Time) { - t = t.UTC() - w.WriteByte(byte(t.Year() - 1900)) - w.WriteByte(byte(t.Month())) - w.WriteByte(byte(t.Day())) - w.WriteByte(byte(t.Hour())) - w.WriteByte(byte(t.Minute())) - w.WriteByte(byte(t.Second())) - w.WriteByte(0) // UTC offset -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/iso9660_writer.go b/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/iso9660_writer.go deleted file mode 100644 index 88594669f..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/iso9660_writer.go +++ /dev/null @@ -1,148 +0,0 @@ -package iso9660wrap - -import ( - "encoding/binary" - "io" - "math" - "strings" - "time" -) - -const SectorSize uint32 = 2048 - -type SectorWriter struct { - w io.Writer - p uint32 -} - -func (w *SectorWriter) Write(p []byte) uint32 { - if len(p) >= math.MaxUint32 { - Panicf("attempted write of length %d is out of sector bounds", len(p)) - } - l := uint32(len(p)) - if l > w.RemainingSpace() { - Panicf("attempted write of length %d at offset %d is out of sector bounds", w.p, len(p)) - } - w.p += l - _, err := w.w.Write(p) - if err != nil { - panic(err) - } - return l -} - -func (w *SectorWriter) WriteUnspecifiedDateTime() uint32 { - b := make([]byte, 17) - for i := 0; i < 16; i++ { - b[i] = '0' - } - b[16] = 0 - return w.Write(b) -} - -func (w *SectorWriter) WriteDateTime(t time.Time) uint32 { - f := t.UTC().Format("20060102150405") - f += "00" // 1/100 - f += "\x00" // UTC offset - if len(f) != 17 { - Panicf("date and time field %q is of unexpected length %d", f, len(f)) - } - return w.WriteString(f) -} - -func (w *SectorWriter) WriteString(str string) uint32 { - return w.Write([]byte(str)) -} - -func (w *SectorWriter) WritePaddedString(str string, length uint32) uint32 { - l := w.WriteString(str) - if l > 32 { - Panicf("padded string %q exceeds length %d", str, length) - } else if l < 32 { - w.WriteString(strings.Repeat(" ", int(32-l))) - } - return 32 -} - -func (w *SectorWriter) WriteByte(b byte) uint32 { - return w.Write([]byte{b}) -} - -func (w *SectorWriter) WriteWord(bo binary.ByteOrder, word uint16) uint32 { - b := make([]byte, 2) - bo.PutUint16(b, word) - return w.Write(b) -} - -func (w *SectorWriter) WriteBothEndianWord(word uint16) uint32 { - w.WriteWord(binary.LittleEndian, word) - w.WriteWord(binary.BigEndian, word) - return 4 -} - -func (w *SectorWriter) WriteDWord(bo binary.ByteOrder, dword uint32) uint32 { - b := make([]byte, 4) - bo.PutUint32(b, dword) - return w.Write(b) -} - -func (w *SectorWriter) WriteLittleEndianDWord(dword uint32) uint32 { - return w.WriteDWord(binary.LittleEndian, dword) -} - -func (w *SectorWriter) WriteBigEndianDWord(dword uint32) uint32 { - return w.WriteDWord(binary.BigEndian, dword) -} - -func (w *SectorWriter) WriteBothEndianDWord(dword uint32) uint32 { - w.WriteLittleEndianDWord(dword) - w.WriteBigEndianDWord(dword) - return 8 -} - -func (w *SectorWriter) WriteZeros(c int) uint32 { - return w.Write(make([]byte, c)) -} - -func (w *SectorWriter) PadWithZeros() uint32 { - return w.Write(make([]byte, w.RemainingSpace())) -} - -func (w *SectorWriter) RemainingSpace() uint32 { - return SectorSize - w.p -} - -func (w *SectorWriter) Reset() { - w.p = 0 -} - -type ISO9660Writer struct { - sw *SectorWriter - sectorNum uint32 -} - -func (w *ISO9660Writer) CurrentSector() uint32 { - return uint32(w.sectorNum) -} - -func (w *ISO9660Writer) NextSector() *SectorWriter { - if w.sw.RemainingSpace() == SectorSize { - Panicf("internal error: tried to leave sector %d empty", w.sectorNum) - } - w.sw.PadWithZeros() - w.sw.Reset() - w.sectorNum++ - return w.sw -} - -func (w *ISO9660Writer) Finish() { - if w.sw.RemainingSpace() != SectorSize { - w.sw.PadWithZeros() - } - w.sw = nil -} - -func NewISO9660Writer(w io.Writer) *ISO9660Writer { - // start at the end of the last reserved sector - return &ISO9660Writer{&SectorWriter{w, SectorSize}, 16 - 1} -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/iso9660wrap.go b/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/iso9660wrap.go deleted file mode 100644 index 7acf7f78f..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/iso9660wrap.go +++ /dev/null @@ -1,367 +0,0 @@ -package iso9660wrap - -import ( - "bufio" - "encoding/binary" - "fmt" - "io" - "math" - "os" - "strings" - "time" -) - -const reservedAreaData string = ` -Once upon a midnight dreary, while I pondered, weak and weary, -Over many a quaint and curious volume of forgotten lore— - While I nodded, nearly napping, suddenly there came a tapping, -As of some one gently rapping, rapping at my chamber door. -“’Tis some visitor,” I muttered, “tapping at my chamber door— - Only this and nothing more.” - - Ah, distinctly I remember it was in the bleak December; -And each separate dying ember wrought its ghost upon the floor. - Eagerly I wished the morrow;—vainly I had sought to borrow - From my books surcease of sorrow—sorrow for the lost Lenore— -For the rare and radiant maiden whom the angels name Lenore— - Nameless here for evermore. - - And the silken, sad, uncertain rustling of each purple curtain -Thrilled me—filled me with fantastic terrors never felt before; - So that now, to still the beating of my heart, I stood repeating - “’Tis some visitor entreating entrance at my chamber door— -Some late visitor entreating entrance at my chamber door;— - This it is and nothing more.” - - Presently my soul grew stronger; hesitating then no longer, -“Sir,” said I, “or Madam, truly your forgiveness I implore; - But the fact is I was napping, and so gently you came rapping, - And so faintly you came tapping, tapping at my chamber door, -That I scarce was sure I heard you”—here I opened wide the door;— - Darkness there and nothing more. - - Deep into that darkness peering, long I stood there wondering, fearing, -Doubting, dreaming dreams no mortal ever dared to dream before; - But the silence was unbroken, and the stillness gave no token, - And the only word there spoken was the whispered word, “Lenore?” -This I whispered, and an echo murmured back the word, “Lenore!”— - Merely this and nothing more. - - Back into the chamber turning, all my soul within me burning, -Soon again I heard a tapping somewhat louder than before. - “Surely,” said I, “surely that is something at my window lattice; - Let me see, then, what thereat is, and this mystery explore— -Let my heart be still a moment and this mystery explore;— - ’Tis the wind and nothing more!” - - Open here I flung the shutter, when, with many a flirt and flutter, -In there stepped a stately Raven of the saintly days of yore; - Not the least obeisance made he; not a minute stopped or stayed he; - But, with mien of lord or lady, perched above my chamber door— -Perched upon a bust of Pallas just above my chamber door— - Perched, and sat, and nothing more. - -Then this ebony bird beguiling my sad fancy into smiling, -By the grave and stern decorum of the countenance it wore, -“Though thy crest be shorn and shaven, thou,” I said, “art sure no craven, -Ghastly grim and ancient Raven wandering from the Nightly shore— -Tell me what thy lordly name is on the Night’s Plutonian shore!” - Quoth the Raven “Nevermore.” - - Much I marvelled this ungainly fowl to hear discourse so plainly, -Though its answer little meaning—little relevancy bore; - For we cannot help agreeing that no living human being - Ever yet was blessed with seeing bird above his chamber door— -Bird or beast upon the sculptured bust above his chamber door, - With such name as “Nevermore.” - - But the Raven, sitting lonely on the placid bust, spoke only -That one word, as if his soul in that one word he did outpour. - Nothing farther then he uttered—not a feather then he fluttered— - Till I scarcely more than muttered “Other friends have flown before— -On the morrow he will leave me, as my Hopes have flown before.” - Then the bird said “Nevermore.” - - Startled at the stillness broken by reply so aptly spoken, -“Doubtless,” said I, “what it utters is its only stock and store - Caught from some unhappy master whom unmerciful Disaster - Followed fast and followed faster till his songs one burden bore— -Till the dirges of his Hope that melancholy burden bore - Of ‘Never—nevermore’.” - - But the Raven still beguiling all my fancy into smiling, -Straight I wheeled a cushioned seat in front of bird, and bust and door; - Then, upon the velvet sinking, I betook myself to linking - Fancy unto fancy, thinking what this ominous bird of yore— -What this grim, ungainly, ghastly, gaunt, and ominous bird of yore - Meant in croaking “Nevermore.” - - This I sat engaged in guessing, but no syllable expressing -To the fowl whose fiery eyes now burned into my bosom’s core; - This and more I sat divining, with my head at ease reclining - On the cushion’s velvet lining that the lamp-light gloated o’er, -But whose velvet-violet lining with the lamp-light gloating o’er, - She shall press, ah, nevermore! - - Then, methought, the air grew denser, perfumed from an unseen censer -Swung by Seraphim whose foot-falls tinkled on the tufted floor. - “Wretch,” I cried, “thy God hath lent thee—by these angels he hath sent thee - Respite—respite and nepenthe from thy memories of Lenore; -Quaff, oh quaff this kind nepenthe and forget this lost Lenore!” - Quoth the Raven “Nevermore.” - - “Prophet!” said I, “thing of evil!—prophet still, if bird or devil!— -Whether Tempter sent, or whether tempest tossed thee here ashore, - Desolate yet all undaunted, on this desert land enchanted— - On this home by Horror haunted—tell me truly, I implore— -Is there—is there balm in Gilead?—tell me—tell me, I implore!” - Quoth the Raven “Nevermore.” - - “Prophet!” said I, “thing of evil!—prophet still, if bird or devil! -By that Heaven that bends above us—by that God we both adore— - Tell this soul with sorrow laden if, within the distant Aidenn, - It shall clasp a sainted maiden whom the angels name Lenore— -Clasp a rare and radiant maiden whom the angels name Lenore.” - Quoth the Raven “Nevermore.” - - “Be that word our sign of parting, bird or fiend!” I shrieked, upstarting— -“Get thee back into the tempest and the Night’s Plutonian shore! - Leave no black plume as a token of that lie thy soul hath spoken! - Leave my loneliness unbroken!—quit the bust above my door! -Take thy beak from out my heart, and take thy form from off my door!” - Quoth the Raven “Nevermore.” - - And the Raven, never flitting, still is sitting, still is sitting -On the pallid bust of Pallas just above my chamber door; - And his eyes have all the seeming of a demon’s that is dreaming, - And the lamp-light o’er him streaming throws his shadow on the floor; -And my soul from out that shadow that lies floating on the floor - Shall be lifted—nevermore! -` - -func Panicf(format string, v ...interface{}) { - panic(fmt.Errorf(format, v...)) -} - -const volumeDescriptorSetMagic = "\x43\x44\x30\x30\x31\x01" - -const primaryVolumeSectorNum uint32 = 16 -const numVolumeSectors uint32 = 2 // primary + terminator -const littleEndianPathTableSectorNum uint32 = primaryVolumeSectorNum + numVolumeSectors -const bigEndianPathTableSectorNum uint32 = littleEndianPathTableSectorNum + 1 -const numPathTableSectors = 2 // no secondaries -const rootDirectorySectorNum uint32 = primaryVolumeSectorNum + numVolumeSectors + numPathTableSectors - -// WriteFile writes the contents of infh to an iso at outfh with the name provided -func WriteFile(outfh, infh *os.File) error { - inputFileSize, inputFilename, err := getInputFileSizeAndName(infh) - if err != nil { - return err - } - if inputFileSize == 0 { - return fmt.Errorf("input file must be at least 1 byte in size") - } - inputFilename = strings.ToUpper(inputFilename) - if !filenameSatisfiesISOConstraints(inputFilename) { - return fmt.Errorf("Input file name %s does not satisfy the ISO9660 character set constraints", inputFilename) - } - - // reserved sectors - reservedAreaLength := int64(16 * SectorSize) - _, err = outfh.Write([]byte(reservedAreaData)) - if err != nil { - return fmt.Errorf("could not write to output file: %s", err) - } - err = outfh.Truncate(reservedAreaLength) - if err != nil { - return fmt.Errorf("could not truncate output file: %s", err) - } - _, err = outfh.Seek(reservedAreaLength, os.SEEK_SET) - if err != nil { - return fmt.Errorf("could not seek output file: %s", err) - } - - err = nil - func() { - defer func() { - var ok bool - e := recover() - if e != nil { - err, ok = e.(error) - if !ok { - panic(e) - } - } - }() - - bufw := bufio.NewWriter(outfh) - - w := NewISO9660Writer(bufw) - - writePrimaryVolumeDescriptor(w, inputFileSize, inputFilename) - writeVolumeDescriptorSetTerminator(w) - writePathTable(w, binary.LittleEndian) - writePathTable(w, binary.BigEndian) - writeData(w, infh, inputFileSize, inputFilename) - - w.Finish() - - err := bufw.Flush() - if err != nil { - panic(err) - } - }() - if err != nil { - return fmt.Errorf("could not write to output file: %s", err) - } - return nil -} - -func writePrimaryVolumeDescriptor(w *ISO9660Writer, inputFileSize uint32, inputFilename string) { - if len(inputFilename) > 32 { - inputFilename = inputFilename[:32] - } - now := time.Now() - - sw := w.NextSector() - if w.CurrentSector() != primaryVolumeSectorNum { - Panicf("internal error: unexpected primary volume sector %d", w.CurrentSector()) - } - - sw.WriteByte('\x01') - sw.WriteString(volumeDescriptorSetMagic) - sw.WriteByte('\x00') - - sw.WritePaddedString("", 32) - sw.WritePaddedString(inputFilename, 32) - - sw.WriteZeros(8) - sw.WriteBothEndianDWord(numTotalSectors(inputFileSize)) - sw.WriteZeros(32) - - sw.WriteBothEndianWord(1) // volume set size - sw.WriteBothEndianWord(1) // volume sequence number - sw.WriteBothEndianWord(uint16(SectorSize)) - sw.WriteBothEndianDWord(SectorSize) // path table length - - sw.WriteLittleEndianDWord(littleEndianPathTableSectorNum) - sw.WriteLittleEndianDWord(0) // no secondary path tables - sw.WriteBigEndianDWord(bigEndianPathTableSectorNum) - sw.WriteBigEndianDWord(0) // no secondary path tables - - WriteDirectoryRecord(sw, "\x00", rootDirectorySectorNum) // root directory - - sw.WritePaddedString("", 128) // volume set identifier - sw.WritePaddedString("", 128) // publisher identifier - sw.WritePaddedString("", 128) // data preparer identifier - sw.WritePaddedString("", 128) // application identifier - - sw.WritePaddedString("", 37) // copyright file identifier - sw.WritePaddedString("", 37) // abstract file identifier - sw.WritePaddedString("", 37) // bibliographical file identifier - - sw.WriteDateTime(now) // volume creation - sw.WriteDateTime(now) // most recent modification - sw.WriteUnspecifiedDateTime() // expires - sw.WriteUnspecifiedDateTime() // is effective (?) - - sw.WriteByte('\x01') // version - sw.WriteByte('\x00') // reserved - - sw.PadWithZeros() // 512 (reserved for app) + 653 (zeros) -} - -func writeVolumeDescriptorSetTerminator(w *ISO9660Writer) { - sw := w.NextSector() - if w.CurrentSector() != primaryVolumeSectorNum+1 { - Panicf("internal error: unexpected volume descriptor set terminator sector %d", w.CurrentSector()) - } - - sw.WriteByte('\xFF') - sw.WriteString(volumeDescriptorSetMagic) - - sw.PadWithZeros() -} - -func writePathTable(w *ISO9660Writer, bo binary.ByteOrder) { - sw := w.NextSector() - sw.WriteByte(1) // name length - sw.WriteByte(0) // number of sectors in extended attribute record - sw.WriteDWord(bo, rootDirectorySectorNum) - sw.WriteWord(bo, 1) // parent directory recno (root directory) - sw.WriteByte(0) // identifier (root directory) - sw.WriteByte(1) // padding - sw.PadWithZeros() -} - -func writeData(w *ISO9660Writer, infh io.Reader, inputFileSize uint32, inputFilename string) { - sw := w.NextSector() - if w.CurrentSector() != rootDirectorySectorNum { - Panicf("internal error: unexpected root directory sector %d", w.CurrentSector()) - } - - WriteDirectoryRecord(sw, "\x00", w.CurrentSector()) - WriteDirectoryRecord(sw, "\x01", rootDirectorySectorNum) - WriteFileRecordHeader(sw, inputFilename, w.CurrentSector()+1, inputFileSize) - - // Now stream the data. Note that the first buffer is never of SectorSize, - // since we've already filled a part of the sector. - b := make([]byte, SectorSize) - total := uint32(0) - for { - l, err := infh.Read(b) - if err != nil && err != io.EOF { - Panicf("could not read from input file: %s", err) - } - if l > 0 { - sw = w.NextSector() - sw.Write(b[:l]) - total += uint32(l) - } - if err == io.EOF { - break - } - } - if total != inputFileSize { - Panicf("input file size changed while the ISO file was being created (expected to read %d, read %d)", inputFileSize, total) - } else if w.CurrentSector() != numTotalSectors(inputFileSize)-1 { - Panicf("internal error: unexpected last sector number (expected %d, actual %d)", - numTotalSectors(inputFileSize)-1, w.CurrentSector()) - } -} - -func numTotalSectors(inputFileSize uint32) uint32 { - var numDataSectors uint32 - numDataSectors = (inputFileSize + (SectorSize - 1)) / SectorSize - return 1 + rootDirectorySectorNum + numDataSectors -} - -func getInputFileSizeAndName(fh *os.File) (uint32, string, error) { - fi, err := fh.Stat() - if err != nil { - return 0, "", err - } - if fi.Size() >= math.MaxUint32 { - return 0, "", fmt.Errorf("file size %d is too large", fi.Size()) - } - return uint32(fi.Size()), fi.Name(), nil -} - -func filenameSatisfiesISOConstraints(filename string) bool { - invalidCharacter := func(r rune) bool { - // According to ISO9660, only capital letters, digits, and underscores - // are permitted. Some sources say a dot is allowed as well. I'm too - // lazy to figure it out right now. - if r >= 'A' && r <= 'Z' { - return false - } else if r >= '0' && r <= '9' { - return false - } else if r == '_' { - return false - } else if r == '.' { - return false - } - return true - } - return strings.IndexFunc(filename, invalidCharacter) == -1 -} diff --git a/tools/infrakit.hyperkit/vendor/github.com/satori/go.uuid b/tools/infrakit.hyperkit/vendor/github.com/satori/go.uuid deleted file mode 160000 index b061729af..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/satori/go.uuid +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b061729afc07e77a8aa4fad0a2fd840958f1942a diff --git a/tools/infrakit.hyperkit/vendor/github.com/spf13/cobra b/tools/infrakit.hyperkit/vendor/github.com/spf13/cobra deleted file mode 160000 index 92ea23a83..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/spf13/cobra +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 92ea23a837e66f46ac9e7d04fa826602b7b0a42d diff --git a/tools/infrakit.hyperkit/vendor/github.com/spf13/pflag b/tools/infrakit.hyperkit/vendor/github.com/spf13/pflag deleted file mode 160000 index 9ff6c6923..000000000 --- a/tools/infrakit.hyperkit/vendor/github.com/spf13/pflag +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9ff6c6923cfffbcd502984b8e0c80539a94968b7 diff --git a/vendor.conf b/vendor.conf index 3dbfe3cbe..1c766a3fd 100644 --- a/vendor.conf +++ b/vendor.conf @@ -1,6 +1,17 @@ github.com/docker/hyperkit/go 874e68dbb7a2a7a2794dbd8648c2f4be1e7a8bb3 github.com/googleapis/gax-go 8c5154c0fe5bf18cf649634d4c6df50897a32751 github.com/golang/protobuf/proto c9c7427a2a70d2eb3bafa0ab2dc163e45f143317 +github.com/Masterminds/semver 312afcd0e81e5cf81fdc3cfd0e8504ae031521c8 +github.com/Masterminds/sprig 01a849f546a584d7b29bfee253e7db0aed44f7ba +github.com/Sirupsen/logrus 10f801ebc38b33738c9d17d50860f484a0988ff5 +github.com/aokoli/goutils 9c37978a95bd5c709a15883b6242714ea6709e64 +github.com/armon/go-radix 4239b77079c7b5d1243b7b4736304ce8ddb6f0f2 +github.com/docker/infrakit 208d114478ed94ee9015083e13946ca1caaad790 +github.com/gorilla/context 08b5f424b9271eedf6f9f0ce86cb9396ed337a42 +github.com/gorilla/mux 599cba5e7b6137d46ddf58fb1765f5d928e69604 +github.com/gorilla/rpc 22c016f3df3febe0c1f6727598b6389507e03a18 +github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 +github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d github.com/mitchellh/go-ps 4fdf99ab29366514c69ccccddab5dc58b8d84062 github.com/rneugeba/iso9660wrap 9c7eaf5ac74b2416be8b7b8d1f35b9af44a6e4fa github.com/surma/gocpio fcb68777e7dc4ea43ffce871b552c0d073c17495 @@ -10,3 +21,9 @@ golang.org/x/oauth2 1611bb46e67abc64a71ecc5c3ae67f1cbbc2b921 google.golang.org/api 1202890e803f07684581b575fda809bf335a533f google.golang.org/grpc 0713829b980f4ddd276689a36235c5fcc82a21bf gopkg.in/yaml.v2 a3f3340b5840cee44f372bddb5880fcbc419b46a +github.com/satori/go.uuid b061729afc07e77a8aa4fad0a2fd840958f1942a +github.com/spf13/cobra 7be4beda01ec05d0b93d80b3facd2b6f44080d94 +github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7 +golang.org/x/crypto 459e26527287adbc2adcc5d0d49abff9a5f315a7 +golang.org/x/sys 99f16d856c9836c42d24e7ab64ea72916925fa97 +gopkg.in/tylerb/graceful.v1 4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb diff --git a/tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/LICENSE.txt b/vendor/github.com/Masterminds/semver/LICENSE.txt similarity index 100% rename from tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/LICENSE.txt rename to vendor/github.com/Masterminds/semver/LICENSE.txt diff --git a/tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/README.md b/vendor/github.com/Masterminds/semver/README.md similarity index 100% rename from tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/README.md rename to vendor/github.com/Masterminds/semver/README.md diff --git a/tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/collection.go b/vendor/github.com/Masterminds/semver/collection.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/collection.go rename to vendor/github.com/Masterminds/semver/collection.go diff --git a/tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/constraints.go b/vendor/github.com/Masterminds/semver/constraints.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/constraints.go rename to vendor/github.com/Masterminds/semver/constraints.go diff --git a/tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/doc.go b/vendor/github.com/Masterminds/semver/doc.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/doc.go rename to vendor/github.com/Masterminds/semver/doc.go diff --git a/tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/version.go b/vendor/github.com/Masterminds/semver/version.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/github.com/Masterminds/semver/version.go rename to vendor/github.com/Masterminds/semver/version.go diff --git a/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/LICENSE b/vendor/github.com/Masterminds/sprig/LICENSE.txt similarity index 86% rename from tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/LICENSE rename to vendor/github.com/Masterminds/sprig/LICENSE.txt index 8a6914999..5c95accc2 100644 --- a/tools/infrakit.hyperkit/vendor/github.com/rneugeba/iso9660wrap/LICENSE +++ b/vendor/github.com/Masterminds/sprig/LICENSE.txt @@ -1,6 +1,5 @@ -The MIT License (MIT) - -Copyright (c) 2015 Marko Tiikkaja +Sprig +Copyright (C) 2013 Masterminds Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -9,13 +8,13 @@ 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 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. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/Masterminds/sprig/README.md b/vendor/github.com/Masterminds/sprig/README.md new file mode 100644 index 000000000..097f1c1b6 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/README.md @@ -0,0 +1,311 @@ +# Sprig: Template functions for Go templates + +The Go language comes with a [built-in template +language](http://golang.org/pkg/text/template/), but not +very many template functions. This library provides a group of commonly +used template functions. + +It is inspired by the template functions found in +[Twig](http://twig.sensiolabs.org/documentation). + +[![Build Status](https://travis-ci.org/Masterminds/sprig.svg?branch=master)](https://travis-ci.org/Masterminds/sprig) + +## Usage + +API documentation is available [at GoDoc.org](http://godoc.org/github.com/Masterminds/sprig), but +read on for standard usage. + +### Load the Sprig library + +To load the Sprig `FuncMap`: + +```go + +import ( + "github.com/Masterminds/sprig" + "html/template" +) + +// This example illustrates that the FuncMap *must* be set before the +// templates themselves are loaded. +tpl := template.Must( + template.New("base").Funcs(sprig.FuncMap()).ParseGlob("*.html") +) + + +``` + +### Call the functions inside of templates + +By convention, all functions are lowercase. This seems to follow the Go +idiom for template functions (as opposed to template methods, which are +TitleCase). + + +Example: + +``` +{{ "hello!" | upper | repeat 5 }} +``` + +Produces: + +``` +HELLO!HELLO!HELLO!HELLO!HELLO! +``` + +## Functions + +### Date Functions + +- date: Format a date, where a date is an integer type or a time.Time type, and + format is a time.Format formatting string. +- dateModify: Given a date, modify it with a duration: `date_modify "-1.5h" now`. If the duration doesn't +parse, it returns the time unaltered. See `time.ParseDuration` for info on duration strings. +- now: Current time.Time, for feeding into date-related functions. +- htmlDate: Format a date for use in the value field of an HTML "date" form element. +- dateInZone: Like date, but takes three arguments: format, timestamp, + timezone. +- htmlDateInZone: Like htmlDate, but takes two arguments: timestamp, + timezone. + +### String Functions + +- trim: strings.TrimSpace +- trimAll: strings.Trim, but with the argument order reversed `trimAll "$" "$5.00"` or `"$5.00 | trimAll "$"` +- trimSuffix: strings.TrimSuffix, but with the argument order reversed `trimSuffix "-" "5-"` +- trimPrefix: strings.TrimPrefix, but with the argument order reversed `trimPrefix "$" "$5"` +- upper: strings.ToUpper +- lower: strings.ToLower +- title: strings.Title +- repeat: strings.Repeat, but with the arguments switched: `repeat count str`. (This simplifies common pipelines) +- substr: Given string, start, and length, return a substr. +- nospace: Remove all spaces from a string. `h e l l o` becomes + `hello`. +- abbrev: Truncate a string with ellipses +- trunc: Truncate a string (no suffix). `trunc 5 "Hello World"` yields "hello". +- abbrevboth: Truncate both sides of a string with ellipses +- untitle: Remove title case +- intials: Given multiple words, return the first letter of each + word +- randAlphaNum: Generate a random alpha-numeric string +- randAlpha: Generate a random alphabetic string +- randAscii: Generate a random ASCII string, including symbols +- randNumeric: Generate a random numeric string +- wrap: Wrap text at the given column count +- wrapWith: Wrap text at the given column count, and with the given + string for a line terminator: `wrap 50 "\n\t" $string` +- contains: strings.Contains, but with the arguments switched: `contains "cat" "uncatch"`. (This simplifies common pipelines) +- hasPrefix: strings.hasPrefix, but with the arguments switched: `hasPrefix "cat" "catch"`. +- hasSuffix: strings.hasSuffix, but with the arguments switched: `hasSuffix "cat" "ducat"`. +- quote: Wrap strings in double quotes. `quote "a" "b"` returns `"a" + "b"` +- squote: Wrap strings in single quotes. +- cat: Concatenate strings, separating them by spaces. `cat $a $b $c`. +- indent: Indent a string using space characters. `indent 4 "foo\nbar"` produces " foo\n bar" +- replace: Replace an old with a new in a string: `$name | replace " " "-"` +- plural: Choose singular or plural based on length: `len $fish | plural + "one anchovy" "many anchovies"` +- uuidv4: Generate a UUID v4 string +- sha256sum: Generate a hex encoded sha256 hash of the input +- toString: Convert something to a string + +### String Slice Functions: + +- join: strings.Join, but as `join SEP SLICE` +- split: strings.Split, but as `split SEP STRING`. The results are returned + as a map with the indexes set to _N, where N is an integer starting from 0. + Use it like this: `{{$v := "foo/bar/baz" | split "/"}}{{$v._0}}` (Prints `foo`) +- splitList: strings.Split, but as `split SEP STRING`. The results are returned + as an array. +- toStrings: convert a list to a list of strings. 'list 1 2 3 | toStrings' produces '["1" "2" "3"]' +- sortAlpha: sort a list lexicographically. + +### Integer Slice Functions: + +- until: Given an integer, returns a slice of counting integers from 0 to one + less than the given integer: `range $i, $e := until 5` +- untilStep: Given start, stop, and step, return an integer slice starting at + 'start', stopping at `stop`, and incrementing by 'step'. This is the same + as Python's long-form of 'range'. + +### Conversions: + +- atoi: Convert a string to an integer. 0 if the integer could not be parsed. +- int: Convert a string or numeric to an int +- int64: Convert a string or numeric to an int64 +- float64: Convert a string or numeric to a float64 + +### Defaults: + +- default: Give a default value. Used like this: {{trim " "| default "empty"}}. + Since trim produces an empty string, the default value is returned. For + things with a length (strings, slices, maps), len(0) will trigger the default. + For numbers, the value 0 will trigger the default. For booleans, false will + trigger the default. For structs, the default is never returned (there is + no clear empty condition). For everything else, nil value triggers a default. +- empty: Returns true if the given value is the zero value for that + type. Structs are always non-empty. +- coalesce: Given a list of items, return the first non-empty one. + This follows the same rules as 'empty'. `{{ coalesce .someVal 0 "hello" }}` + will return `.someVal` if set, or else return "hello". The 0 is skipped + because it is an empty value. +- compact: Return a copy of a list with all of the empty values removed. + `list 0 1 2 "" | compact` will return `[1 2]` + +### OS: + +- env: Read an environment variable. +- expandenv: Expand all environment variables in a string. + +### File Paths: +- base: Return the last element of a path. https://golang.org/pkg/path#Base +- dir: Remove the last element of a path. https://golang.org/pkg/path#Dir +- clean: Clean a path to the shortest equivalent name. (e.g. remove "foo/.." + from "foo/../bar.html") https://golang.org/pkg/path#Clean +- ext: Get the extension for a file path: https://golang.org/pkg/path#Ext +- isAbs: Returns true if a path is absolute: https://golang.org/pkg/path#IsAbs + +### Encoding: + +- b32enc: Encode a string into a Base32 string +- b32dec: Decode a string from a Base32 string +- b64enc: Encode a string into a Base64 string +- b64dec: Decode a string from a Base64 string + +### Data Structures: + +- tuple: Takes an arbitrary list of items and returns a slice of items. Its + tuple-ish properties are mainly gained through the template idiom, and not + through an API provided here. WARNING: The implementation of tuple will + change in the future. +- list: An arbitrary ordered list of items. (This is prefered over tuple.) +- dict: Takes a list of name/values and returns a map[string]interface{}. + The first parameter is converted to a string and stored as a key, the + second parameter is treated as the value. And so on, with odds as keys and + evens as values. If the function call ends with an odd, the last key will + be assigned the empty string. Non-string keys are converted to strings as + follows: []byte are converted, fmt.Stringers will have String() called. + errors will have Error() called. All others will be passed through + fmt.Sprtinf("%v"). _dicts are unordered_. + +List: + +``` +{{$t := list 1 "a" "foo"}} +{{index $t 2}}{{index $t 0 }}{{index $t 1}} +{{/* Prints foo1a *}} +``` + +Dict: +``` +{{ $t := map "key1" "value1" "key2" "value2" }} +{{ $t.key2 }} +{{ /* Prints value2 *}} +``` + + +### Lists Functions: + +These are used to manipulate lists: `{{ list 1 2 3 | reverse | first }}` + +- first: Get the first item in a 'list'. 'list 1 2 3 | first' prints '1' +- last: Get the last item in a 'list': 'list 1 2 3 | last ' prints '3' +- rest: Get all but the first item in a list: 'list 1 2 3 | rest' returns '[2 3]' +- initial: Get all but the last item in a list: 'list 1 2 3 | initial' returns '[1 2]' +- append: Add an item to the end of a list: 'append $list 4' adds '4' to the end of '$list' +- prepend: Add an item to the beginning of a list: 'prepend $list 4' puts 4 at the beginning of the list. +- reverse: Reverse the items in a list. +- uniq: Remove duplicates from a list. +- without: Return a list with the given values removed: 'without (list 1 2 3) 1' would return '[2 3]' +- has: Return 'tru' if the item is found in the list: 'has "foo" $list' will return 'true' if the list contains "foo" + +### Dict Functions: + +These are used to manipulate dicts. + +- set: Takes a dict, a key, and a value, and sets that key/value pair in + the dict. `set $dict $key $value`. For convenience, it returns the dict, + even though the dict was modified in place. +- unset: Takes a dict and a key, and deletes that key/value pair from the + dict. `unset $dict $key`. This returns the dict for convenience. +- hasKey: Takes a dict and a key, and returns boolean true if the key is in + the dict. +- pluck: Given a key and one or more maps, get all of the values for that key. +- keys: Get an array of all of the keys in a dict. Order is not guaranteed. +- pick: Select just the given keys out of the dict, and return a new dict. +- omit: Return a dict without the given keys. + +### Reflection: + +- typeOf: Takes an interface and returns a string representation of the type. + For pointers, this will return a type prefixed with an asterisk(`*`). So + a pointer to type `Foo` will be `*Foo`. +- typeIs: Compares an interface with a string name, and returns true if they match. + Note that a pointer will not match a reference. For example `*Foo` will not + match `Foo`. +- typeIsLike: returns true if the interface is of the given type, or + is a pointer to the given type. +- kindOf: Takes an interface and returns a string representation of its kind. +- kindIs: Returns true if the given string matches the kind of the given interface. + + Note: None of these can test whether or not something implements a given + interface, since doing so would require compiling the interface in ahead of + time. + + +### Math Functions: + +Integer functions will convert integers of any width to `int64`. If a +string is passed in, functions will attempt to conver with +`strconv.ParseInt(s, 1064)`. If this fails, the value will be treated as 0. + +- add1: Increment an integer by 1 +- add: Sum integers. `add 1 2 3` renders `6` +- sub: Subtract the second integer from the first +- div: Divide the first integer by the second +- mod: Module of first integer divided by second +- mul: Multiply integers integers +- max (biggest): Return the biggest of a series of integers. `max 1 2 3` + returns `3`. +- min: Return the smallest of a series of integers. `min 1 2 3` returns + `1`. + +### Cryptographic Functions: + +- derivePassword: Derive a password from the given parameters according to the "Master Password" algorithm (http://masterpasswordapp.com/algorithm.html) + Given parameters (in order) are: + `counter` (starting with 1), `password_type` (maximum, long, medium, short, basic, or pin), `password`, + `user`, and `site`. The following line generates a long password for the user "user" and with a master-password "password" on the site "example.com": + ``` + {{ derivePassword 1 "long" "password" "user" "example.com" }} + ``` + +## SemVer Functions: + +These functions provide version parsing and comparisons for SemVer 2 version +strings. + +- semver: Parse a semantic version and return a Version object. +- semverCompare: Compare a SemVer range to a particular version. + +## Principles: + +The following principles were used in deciding on which functions to add, and +determining how to implement them. + +- Template functions should be used to build layout. Therefore, the following + types of operations are within the domain of template functions: + - Formatting + - Layout + - Simple type conversions + - Utilities that assist in handling common formatting and layout needs (e.g. arithmetic) +- Template functions should not return errors unless there is no way to print + a sensible value. For example, converting a string to an integer should not + produce an error if conversion fails. Instead, it should display a default + value that can be displayed. +- Simple math is necessary for grid layouts, pagers, and so on. Complex math + (anything other than arithmetic) should be done outside of templates. +- Template functions only deal with the data passed into them. They never retrieve + data from a source. +- Finally, do not override core Go template functions. diff --git a/vendor/github.com/Masterminds/sprig/crypto.go b/vendor/github.com/Masterminds/sprig/crypto.go new file mode 100644 index 000000000..a935b6c1a --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/crypto.go @@ -0,0 +1,148 @@ +package sprig + +import ( + "bytes" + "crypto/dsa" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/hmac" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/asn1" + "encoding/binary" + "encoding/hex" + "encoding/pem" + "fmt" + "math/big" + + uuid "github.com/satori/go.uuid" + "golang.org/x/crypto/scrypt" +) + +func sha256sum(input string) string { + hash := sha256.Sum256([]byte(input)) + return hex.EncodeToString(hash[:]) +} + +// uuidv4 provides a safe and secure UUID v4 implementation +func uuidv4() string { + return fmt.Sprintf("%s", uuid.NewV4()) +} + +var master_password_seed = "com.lyndir.masterpassword" + +var password_type_templates = map[string][][]byte{ + "maximum": {[]byte("anoxxxxxxxxxxxxxxxxx"), []byte("axxxxxxxxxxxxxxxxxno")}, + "long": {[]byte("CvcvnoCvcvCvcv"), []byte("CvcvCvcvnoCvcv"), []byte("CvcvCvcvCvcvno"), []byte("CvccnoCvcvCvcv"), []byte("CvccCvcvnoCvcv"), + []byte("CvccCvcvCvcvno"), []byte("CvcvnoCvccCvcv"), []byte("CvcvCvccnoCvcv"), []byte("CvcvCvccCvcvno"), []byte("CvcvnoCvcvCvcc"), + []byte("CvcvCvcvnoCvcc"), []byte("CvcvCvcvCvccno"), []byte("CvccnoCvccCvcv"), []byte("CvccCvccnoCvcv"), []byte("CvccCvccCvcvno"), + []byte("CvcvnoCvccCvcc"), []byte("CvcvCvccnoCvcc"), []byte("CvcvCvccCvccno"), []byte("CvccnoCvcvCvcc"), []byte("CvccCvcvnoCvcc"), + []byte("CvccCvcvCvccno")}, + "medium": {[]byte("CvcnoCvc"), []byte("CvcCvcno")}, + "short": {[]byte("Cvcn")}, + "basic": {[]byte("aaanaaan"), []byte("aannaaan"), []byte("aaannaaa")}, + "pin": {[]byte("nnnn")}, +} + +var template_characters = map[byte]string{ + 'V': "AEIOU", + 'C': "BCDFGHJKLMNPQRSTVWXYZ", + 'v': "aeiou", + 'c': "bcdfghjklmnpqrstvwxyz", + 'A': "AEIOUBCDFGHJKLMNPQRSTVWXYZ", + 'a': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz", + 'n': "0123456789", + 'o': "@&%?,=[]_:-+*$#!'^~;()/.", + 'x': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()", +} + +func derivePassword(counter uint32, password_type, password, user, site string) string { + var templates = password_type_templates[password_type] + if templates == nil { + return fmt.Sprintf("cannot find password template %s", password_type) + } + + var buffer bytes.Buffer + buffer.WriteString(master_password_seed) + binary.Write(&buffer, binary.BigEndian, uint32(len(user))) + buffer.WriteString(user) + + salt := buffer.Bytes() + key, err := scrypt.Key([]byte(password), salt, 32768, 8, 2, 64) + if err != nil { + return fmt.Sprintf("failed to derive password: %s", err) + } + + buffer.Truncate(len(master_password_seed)) + binary.Write(&buffer, binary.BigEndian, uint32(len(site))) + buffer.WriteString(site) + binary.Write(&buffer, binary.BigEndian, counter) + + var hmacv = hmac.New(sha256.New, key) + hmacv.Write(buffer.Bytes()) + var seed = hmacv.Sum(nil) + var temp = templates[int(seed[0])%len(templates)] + + buffer.Truncate(0) + for i, element := range temp { + pass_chars := template_characters[element] + pass_char := pass_chars[int(seed[i+1])%len(pass_chars)] + buffer.WriteByte(pass_char) + } + + return buffer.String() +} + +func generatePrivateKey(typ string) string { + var priv interface{} + var err error + switch typ { + case "", "rsa": + // good enough for government work + priv, err = rsa.GenerateKey(rand.Reader, 4096) + case "dsa": + key := new(dsa.PrivateKey) + // again, good enough for government work + if err = dsa.GenerateParameters(&key.Parameters, rand.Reader, dsa.L2048N256); err != nil { + return fmt.Sprintf("failed to generate dsa params: %s", err) + } + err = dsa.GenerateKey(key, rand.Reader) + priv = key + case "ecdsa": + // again, good enough for government work + priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + default: + return "Unknown type " + typ + } + if err != nil { + return fmt.Sprintf("failed to generate private key: %s", err) + } + + return string(pem.EncodeToMemory(pemBlockForKey(priv))) +} + +type DSAKeyFormat struct { + Version int + P, Q, G, Y, X *big.Int +} + +func pemBlockForKey(priv interface{}) *pem.Block { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} + case *dsa.PrivateKey: + val := DSAKeyFormat{ + P: k.P, Q: k.Q, G: k.G, + Y: k.Y, X: k.X, + } + bytes, _ := asn1.Marshal(val) + return &pem.Block{Type: "DSA PRIVATE KEY", Bytes: bytes} + case *ecdsa.PrivateKey: + b, _ := x509.MarshalECPrivateKey(k) + return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} + default: + return nil + } +} diff --git a/vendor/github.com/Masterminds/sprig/date.go b/vendor/github.com/Masterminds/sprig/date.go new file mode 100644 index 000000000..dc5263f24 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/date.go @@ -0,0 +1,53 @@ +package sprig + +import ( + "time" +) + +// Given a format and a date, format the date string. +// +// Date can be a `time.Time` or an `int, int32, int64`. +// In the later case, it is treated as seconds since UNIX +// epoch. +func date(fmt string, date interface{}) string { + return dateInZone(fmt, date, "Local") +} + +func htmlDate(date interface{}) string { + return dateInZone("2006-01-02", date, "Local") +} + +func htmlDateInZone(date interface{}, zone string) string { + return dateInZone("2006-01-02", date, zone) +} + +func dateInZone(fmt string, date interface{}, zone string) string { + var t time.Time + switch date := date.(type) { + default: + t = time.Now() + case time.Time: + t = date + case int64: + t = time.Unix(date, 0) + case int: + t = time.Unix(int64(date), 0) + case int32: + t = time.Unix(int64(date), 0) + } + + loc, err := time.LoadLocation(zone) + if err != nil { + loc, _ = time.LoadLocation("UTC") + } + + return t.In(loc).Format(fmt) +} + +func dateModify(fmt string, date time.Time) time.Time { + d, err := time.ParseDuration(fmt) + if err != nil { + return date + } + return date.Add(d) +} diff --git a/vendor/github.com/Masterminds/sprig/defaults.go b/vendor/github.com/Masterminds/sprig/defaults.go new file mode 100644 index 000000000..9892f07ed --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/defaults.go @@ -0,0 +1,62 @@ +package sprig + +import ( + "reflect" +) + +// dfault checks whether `given` is set, and returns default if not set. +// +// This returns `d` if `given` appears not to be set, and `given` otherwise. +// +// For numeric types 0 is unset. +// For strings, maps, arrays, and slices, len() = 0 is considered unset. +// For bool, false is unset. +// Structs are never considered unset. +// +// For everything else, including pointers, a nil value is unset. +func dfault(d interface{}, given ...interface{}) interface{} { + + if empty(given) || empty(given[0]) { + return d + } + return given[0] +} + +// empty returns true if the given value has the zero value for its type. +func empty(given interface{}) bool { + g := reflect.ValueOf(given) + if !g.IsValid() { + return true + } + + // Basically adapted from text/template.isTrue + switch g.Kind() { + default: + return g.IsNil() + case reflect.Array, reflect.Slice, reflect.Map, reflect.String: + return g.Len() == 0 + case reflect.Bool: + return g.Bool() == false + case reflect.Complex64, reflect.Complex128: + return g.Complex() == 0 + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return g.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return g.Uint() == 0 + case reflect.Float32, reflect.Float64: + return g.Float() == 0 + case reflect.Struct: + return false + } + return true +} + +// coalesce returns the first non-empty value. +func coalesce(v ...interface{}) interface{} { + for _, val := range v { + if !empty(val) { + return val + } + } + return nil +} diff --git a/vendor/github.com/Masterminds/sprig/dict.go b/vendor/github.com/Masterminds/sprig/dict.go new file mode 100644 index 000000000..d50e11c5c --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/dict.go @@ -0,0 +1,74 @@ +package sprig + +func set(d map[string]interface{}, key string, value interface{}) map[string]interface{} { + d[key] = value + return d +} + +func unset(d map[string]interface{}, key string) map[string]interface{} { + delete(d, key) + return d +} + +func hasKey(d map[string]interface{}, key string) bool { + _, ok := d[key] + return ok +} + +func pluck(key string, d ...map[string]interface{}) []interface{} { + res := []interface{}{} + for _, dict := range d { + if val, ok := dict[key]; ok { + res = append(res, val) + } + } + return res +} + +func keys(dict map[string]interface{}) []string { + k := []string{} + for key := range dict { + k = append(k, key) + } + return k +} + +func pick(dict map[string]interface{}, keys ...string) map[string]interface{} { + res := map[string]interface{}{} + for _, k := range keys { + if v, ok := dict[k]; ok { + res[k] = v + } + } + return res +} + +func omit(dict map[string]interface{}, keys ...string) map[string]interface{} { + res := map[string]interface{}{} + + omit := make(map[string]bool, len(keys)) + for _, k := range keys { + omit[k] = true + } + + for k, v := range dict { + if _, ok := omit[k]; !ok { + res[k] = v + } + } + return res +} + +func dict(v ...interface{}) map[string]interface{} { + dict := map[string]interface{}{} + lenv := len(v) + for i := 0; i < lenv; i += 2 { + key := strval(v[i]) + if i+1 >= lenv { + dict[key] = "" + continue + } + dict[key] = v[i+1] + } + return dict +} diff --git a/vendor/github.com/Masterminds/sprig/doc.go b/vendor/github.com/Masterminds/sprig/doc.go new file mode 100644 index 000000000..7ecb5e25d --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/doc.go @@ -0,0 +1,225 @@ +/* +Sprig: Template functions for Go. + +This package contains a number of utility functions for working with data +inside of Go `html/template` and `text/template` files. + +To add these functions, use the `template.Funcs()` method: + + t := templates.New("foo").Funcs(sprig.FuncMap()) + +Note that you should add the function map before you parse any template files. + + In several cases, Sprig reverses the order of arguments from the way they + appear in the standard library. This is to make it easier to pipe + arguments into functions. + +Date Functions + + - date FORMAT TIME: Format a date, where a date is an integer type or a time.Time type, and + format is a time.Format formatting string. + - dateModify: Given a date, modify it with a duration: `date_modify "-1.5h" now`. If the duration doesn't + parse, it returns the time unaltered. See `time.ParseDuration` for info on duration strings. + - now: Current time.Time, for feeding into date-related functions. + - htmlDate TIME: Format a date for use in the value field of an HTML "date" form element. + - dateInZone FORMAT TIME TZ: Like date, but takes three arguments: format, timestamp, + timezone. + - htmlDateInZone TIME TZ: Like htmlDate, but takes two arguments: timestamp, + timezone. + +String Functions + + - abbrev: Truncate a string with ellipses. `abbrev 5 "hello world"` yields "he..." + - abbrevboth: Abbreviate from both sides, yielding "...lo wo..." + - trunc: Truncate a string (no suffix). `trunc 5 "Hello World"` yields "hello". + - trim: strings.TrimSpace + - trimAll: strings.Trim, but with the argument order reversed `trimAll "$" "$5.00"` or `"$5.00 | trimAll "$"` + - trimSuffix: strings.TrimSuffix, but with the argument order reversed: `trimSuffix "-" "ends-with-"` + - trimPrefix: strings.TrimPrefix, but with the argument order reversed `trimPrefix "$" "$5"` + - upper: strings.ToUpper + - lower: strings.ToLower + - nospace: Remove all space characters from a string. `nospace "h e l l o"` becomes "hello" + - title: strings.Title + - untitle: Remove title casing + - repeat: strings.Repeat, but with the arguments switched: `repeat count str`. (This simplifies common pipelines) + - substr: Given string, start, and length, return a substr. + - initials: Given a multi-word string, return the initials. `initials "Matt Butcher"` returns "MB" + - randAlphaNum: Given a length, generate a random alphanumeric sequence + - randAlpha: Given a length, generate an alphabetic string + - randAscii: Given a length, generate a random ASCII string (symbols included) + - randNumeric: Given a length, generate a string of digits. + - wrap: Force a line wrap at the given width. `wrap 80 "imagine a longer string"` + - wrapWith: Wrap a line at the given length, but using 'sep' instead of a newline. `wrapWith 50, "
", $html` + - contains: strings.Contains, but with the arguments switched: `contains substr str`. (This simplifies common pipelines) + - hasPrefix: strings.hasPrefix, but with the arguments switched + - hasSuffix: strings.hasSuffix, but with the arguments switched + - quote: Wrap string(s) in double quotation marks, escape the contents by adding '\' before '"'. + - squote: Wrap string(s) in double quotation marks, does not escape content. + - cat: Concatenate strings, separating them by spaces. `cat $a $b $c`. + - indent: Indent a string using space characters. `indent 4 "foo\nbar"` produces " foo\n bar" + - replace: Replace an old with a new in a string: `$name | replace " " "-"` + - plural: Choose singular or plural based on length: `len $fish | plural "one anchovy" "many anchovies"` + - sha256sum: Generate a hex encoded sha256 hash of the input + - toString: Convert something to a string + +String Slice Functions: + + - join: strings.Join, but as `join SEP SLICE` + - split: strings.Split, but as `split SEP STRING`. The results are returned + as a map with the indexes set to _N, where N is an integer starting from 0. + Use it like this: `{{$v := "foo/bar/baz" | split "/"}}{{$v._0}}` (Prints `foo`) + - splitList: strings.Split, but as `split SEP STRING`. The results are returned + as an array. + - toStrings: convert a list to a list of strings. 'list 1 2 3 | toStrings' produces '["1" "2" "3"]' + - sortAlpha: sort a list lexicographically. + +Integer Slice Functions: + + - until: Given an integer, returns a slice of counting integers from 0 to one + less than the given integer: `range $i, $e := until 5` + - untilStep: Given start, stop, and step, return an integer slice starting at + 'start', stopping at `stop`, and incrementing by 'step. This is the same + as Python's long-form of 'range'. + +Conversions: + + - atoi: Convert a string to an integer. 0 if the integer could not be parsed. + - in64: Convert a string or another numeric type to an int64. + - int: Convert a string or another numeric type to an int. + - float64: Convert a string or another numeric type to a float64. + +Defaults: + + - default: Give a default value. Used like this: trim " "| default "empty". + Since trim produces an empty string, the default value is returned. For + things with a length (strings, slices, maps), len(0) will trigger the default. + For numbers, the value 0 will trigger the default. For booleans, false will + trigger the default. For structs, the default is never returned (there is + no clear empty condition). For everything else, nil value triggers a default. + - empty: Return true if the given value is the zero value for its type. + Caveats: structs are always non-empty. This should match the behavior of + {{if pipeline}}, but can be used inside of a pipeline. + - coalesce: Given a list of items, return the first non-empty one. + This follows the same rules as 'empty'. '{{ coalesce .someVal 0 "hello" }}` + will return `.someVal` if set, or else return "hello". The 0 is skipped + because it is an empty value. + - compact: Return a copy of a list with all of the empty values removed. + 'list 0 1 2 "" | compact' will return '[1 2]' + +OS: + - env: Resolve an environment variable + - expandenv: Expand a string through the environment + +File Paths: + - base: Return the last element of a path. https://golang.org/pkg/path#Base + - dir: Remove the last element of a path. https://golang.org/pkg/path#Dir + - clean: Clean a path to the shortest equivalent name. (e.g. remove "foo/.." + from "foo/../bar.html") https://golang.org/pkg/path#Clean + - ext: https://golang.org/pkg/path#Ext + - isAbs: https://golang.org/pkg/path#IsAbs + +Encoding: + - b64enc: Base 64 encode a string. + - b64dec: Base 64 decode a string. + +Reflection: + + - typeOf: Takes an interface and returns a string representation of the type. + For pointers, this will return a type prefixed with an asterisk(`*`). So + a pointer to type `Foo` will be `*Foo`. + - typeIs: Compares an interface with a string name, and returns true if they match. + Note that a pointer will not match a reference. For example `*Foo` will not + match `Foo`. + - typeIsLike: Compares an interface with a string name and returns true if + the interface is that `name` or that `*name`. In other words, if the given + value matches the given type or is a pointer to the given type, this returns + true. + - kindOf: Takes an interface and returns a string representation of its kind. + - kindIs: Returns true if the given string matches the kind of the given interface. + + Note: None of these can test whether or not something implements a given + interface, since doing so would require compiling the interface in ahead of + time. + +Data Structures: + + - tuple: Takes an arbitrary list of items and returns a slice of items. Its + tuple-ish properties are mainly gained through the template idiom, and not + through an API provided here. WARNING: The implementation of tuple will + change in the future. + - list: An arbitrary ordered list of items. (This is prefered over tuple.) + - dict: Takes a list of name/values and returns a map[string]interface{}. + The first parameter is converted to a string and stored as a key, the + second parameter is treated as the value. And so on, with odds as keys and + evens as values. If the function call ends with an odd, the last key will + be assigned the empty string. Non-string keys are converted to strings as + follows: []byte are converted, fmt.Stringers will have String() called. + errors will have Error() called. All others will be passed through + fmt.Sprtinf("%v"). + +Lists Functions: + +These are used to manipulate lists: '{{ list 1 2 3 | reverse | first }}' + + - first: Get the first item in a 'list'. 'list 1 2 3 | first' prints '1' + - last: Get the last item in a 'list': 'list 1 2 3 | last ' prints '3' + - rest: Get all but the first item in a list: 'list 1 2 3 | rest' returns '[2 3]' + - initial: Get all but the last item in a list: 'list 1 2 3 | initial' returns '[1 2]' + - append: Add an item to the end of a list: 'append $list 4' adds '4' to the end of '$list' + - prepend: Add an item to the beginning of a list: 'prepend $list 4' puts 4 at the beginning of the list. + - reverse: Reverse the items in a list. + - uniq: Remove duplicates from a list. + - without: Return a list with the given values removed: 'without (list 1 2 3) 1' would return '[2 3]' + - has: Return 'true' if the item is found in the list: 'has "foo" $list' will return 'true' if the list contains "foo" + +Dict Functions: + +These are used to manipulate dicts. + + - set: Takes a dict, a key, and a value, and sets that key/value pair in + the dict. `set $dict $key $value`. For convenience, it returns the dict, + even though the dict was modified in place. + - unset: Takes a dict and a key, and deletes that key/value pair from the + dict. `unset $dict $key`. This returns the dict for convenience. + - hasKey: Takes a dict and a key, and returns boolean true if the key is in + the dict. + - pluck: Given a key and one or more maps, get all of the values for that key. + - keys: Get an array of all of the keys in a dict. + - pick: Select just the given keys out of the dict, and return a new dict. + - omit: Return a dict without the given keys. + +Math Functions: + +Integer functions will convert integers of any width to `int64`. If a +string is passed in, functions will attempt to convert with +`strconv.ParseInt(s, 1064)`. If this fails, the value will be treated as 0. + + - add1: Increment an integer by 1 + - add: Sum an arbitrary number of integers + - sub: Subtract the second integer from the first + - div: Divide the first integer by the second + - mod: Module of first integer divided by second + - mul: Multiply integers + - max: Return the biggest of a series of one or more integers + - min: Return the smallest of a series of one or more integers + - biggest: DEPRECATED. Return the biggest of a series of one or more integers + +Crypto Functions: + + - genPrivateKey: Generate a private key for the given cryptosystem. If no + argument is supplied, by default it will generate a private key using + the RSA algorithm. Accepted values are `rsa`, `dsa`, and `ecdsa`. + - derivePassword: Derive a password from the given parameters according to the ["Master Password" algorithm](http://masterpasswordapp.com/algorithm.html) + Given parameters (in order) are: + `counter` (starting with 1), `password_type` (maximum, long, medium, short, basic, or pin), `password`, + `user`, and `site` + +SemVer Functions: + +These functions provide version parsing and comparisons for SemVer 2 version +strings. + + - semver: Parse a semantic version and return a Version object. + - semverCompare: Compare a SemVer range to a particular version. +*/ +package sprig diff --git a/vendor/github.com/Masterminds/sprig/functions.go b/vendor/github.com/Masterminds/sprig/functions.go new file mode 100644 index 000000000..be108360f --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/functions.go @@ -0,0 +1,250 @@ +package sprig + +import ( + "html/template" + "os" + "path" + "strconv" + "strings" + ttemplate "text/template" + "time" + + util "github.com/aokoli/goutils" +) + +// Produce the function map. +// +// Use this to pass the functions into the template engine: +// +// tpl := template.New("foo").Funcs(sprig.FuncMap())) +// +func FuncMap() template.FuncMap { + return HtmlFuncMap() +} + +// HermeticTextFuncMap returns a 'text/template'.FuncMap with only repeatable functions. +func HermeticTxtFuncMap() ttemplate.FuncMap { + r := TxtFuncMap() + for _, name := range nonhermeticFunctions { + delete(r, name) + } + return r +} + +// HermeticHtmlFuncMap returns an 'html/template'.Funcmap with only repeatable functions. +func HermeticHtmlFuncMap() template.FuncMap { + r := HtmlFuncMap() + for _, name := range nonhermeticFunctions { + delete(r, name) + } + return r +} + +// TextFuncMap returns a 'text/template'.FuncMap +func TxtFuncMap() ttemplate.FuncMap { + return ttemplate.FuncMap(GenericFuncMap()) +} + +// HtmlFuncMap returns an 'html/template'.Funcmap +func HtmlFuncMap() template.FuncMap { + return template.FuncMap(GenericFuncMap()) +} + +// GenericFuncMap returns a copy of the basic function map as a map[string]interface{}. +func GenericFuncMap() map[string]interface{} { + gfm := make(map[string]interface{}, len(genericMap)) + for k, v := range genericMap { + gfm[k] = v + } + return gfm +} + +// These functions are not guaranteed to evaluate to the same result for given input, because they +// refer to the environemnt or global state. +var nonhermeticFunctions = []string{ + // Date functions + "date", + "date_in_zone", + "date_modify", + "now", + "htmlDate", + "htmlDateInZone", + "dateInZone", + "dateModify", + + // Strings + "randAlphaNum", + "randAlpha", + "randAscii", + "randNumeric", + "uuidv4", + + // OS + "env", + "expandenv", +} + +var genericMap = map[string]interface{}{ + "hello": func() string { return "Hello!" }, + + // Date functions + "date": date, + "date_in_zone": dateInZone, + "date_modify": dateModify, + "now": func() time.Time { return time.Now() }, + "htmlDate": htmlDate, + "htmlDateInZone": htmlDateInZone, + "dateInZone": dateInZone, + "dateModify": dateModify, + + // Strings + "abbrev": abbrev, + "abbrevboth": abbrevboth, + "trunc": trunc, + "trim": strings.TrimSpace, + "upper": strings.ToUpper, + "lower": strings.ToLower, + "title": strings.Title, + "untitle": untitle, + "substr": substring, + // Switch order so that "foo" | repeat 5 + "repeat": func(count int, str string) string { return strings.Repeat(str, count) }, + // Deprecated: Use trimAll. + "trimall": func(a, b string) string { return strings.Trim(b, a) }, + // Switch order so that "$foo" | trimall "$" + "trimAll": func(a, b string) string { return strings.Trim(b, a) }, + "trimSuffix": func(a, b string) string { return strings.TrimSuffix(b, a) }, + "trimPrefix": func(a, b string) string { return strings.TrimPrefix(b, a) }, + "nospace": util.DeleteWhiteSpace, + "initials": initials, + "randAlphaNum": randAlphaNumeric, + "randAlpha": randAlpha, + "randAscii": randAscii, + "randNumeric": randNumeric, + "swapcase": util.SwapCase, + "wrap": func(l int, s string) string { return util.Wrap(s, l) }, + "wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) }, + // Switch order so that "foobar" | contains "foo" + "contains": func(substr string, str string) bool { return strings.Contains(str, substr) }, + "hasPrefix": func(substr string, str string) bool { return strings.HasPrefix(str, substr) }, + "hasSuffix": func(substr string, str string) bool { return strings.HasSuffix(str, substr) }, + "quote": quote, + "squote": squote, + "cat": cat, + "indent": indent, + "replace": replace, + "plural": plural, + "sha256sum": sha256sum, + "toString": strval, + + // Wrap Atoi to stop errors. + "atoi": func(a string) int { i, _ := strconv.Atoi(a); return i }, + "int64": toInt64, + "int": toInt, + "float64": toFloat64, + + //"gt": func(a, b int) bool {return a > b}, + //"gte": func(a, b int) bool {return a >= b}, + //"lt": func(a, b int) bool {return a < b}, + //"lte": func(a, b int) bool {return a <= b}, + + // split "/" foo/bar returns map[int]string{0: foo, 1: bar} + "split": split, + "splitList": func(sep, orig string) []string { return strings.Split(orig, sep) }, + "toStrings": strslice, + + "until": until, + "untilStep": untilStep, + + // VERY basic arithmetic. + "add1": func(i interface{}) int64 { return toInt64(i) + 1 }, + "add": func(i ...interface{}) int64 { + var a int64 = 0 + for _, b := range i { + a += toInt64(b) + } + return a + }, + "sub": func(a, b interface{}) int64 { return toInt64(a) - toInt64(b) }, + "div": func(a, b interface{}) int64 { return toInt64(a) / toInt64(b) }, + "mod": func(a, b interface{}) int64 { return toInt64(a) % toInt64(b) }, + "mul": func(a interface{}, v ...interface{}) int64 { + val := toInt64(a) + for _, b := range v { + val = val * toInt64(b) + } + return val + }, + "biggest": max, + "max": max, + "min": min, + + // string slices. Note that we reverse the order b/c that's better + // for template processing. + "join": join, + "sortAlpha": sortAlpha, + + // Defaults + "default": dfault, + "empty": empty, + "coalesce": coalesce, + "compact": compact, + + // Reflection + "typeOf": typeOf, + "typeIs": typeIs, + "typeIsLike": typeIsLike, + "kindOf": kindOf, + "kindIs": kindIs, + + // OS: + "env": func(s string) string { return os.Getenv(s) }, + "expandenv": func(s string) string { return os.ExpandEnv(s) }, + + // File Paths: + "base": path.Base, + "dir": path.Dir, + "clean": path.Clean, + "ext": path.Ext, + "isAbs": path.IsAbs, + + // Encoding: + "b64enc": base64encode, + "b64dec": base64decode, + "b32enc": base32encode, + "b32dec": base32decode, + + // Data Structures: + "tuple": list, // FIXME: with the addition of append/prepend these are no longer immutable. + "list": list, + "dict": dict, + "set": set, + "unset": unset, + "hasKey": hasKey, + "pluck": pluck, + "keys": keys, + "pick": pick, + "omit": omit, + + "append": push, "push": push, + "prepend": prepend, + "first": first, + "rest": rest, + "last": last, + "initial": initial, + "reverse": reverse, + "uniq": uniq, + "without": without, + "has": func(needle interface{}, haystack []interface{}) bool { return inList(haystack, needle) }, + + // Crypto: + "genPrivateKey": generatePrivateKey, + "derivePassword": derivePassword, + + // UUIDs: + "uuidv4": uuidv4, + + // SemVer: + "semver": semver, + "semverCompare": semverCompare, +} diff --git a/vendor/github.com/Masterminds/sprig/list.go b/vendor/github.com/Masterminds/sprig/list.go new file mode 100644 index 000000000..0c47b8c8a --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/list.go @@ -0,0 +1,109 @@ +package sprig + +import ( + "reflect" + "sort" +) + +func list(v ...interface{}) []interface{} { + return v +} + +func push(list []interface{}, v interface{}) []interface{} { + return append(list, v) +} + +func prepend(list []interface{}, v interface{}) []interface{} { + return append([]interface{}{v}, list...) +} + +func last(list []interface{}) interface{} { + l := len(list) + if l == 0 { + return nil + } + return list[l-1] +} + +func first(list []interface{}) interface{} { + if len(list) == 0 { + return nil + } + return list[0] +} + +func rest(list []interface{}) []interface{} { + if len(list) == 0 { + return list + } + return list[1:] +} + +func initial(list []interface{}) []interface{} { + l := len(list) + if l == 0 { + return list + } + return list[:l-1] +} + +func sortAlpha(list interface{}) []string { + k := reflect.Indirect(reflect.ValueOf(list)).Kind() + switch k { + case reflect.Slice, reflect.Array: + a := strslice(list) + s := sort.StringSlice(a) + s.Sort() + return s + } + return []string{strval(list)} +} + +func reverse(v []interface{}) []interface{} { + // We do not sort in place because the incomming array should not be altered. + l := len(v) + c := make([]interface{}, l) + for i := 0; i < l; i++ { + c[l-i-1] = v[i] + } + return c +} + +func compact(list []interface{}) []interface{} { + res := []interface{}{} + for _, item := range list { + if !empty(item) { + res = append(res, item) + } + } + return res +} + +func uniq(list []interface{}) []interface{} { + dest := []interface{}{} + for _, item := range list { + if !inList(dest, item) { + dest = append(dest, item) + } + } + return dest +} + +func inList(haystack []interface{}, needle interface{}) bool { + for _, h := range haystack { + if reflect.DeepEqual(needle, h) { + return true + } + } + return false +} + +func without(list []interface{}, omit ...interface{}) []interface{} { + res := []interface{}{} + for _, i := range list { + if !inList(omit, i) { + res = append(res, i) + } + } + return res +} diff --git a/vendor/github.com/Masterminds/sprig/numeric.go b/vendor/github.com/Masterminds/sprig/numeric.go new file mode 100644 index 000000000..191e3b97a --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/numeric.go @@ -0,0 +1,129 @@ +package sprig + +import ( + "math" + "reflect" + "strconv" +) + +// toFloat64 converts 64-bit floats +func toFloat64(v interface{}) float64 { + if str, ok := v.(string); ok { + iv, err := strconv.ParseFloat(str, 64) + if err != nil { + return 0 + } + return iv + } + + val := reflect.Indirect(reflect.ValueOf(v)) + switch val.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return float64(val.Int()) + case reflect.Uint8, reflect.Uint16, reflect.Uint32: + return float64(val.Uint()) + case reflect.Uint, reflect.Uint64: + return float64(val.Uint()) + case reflect.Float32, reflect.Float64: + return val.Float() + case reflect.Bool: + if val.Bool() == true { + return 1 + } + return 0 + default: + return 0 + } +} + +func toInt(v interface{}) int { + //It's not optimal. Bud I don't want duplicate toInt64 code. + return int(toInt64(v)) +} + +// toInt64 converts integer types to 64-bit integers +func toInt64(v interface{}) int64 { + if str, ok := v.(string); ok { + iv, err := strconv.ParseInt(str, 10, 64) + if err != nil { + return 0 + } + return iv + } + + val := reflect.Indirect(reflect.ValueOf(v)) + switch val.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return val.Int() + case reflect.Uint8, reflect.Uint16, reflect.Uint32: + return int64(val.Uint()) + case reflect.Uint, reflect.Uint64: + tv := val.Uint() + if tv <= math.MaxInt64 { + return int64(tv) + } + // TODO: What is the sensible thing to do here? + return math.MaxInt64 + case reflect.Float32, reflect.Float64: + return int64(val.Float()) + case reflect.Bool: + if val.Bool() == true { + return 1 + } + return 0 + default: + return 0 + } +} + +func max(a interface{}, i ...interface{}) int64 { + aa := toInt64(a) + for _, b := range i { + bb := toInt64(b) + if bb > aa { + aa = bb + } + } + return aa +} + +func min(a interface{}, i ...interface{}) int64 { + aa := toInt64(a) + for _, b := range i { + bb := toInt64(b) + if bb < aa { + aa = bb + } + } + return aa +} + +func until(count int) []int { + step := 1 + if count < 0 { + step = -1 + } + return untilStep(0, count, step) +} + +func untilStep(start, stop, step int) []int { + v := []int{} + + if stop < start { + if step >= 0 { + return v + } + for i := start; i > stop; i += step { + v = append(v, i) + } + return v + } + + if step <= 0 { + return v + } + for i := start; i < stop; i += step { + v = append(v, i) + } + return v +} diff --git a/vendor/github.com/Masterminds/sprig/reflect.go b/vendor/github.com/Masterminds/sprig/reflect.go new file mode 100644 index 000000000..8a65c132f --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/reflect.go @@ -0,0 +1,28 @@ +package sprig + +import ( + "fmt" + "reflect" +) + +// typeIs returns true if the src is the type named in target. +func typeIs(target string, src interface{}) bool { + return target == typeOf(src) +} + +func typeIsLike(target string, src interface{}) bool { + t := typeOf(src) + return target == t || "*"+target == t +} + +func typeOf(src interface{}) string { + return fmt.Sprintf("%T", src) +} + +func kindIs(target string, src interface{}) bool { + return target == kindOf(src) +} + +func kindOf(src interface{}) string { + return reflect.ValueOf(src).Kind().String() +} diff --git a/vendor/github.com/Masterminds/sprig/semver.go b/vendor/github.com/Masterminds/sprig/semver.go new file mode 100644 index 000000000..c2bf8a1fd --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/semver.go @@ -0,0 +1,23 @@ +package sprig + +import ( + sv2 "github.com/Masterminds/semver" +) + +func semverCompare(constraint, version string) (bool, error) { + c, err := sv2.NewConstraint(constraint) + if err != nil { + return false, err + } + + v, err := sv2.NewVersion(version) + if err != nil { + return false, err + } + + return c.Check(v), nil +} + +func semver(version string) (*sv2.Version, error) { + return sv2.NewVersion(version) +} diff --git a/vendor/github.com/Masterminds/sprig/strings.go b/vendor/github.com/Masterminds/sprig/strings.go new file mode 100644 index 000000000..69bcd9854 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/strings.go @@ -0,0 +1,197 @@ +package sprig + +import ( + "encoding/base32" + "encoding/base64" + "fmt" + "reflect" + "strconv" + "strings" + + util "github.com/aokoli/goutils" +) + +func base64encode(v string) string { + return base64.StdEncoding.EncodeToString([]byte(v)) +} + +func base64decode(v string) string { + data, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return err.Error() + } + return string(data) +} + +func base32encode(v string) string { + return base32.StdEncoding.EncodeToString([]byte(v)) +} + +func base32decode(v string) string { + data, err := base32.StdEncoding.DecodeString(v) + if err != nil { + return err.Error() + } + return string(data) +} + +func abbrev(width int, s string) string { + if width < 4 { + return s + } + r, _ := util.Abbreviate(s, width) + return r +} + +func abbrevboth(left, right int, s string) string { + if right < 4 || left > 0 && right < 7 { + return s + } + r, _ := util.AbbreviateFull(s, left, right) + return r +} +func initials(s string) string { + // Wrap this just to eliminate the var args, which templates don't do well. + return util.Initials(s) +} + +func randAlphaNumeric(count int) string { + // It is not possible, it appears, to actually generate an error here. + r, _ := util.RandomAlphaNumeric(count) + return r +} + +func randAlpha(count int) string { + r, _ := util.RandomAlphabetic(count) + return r +} + +func randAscii(count int) string { + r, _ := util.RandomAscii(count) + return r +} + +func randNumeric(count int) string { + r, _ := util.RandomNumeric(count) + return r +} + +func untitle(str string) string { + return util.Uncapitalize(str) +} + +func quote(str ...interface{}) string { + out := make([]string, len(str)) + for i, s := range str { + out[i] = fmt.Sprintf("%q", strval(s)) + } + return strings.Join(out, " ") +} + +func squote(str ...interface{}) string { + out := make([]string, len(str)) + for i, s := range str { + out[i] = fmt.Sprintf("'%v'", s) + } + return strings.Join(out, " ") +} + +func cat(v ...interface{}) string { + r := strings.TrimSpace(strings.Repeat("%v ", len(v))) + return fmt.Sprintf(r, v...) +} + +func indent(spaces int, v string) string { + pad := strings.Repeat(" ", spaces) + return pad + strings.Replace(v, "\n", "\n"+pad, -1) +} + +func replace(old, new, src string) string { + return strings.Replace(src, old, new, -1) +} + +func plural(one, many string, count int) string { + if count == 1 { + return one + } + return many +} + +func strslice(v interface{}) []string { + switch v := v.(type) { + case []string: + return v + case []interface{}: + l := len(v) + b := make([]string, l) + for i := 0; i < l; i++ { + b[i] = strval(v[i]) + } + return b + default: + val := reflect.ValueOf(v) + switch val.Kind() { + case reflect.Array, reflect.Slice: + l := val.Len() + b := make([]string, l) + for i := 0; i < l; i++ { + b[i] = strval(val.Index(i).Interface()) + } + return b + default: + return []string{strval(v)} + } + } +} + +func strval(v interface{}) string { + switch v := v.(type) { + case string: + return v + case []byte: + return string(v) + case error: + return v.Error() + case fmt.Stringer: + return v.String() + default: + return fmt.Sprintf("%v", v) + } +} + +func trunc(c int, s string) string { + if len(s) <= c { + return s + } + return s[0:c] +} + +func join(sep string, v interface{}) string { + return strings.Join(strslice(v), sep) +} + +func split(sep, orig string) map[string]string { + parts := strings.Split(orig, sep) + res := make(map[string]string, len(parts)) + for i, v := range parts { + res["_"+strconv.Itoa(i)] = v + } + return res +} + +// substring creates a substring of the given string. +// +// If start is < 0, this calls string[:length]. +// +// If start is >= 0 and length < 0, this calls string[start:] +// +// Otherwise, this calls string[start, length]. +func substring(start, length int, s string) string { + if start < 0 { + return s[:length] + } + if length < 0 { + return s[start:] + } + return s[start:length] +} diff --git a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/LICENSE.md b/vendor/github.com/Sirupsen/logrus/LICENSE similarity index 96% rename from tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/LICENSE.md rename to vendor/github.com/Sirupsen/logrus/LICENSE index 229851590..f090cb42f 100644 --- a/tools/infrakit.hyperkit/vendor/github.com/mitchellh/go-ps/LICENSE.md +++ b/vendor/github.com/Sirupsen/logrus/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Mitchell Hashimoto +Copyright (c) 2014 Simon Eskildsen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/Sirupsen/logrus/README.md b/vendor/github.com/Sirupsen/logrus/README.md new file mode 100644 index 000000000..c32287611 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/README.md @@ -0,0 +1,479 @@ +# Logrus :walrus: [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus) + +**Seeing weird case-sensitive problems?** See [this +issue](https://github.com/sirupsen/logrus/issues/451#issuecomment-264332021). +This change has been reverted. I apologize for causing this. I greatly +underestimated the impact this would have. Logrus strives for stability and +backwards compatibility and failed to provide that. + +Logrus is a structured logger for Go (golang), completely API compatible with +the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not +yet stable (pre 1.0). Logrus itself is completely stable and has been used in +many large deployments. The core API is unlikely to change much but please +version control your Logrus to make sure you aren't fetching latest `master` on +every build.** + +Nicely color-coded in development (when a TTY is attached, otherwise just +plain text): + +![Colored](http://i.imgur.com/PY7qMwd.png) + +With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash +or Splunk: + +```json +{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the +ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} + +{"level":"warning","msg":"The group's number increased tremendously!", +"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"A giant walrus appears!", +"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", +"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} + +{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, +"time":"2014-03-10 19:57:38.562543128 -0400 EDT"} +``` + +With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not +attached, the output is compatible with the +[logfmt](http://godoc.org/github.com/kr/logfmt) format: + +```text +time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 +time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 +time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true +time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 +time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 +time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true +exit status 1 +``` + +#### Example + +The simplest way to use Logrus is simply the package-level exported logger: + +```go +package main + +import ( + log "github.com/Sirupsen/logrus" +) + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + }).Info("A walrus appears") +} +``` + +Note that it's completely api-compatible with the stdlib logger, so you can +replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"` +and you'll now have the flexibility of Logrus. You can customize it all you +want: + +```go +package main + +import ( + "os" + log "github.com/Sirupsen/logrus" +) + +func init() { + // Log as JSON instead of the default ASCII formatter. + log.SetFormatter(&log.JSONFormatter{}) + + // Output to stdout instead of the default stderr + // Can be any io.Writer, see below for File example + log.SetOutput(os.Stdout) + + // Only log the warning severity or above. + log.SetLevel(log.WarnLevel) +} + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(log.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(log.Fields{ + "omg": true, + "number": 100, + }).Fatal("The ice breaks!") + + // A common pattern is to re-use fields between logging statements by re-using + // the logrus.Entry returned from WithFields() + contextLogger := log.WithFields(log.Fields{ + "common": "this is a common field", + "other": "I also should be logged always", + }) + + contextLogger.Info("I'll be logged with common and other field") + contextLogger.Info("Me too") +} +``` + +For more advanced usage such as logging to multiple locations from the same +application, you can also create an instance of the `logrus` Logger: + +```go +package main + +import ( + "os" + "github.com/Sirupsen/logrus" +) + +// Create a new instance of the logger. You can have any number of instances. +var log = logrus.New() + +func main() { + // The API for setting attributes is a little different than the package level + // exported logger. See Godoc. + log.Out = os.Stdout + + // You could set this to any `io.Writer` such as a file + // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) + // if err == nil { + // log.Out = file + // } else { + // log.Info("Failed to log to file, using default stderr") + // } + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") +} +``` + +#### Fields + +Logrus encourages careful, structured logging though logging fields instead of +long, unparseable error messages. For example, instead of: `log.Fatalf("Failed +to send event %s to topic %s with key %d")`, you should log the much more +discoverable: + +```go +log.WithFields(log.Fields{ + "event": event, + "topic": topic, + "key": key, +}).Fatal("Failed to send event") +``` + +We've found this API forces you to think about logging in a way that produces +much more useful logging messages. We've been in countless situations where just +a single added field to a log statement that was already there would've saved us +hours. The `WithFields` call is optional. + +In general, with Logrus using any of the `printf`-family functions should be +seen as a hint you should add a field, however, you can still use the +`printf`-family functions with Logrus. + +#### Default Fields + +Often it's helpful to have fields _always_ attached to log statements in an +application or parts of one. For example, you may want to always log the +`request_id` and `user_ip` in the context of a request. Instead of writing +`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on +every line, you can create a `logrus.Entry` to pass around instead: + +```go +requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) +requestLogger.Info("something happened on that request") # will log request_id and user_ip +requestLogger.Warn("something not great happened") +``` + +#### Hooks + +You can add hooks for logging levels. For example to send errors to an exception +tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to +multiple places simultaneously, e.g. syslog. + +Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in +`init`: + +```go +import ( + log "github.com/Sirupsen/logrus" + "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake" + logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" + "log/syslog" +) + +func init() { + + // Use the Airbrake hook to report errors that have Error severity or above to + // an exception tracker. You can create custom hooks, see the Hooks section. + log.AddHook(airbrake.NewHook(123, "xyz", "production")) + + hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + if err != nil { + log.Error("Unable to connect to local syslog daemon") + } else { + log.AddHook(hook) + } +} +``` +Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). + +| Hook | Description | +| ----- | ----------- | +| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. | +| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. | +| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) | +| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) | +| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. | +| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic | +| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) | +| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch| +| [Firehose](https://github.com/beaubrewer/firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/) +| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd | +| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) | +| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) | +| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. | +| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger | +| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb | +| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) | +| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` | +| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka | +| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem | +| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) | +| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) | +| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) | +| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) | +| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) | +| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail | +| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb | +| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) | +| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit | +| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. | +| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) | +| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) | +| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) | +| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) | +| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar | +| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)| +| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. | +| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. | +| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) | +| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)| +| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. | +| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) | +| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) | +| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash | + +#### Level logging + +Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic. + +```go +log.Debug("Useful debugging information.") +log.Info("Something noteworthy happened!") +log.Warn("You should probably take a look at this.") +log.Error("Something failed but I'm not quitting.") +// Calls os.Exit(1) after logging +log.Fatal("Bye.") +// Calls panic() after logging +log.Panic("I'm bailing.") +``` + +You can set the logging level on a `Logger`, then it will only log entries with +that severity or anything above it: + +```go +// Will log anything that is info or above (warn, error, fatal, panic). Default. +log.SetLevel(log.InfoLevel) +``` + +It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose +environment if your application has that. + +#### Entries + +Besides the fields added with `WithField` or `WithFields` some fields are +automatically added to all logging events: + +1. `time`. The timestamp when the entry was created. +2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after + the `AddFields` call. E.g. `Failed to send event.` +3. `level`. The logging level. E.g. `info`. + +#### Environments + +Logrus has no notion of environment. + +If you wish for hooks and formatters to only be used in specific environments, +you should handle that yourself. For example, if your application has a global +variable `Environment`, which is a string representation of the environment you +could do: + +```go +import ( + log "github.com/Sirupsen/logrus" +) + +init() { + // do something here to set environment depending on an environment variable + // or command-line flag + if Environment == "production" { + log.SetFormatter(&log.JSONFormatter{}) + } else { + // The TextFormatter is default, you don't actually have to do this. + log.SetFormatter(&log.TextFormatter{}) + } +} +``` + +This configuration is how `logrus` was intended to be used, but JSON in +production is mostly only useful if you do log aggregation with tools like +Splunk or Logstash. + +#### Formatters + +The built-in logging formatters are: + +* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise + without colors. + * *Note:* to force colored output when there is no TTY, set the `ForceColors` + field to `true`. To force no colored output even if there is a TTY set the + `DisableColors` field to `true`. For Windows, see + [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable). + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). +* `logrus.JSONFormatter`. Logs fields as JSON. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). + +Third party logging formatters: + +* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events. +* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. +* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. + +You can define your formatter by implementing the `Formatter` interface, +requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a +`Fields` type (`map[string]interface{}`) with all your fields as well as the +default ones (see Entries section above): + +```go +type MyJSONFormatter struct { +} + +log.SetFormatter(new(MyJSONFormatter)) + +func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { + // Note this doesn't include Time, Level and Message which are available on + // the Entry. Consult `godoc` on information about those fields or read the + // source of the official loggers. + serialized, err := json.Marshal(entry.Data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + return append(serialized, '\n'), nil +} +``` + +#### Logger as an `io.Writer` + +Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. + +```go +w := logger.Writer() +defer w.Close() + +srv := http.Server{ + // create a stdlib log.Logger that writes to + // logrus.Logger. + ErrorLog: log.New(w, "", 0), +} +``` + +Each line written to that writer will be printed the usual way, using formatters +and hooks. The level for those entries is `info`. + +This means that we can override the standard library logger easily: + +```go +logger := logrus.New() +logger.Formatter = &logrus.JSONFormatter{} + +// Use logrus for standard log output +// Note that `log` here references stdlib's log +// Not logrus imported under the name `log`. +log.SetOutput(logger.Writer()) +``` + +#### Rotation + +Log rotation is not provided with Logrus. Log rotation should be done by an +external program (like `logrotate(8)`) that can compress and delete old log +entries. It should not be a feature of the application-level logger. + +#### Tools + +| Tool | Description | +| ---- | ----------- | +|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| +|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) | + +#### Testing + +Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: + +* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook +* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): + +```go +logger, hook := NewNullLogger() +logger.Error("Hello error") + +assert.Equal(1, len(hook.Entries)) +assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level) +assert.Equal("Hello error", hook.LastEntry().Message) + +hook.Reset() +assert.Nil(hook.LastEntry()) +``` + +#### Fatal handlers + +Logrus can register one or more functions that will be called when any `fatal` +level message is logged. The registered handlers will be executed before +logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need +to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. + +``` +... +handler := func() { + // gracefully shutdown something... +} +logrus.RegisterExitHandler(handler) +... +``` + +#### Thread safety + +By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs. +If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. + +Situation when locking is not needed includes: + +* You have no hooks registered, or hooks calling is already thread-safe. + +* Writing to logger.Out is already thread-safe, for example: + + 1) logger.Out is protected by locks. + + 2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing) + + (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/) diff --git a/vendor/github.com/Sirupsen/logrus/alt_exit.go b/vendor/github.com/Sirupsen/logrus/alt_exit.go new file mode 100644 index 000000000..8af90637a --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/alt_exit.go @@ -0,0 +1,64 @@ +package logrus + +// The following code was sourced and modified from the +// https://github.com/tebeka/atexit package governed by the following license: +// +// Copyright (c) 2012 Miki Tebeka . +// +// 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. + +import ( + "fmt" + "os" +) + +var handlers = []func(){} + +func runHandler(handler func()) { + defer func() { + if err := recover(); err != nil { + fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err) + } + }() + + handler() +} + +func runHandlers() { + for _, handler := range handlers { + runHandler(handler) + } +} + +// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) +func Exit(code int) { + runHandlers() + os.Exit(code) +} + +// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke +// all handlers. The handlers will also be invoked when any Fatal log entry is +// made. +// +// This method is useful when a caller wishes to use logrus to log a fatal +// message but also needs to gracefully shutdown. An example usecase could be +// closing database connections, or sending a alert that the application is +// closing. +func RegisterExitHandler(handler func()) { + handlers = append(handlers, handler) +} diff --git a/vendor/github.com/Sirupsen/logrus/doc.go b/vendor/github.com/Sirupsen/logrus/doc.go new file mode 100644 index 000000000..dddd5f877 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/doc.go @@ -0,0 +1,26 @@ +/* +Package logrus is a structured logger for Go, completely API compatible with the standard library logger. + + +The simplest way to use Logrus is simply the package-level exported logger: + + package main + + import ( + log "github.com/Sirupsen/logrus" + ) + + func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "number": 1, + "size": 10, + }).Info("A walrus appears") + } + +Output: + time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 + +For a full guide visit https://github.com/Sirupsen/logrus +*/ +package logrus diff --git a/vendor/github.com/Sirupsen/logrus/entry.go b/vendor/github.com/Sirupsen/logrus/entry.go new file mode 100644 index 000000000..4edbe7a2d --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/entry.go @@ -0,0 +1,275 @@ +package logrus + +import ( + "bytes" + "fmt" + "os" + "sync" + "time" +) + +var bufferPool *sync.Pool + +func init() { + bufferPool = &sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, + } +} + +// Defines the key when adding errors using WithError. +var ErrorKey = "error" + +// An entry is the final or intermediate Logrus logging entry. It contains all +// the fields passed with WithField{,s}. It's finally logged when Debug, Info, +// Warn, Error, Fatal or Panic is called on it. These objects can be reused and +// passed around as much as you wish to avoid field duplication. +type Entry struct { + Logger *Logger + + // Contains all the fields set by the user. + Data Fields + + // Time at which the log entry was created + Time time.Time + + // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic + Level Level + + // Message passed to Debug, Info, Warn, Error, Fatal or Panic + Message string + + // When formatter is called in entry.log(), an Buffer may be set to entry + Buffer *bytes.Buffer +} + +func NewEntry(logger *Logger) *Entry { + return &Entry{ + Logger: logger, + // Default is three fields, give a little extra room + Data: make(Fields, 5), + } +} + +// Returns the string representation from the reader and ultimately the +// formatter. +func (entry *Entry) String() (string, error) { + serialized, err := entry.Logger.Formatter.Format(entry) + if err != nil { + return "", err + } + str := string(serialized) + return str, nil +} + +// Add an error as single field (using the key defined in ErrorKey) to the Entry. +func (entry *Entry) WithError(err error) *Entry { + return entry.WithField(ErrorKey, err) +} + +// Add a single field to the Entry. +func (entry *Entry) WithField(key string, value interface{}) *Entry { + return entry.WithFields(Fields{key: value}) +} + +// Add a map of fields to the Entry. +func (entry *Entry) WithFields(fields Fields) *Entry { + data := make(Fields, len(entry.Data)+len(fields)) + for k, v := range entry.Data { + data[k] = v + } + for k, v := range fields { + data[k] = v + } + return &Entry{Logger: entry.Logger, Data: data} +} + +// This function is not declared with a pointer value because otherwise +// race conditions will occur when using multiple goroutines +func (entry Entry) log(level Level, msg string) { + var buffer *bytes.Buffer + entry.Time = time.Now() + entry.Level = level + entry.Message = msg + + if err := entry.Logger.Hooks.Fire(level, &entry); err != nil { + entry.Logger.mu.Lock() + fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) + entry.Logger.mu.Unlock() + } + buffer = bufferPool.Get().(*bytes.Buffer) + buffer.Reset() + defer bufferPool.Put(buffer) + entry.Buffer = buffer + serialized, err := entry.Logger.Formatter.Format(&entry) + entry.Buffer = nil + if err != nil { + entry.Logger.mu.Lock() + fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) + entry.Logger.mu.Unlock() + } else { + entry.Logger.mu.Lock() + _, err = entry.Logger.Out.Write(serialized) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) + } + entry.Logger.mu.Unlock() + } + + // To avoid Entry#log() returning a value that only would make sense for + // panic() to use in Entry#Panic(), we avoid the allocation by checking + // directly here. + if level <= PanicLevel { + panic(&entry) + } +} + +func (entry *Entry) Debug(args ...interface{}) { + if entry.Logger.Level >= DebugLevel { + entry.log(DebugLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Print(args ...interface{}) { + entry.Info(args...) +} + +func (entry *Entry) Info(args ...interface{}) { + if entry.Logger.Level >= InfoLevel { + entry.log(InfoLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Warn(args ...interface{}) { + if entry.Logger.Level >= WarnLevel { + entry.log(WarnLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Warning(args ...interface{}) { + entry.Warn(args...) +} + +func (entry *Entry) Error(args ...interface{}) { + if entry.Logger.Level >= ErrorLevel { + entry.log(ErrorLevel, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Fatal(args ...interface{}) { + if entry.Logger.Level >= FatalLevel { + entry.log(FatalLevel, fmt.Sprint(args...)) + } + Exit(1) +} + +func (entry *Entry) Panic(args ...interface{}) { + if entry.Logger.Level >= PanicLevel { + entry.log(PanicLevel, fmt.Sprint(args...)) + } + panic(fmt.Sprint(args...)) +} + +// Entry Printf family functions + +func (entry *Entry) Debugf(format string, args ...interface{}) { + if entry.Logger.Level >= DebugLevel { + entry.Debug(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Infof(format string, args ...interface{}) { + if entry.Logger.Level >= InfoLevel { + entry.Info(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Printf(format string, args ...interface{}) { + entry.Infof(format, args...) +} + +func (entry *Entry) Warnf(format string, args ...interface{}) { + if entry.Logger.Level >= WarnLevel { + entry.Warn(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Warningf(format string, args ...interface{}) { + entry.Warnf(format, args...) +} + +func (entry *Entry) Errorf(format string, args ...interface{}) { + if entry.Logger.Level >= ErrorLevel { + entry.Error(fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Fatalf(format string, args ...interface{}) { + if entry.Logger.Level >= FatalLevel { + entry.Fatal(fmt.Sprintf(format, args...)) + } + Exit(1) +} + +func (entry *Entry) Panicf(format string, args ...interface{}) { + if entry.Logger.Level >= PanicLevel { + entry.Panic(fmt.Sprintf(format, args...)) + } +} + +// Entry Println family functions + +func (entry *Entry) Debugln(args ...interface{}) { + if entry.Logger.Level >= DebugLevel { + entry.Debug(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Infoln(args ...interface{}) { + if entry.Logger.Level >= InfoLevel { + entry.Info(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Println(args ...interface{}) { + entry.Infoln(args...) +} + +func (entry *Entry) Warnln(args ...interface{}) { + if entry.Logger.Level >= WarnLevel { + entry.Warn(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Warningln(args ...interface{}) { + entry.Warnln(args...) +} + +func (entry *Entry) Errorln(args ...interface{}) { + if entry.Logger.Level >= ErrorLevel { + entry.Error(entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Fatalln(args ...interface{}) { + if entry.Logger.Level >= FatalLevel { + entry.Fatal(entry.sprintlnn(args...)) + } + Exit(1) +} + +func (entry *Entry) Panicln(args ...interface{}) { + if entry.Logger.Level >= PanicLevel { + entry.Panic(entry.sprintlnn(args...)) + } +} + +// Sprintlnn => Sprint no newline. This is to get the behavior of how +// fmt.Sprintln where spaces are always added between operands, regardless of +// their type. Instead of vendoring the Sprintln implementation to spare a +// string allocation, we do the simplest thing. +func (entry *Entry) sprintlnn(args ...interface{}) string { + msg := fmt.Sprintln(args...) + return msg[:len(msg)-1] +} diff --git a/vendor/github.com/Sirupsen/logrus/exported.go b/vendor/github.com/Sirupsen/logrus/exported.go new file mode 100644 index 000000000..9a0120ac1 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/exported.go @@ -0,0 +1,193 @@ +package logrus + +import ( + "io" +) + +var ( + // std is the name of the standard logger in stdlib `log` + std = New() +) + +func StandardLogger() *Logger { + return std +} + +// SetOutput sets the standard logger output. +func SetOutput(out io.Writer) { + std.mu.Lock() + defer std.mu.Unlock() + std.Out = out +} + +// SetFormatter sets the standard logger formatter. +func SetFormatter(formatter Formatter) { + std.mu.Lock() + defer std.mu.Unlock() + std.Formatter = formatter +} + +// SetLevel sets the standard logger level. +func SetLevel(level Level) { + std.mu.Lock() + defer std.mu.Unlock() + std.Level = level +} + +// GetLevel returns the standard logger level. +func GetLevel() Level { + std.mu.Lock() + defer std.mu.Unlock() + return std.Level +} + +// AddHook adds a hook to the standard logger hooks. +func AddHook(hook Hook) { + std.mu.Lock() + defer std.mu.Unlock() + std.Hooks.Add(hook) +} + +// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. +func WithError(err error) *Entry { + return std.WithField(ErrorKey, err) +} + +// WithField creates an entry from the standard logger and adds a field to +// it. If you want multiple fields, use `WithFields`. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithField(key string, value interface{}) *Entry { + return std.WithField(key, value) +} + +// WithFields creates an entry from the standard logger and adds multiple +// fields to it. This is simply a helper for `WithField`, invoking it +// once for each field. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithFields(fields Fields) *Entry { + return std.WithFields(fields) +} + +// Debug logs a message at level Debug on the standard logger. +func Debug(args ...interface{}) { + std.Debug(args...) +} + +// Print logs a message at level Info on the standard logger. +func Print(args ...interface{}) { + std.Print(args...) +} + +// Info logs a message at level Info on the standard logger. +func Info(args ...interface{}) { + std.Info(args...) +} + +// Warn logs a message at level Warn on the standard logger. +func Warn(args ...interface{}) { + std.Warn(args...) +} + +// Warning logs a message at level Warn on the standard logger. +func Warning(args ...interface{}) { + std.Warning(args...) +} + +// Error logs a message at level Error on the standard logger. +func Error(args ...interface{}) { + std.Error(args...) +} + +// Panic logs a message at level Panic on the standard logger. +func Panic(args ...interface{}) { + std.Panic(args...) +} + +// Fatal logs a message at level Fatal on the standard logger. +func Fatal(args ...interface{}) { + std.Fatal(args...) +} + +// Debugf logs a message at level Debug on the standard logger. +func Debugf(format string, args ...interface{}) { + std.Debugf(format, args...) +} + +// Printf logs a message at level Info on the standard logger. +func Printf(format string, args ...interface{}) { + std.Printf(format, args...) +} + +// Infof logs a message at level Info on the standard logger. +func Infof(format string, args ...interface{}) { + std.Infof(format, args...) +} + +// Warnf logs a message at level Warn on the standard logger. +func Warnf(format string, args ...interface{}) { + std.Warnf(format, args...) +} + +// Warningf logs a message at level Warn on the standard logger. +func Warningf(format string, args ...interface{}) { + std.Warningf(format, args...) +} + +// Errorf logs a message at level Error on the standard logger. +func Errorf(format string, args ...interface{}) { + std.Errorf(format, args...) +} + +// Panicf logs a message at level Panic on the standard logger. +func Panicf(format string, args ...interface{}) { + std.Panicf(format, args...) +} + +// Fatalf logs a message at level Fatal on the standard logger. +func Fatalf(format string, args ...interface{}) { + std.Fatalf(format, args...) +} + +// Debugln logs a message at level Debug on the standard logger. +func Debugln(args ...interface{}) { + std.Debugln(args...) +} + +// Println logs a message at level Info on the standard logger. +func Println(args ...interface{}) { + std.Println(args...) +} + +// Infoln logs a message at level Info on the standard logger. +func Infoln(args ...interface{}) { + std.Infoln(args...) +} + +// Warnln logs a message at level Warn on the standard logger. +func Warnln(args ...interface{}) { + std.Warnln(args...) +} + +// Warningln logs a message at level Warn on the standard logger. +func Warningln(args ...interface{}) { + std.Warningln(args...) +} + +// Errorln logs a message at level Error on the standard logger. +func Errorln(args ...interface{}) { + std.Errorln(args...) +} + +// Panicln logs a message at level Panic on the standard logger. +func Panicln(args ...interface{}) { + std.Panicln(args...) +} + +// Fatalln logs a message at level Fatal on the standard logger. +func Fatalln(args ...interface{}) { + std.Fatalln(args...) +} diff --git a/vendor/github.com/Sirupsen/logrus/formatter.go b/vendor/github.com/Sirupsen/logrus/formatter.go new file mode 100644 index 000000000..b5fbe934d --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/formatter.go @@ -0,0 +1,45 @@ +package logrus + +import "time" + +const DefaultTimestampFormat = time.RFC3339 + +// The Formatter interface is used to implement a custom Formatter. It takes an +// `Entry`. It exposes all the fields, including the default ones: +// +// * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. +// * `entry.Data["time"]`. The timestamp. +// * `entry.Data["level"]. The level the entry was logged at. +// +// Any additional fields added with `WithField` or `WithFields` are also in +// `entry.Data`. Format is expected to return an array of bytes which are then +// logged to `logger.Out`. +type Formatter interface { + Format(*Entry) ([]byte, error) +} + +// This is to not silently overwrite `time`, `msg` and `level` fields when +// dumping it. If this code wasn't there doing: +// +// logrus.WithField("level", 1).Info("hello") +// +// Would just silently drop the user provided level. Instead with this code +// it'll logged as: +// +// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} +// +// It's not exported because it's still using Data in an opinionated way. It's to +// avoid code duplication between the two default formatters. +func prefixFieldClashes(data Fields) { + if t, ok := data["time"]; ok { + data["fields.time"] = t + } + + if m, ok := data["msg"]; ok { + data["fields.msg"] = m + } + + if l, ok := data["level"]; ok { + data["fields.level"] = l + } +} diff --git a/vendor/github.com/Sirupsen/logrus/hooks.go b/vendor/github.com/Sirupsen/logrus/hooks.go new file mode 100644 index 000000000..3f151cdc3 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/hooks.go @@ -0,0 +1,34 @@ +package logrus + +// A hook to be fired when logging on the logging levels returned from +// `Levels()` on your implementation of the interface. Note that this is not +// fired in a goroutine or a channel with workers, you should handle such +// functionality yourself if your call is non-blocking and you don't wish for +// the logging calls for levels returned from `Levels()` to block. +type Hook interface { + Levels() []Level + Fire(*Entry) error +} + +// Internal type for storing the hooks on a logger instance. +type LevelHooks map[Level][]Hook + +// Add a hook to an instance of logger. This is called with +// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. +func (hooks LevelHooks) Add(hook Hook) { + for _, level := range hook.Levels() { + hooks[level] = append(hooks[level], hook) + } +} + +// Fire all the hooks for the passed level. Used by `entry.log` to fire +// appropriate hooks for a log entry. +func (hooks LevelHooks) Fire(level Level, entry *Entry) error { + for _, hook := range hooks[level] { + if err := hook.Fire(entry); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/Sirupsen/logrus/json_formatter.go b/vendor/github.com/Sirupsen/logrus/json_formatter.go new file mode 100644 index 000000000..266554e9f --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/json_formatter.go @@ -0,0 +1,74 @@ +package logrus + +import ( + "encoding/json" + "fmt" +) + +type fieldKey string +type FieldMap map[fieldKey]string + +const ( + FieldKeyMsg = "msg" + FieldKeyLevel = "level" + FieldKeyTime = "time" +) + +func (f FieldMap) resolve(key fieldKey) string { + if k, ok := f[key]; ok { + return k + } + + return string(key) +} + +type JSONFormatter struct { + // TimestampFormat sets the format used for marshaling timestamps. + TimestampFormat string + + // DisableTimestamp allows disabling automatic timestamps in output + DisableTimestamp bool + + // FieldMap allows users to customize the names of keys for various fields. + // As an example: + // formatter := &JSONFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyLevel: "@message", + // }, + // } + FieldMap FieldMap +} + +func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { + data := make(Fields, len(entry.Data)+3) + for k, v := range entry.Data { + switch v := v.(type) { + case error: + // Otherwise errors are ignored by `encoding/json` + // https://github.com/Sirupsen/logrus/issues/137 + data[k] = v.Error() + default: + data[k] = v + } + } + prefixFieldClashes(data) + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = DefaultTimestampFormat + } + + if !f.DisableTimestamp { + data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) + } + data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message + data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() + + serialized, err := json.Marshal(data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + return append(serialized, '\n'), nil +} diff --git a/vendor/github.com/Sirupsen/logrus/logger.go b/vendor/github.com/Sirupsen/logrus/logger.go new file mode 100644 index 000000000..b769f3d35 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/logger.go @@ -0,0 +1,308 @@ +package logrus + +import ( + "io" + "os" + "sync" +) + +type Logger struct { + // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a + // file, or leave it default which is `os.Stderr`. You can also set this to + // something more adventorous, such as logging to Kafka. + Out io.Writer + // Hooks for the logger instance. These allow firing events based on logging + // levels and log entries. For example, to send errors to an error tracking + // service, log to StatsD or dump the core on fatal errors. + Hooks LevelHooks + // All log entries pass through the formatter before logged to Out. The + // included formatters are `TextFormatter` and `JSONFormatter` for which + // TextFormatter is the default. In development (when a TTY is attached) it + // logs with colors, but to a file it wouldn't. You can easily implement your + // own that implements the `Formatter` interface, see the `README` or included + // formatters for examples. + Formatter Formatter + // The logging level the logger should log at. This is typically (and defaults + // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be + // logged. `logrus.Debug` is useful in + Level Level + // Used to sync writing to the log. Locking is enabled by Default + mu MutexWrap + // Reusable empty entry + entryPool sync.Pool +} + +type MutexWrap struct { + lock sync.Mutex + disabled bool +} + +func (mw *MutexWrap) Lock() { + if !mw.disabled { + mw.lock.Lock() + } +} + +func (mw *MutexWrap) Unlock() { + if !mw.disabled { + mw.lock.Unlock() + } +} + +func (mw *MutexWrap) Disable() { + mw.disabled = true +} + +// Creates a new logger. Configuration should be set by changing `Formatter`, +// `Out` and `Hooks` directly on the default logger instance. You can also just +// instantiate your own: +// +// var log = &Logger{ +// Out: os.Stderr, +// Formatter: new(JSONFormatter), +// Hooks: make(LevelHooks), +// Level: logrus.DebugLevel, +// } +// +// It's recommended to make this a global instance called `log`. +func New() *Logger { + return &Logger{ + Out: os.Stderr, + Formatter: new(TextFormatter), + Hooks: make(LevelHooks), + Level: InfoLevel, + } +} + +func (logger *Logger) newEntry() *Entry { + entry, ok := logger.entryPool.Get().(*Entry) + if ok { + return entry + } + return NewEntry(logger) +} + +func (logger *Logger) releaseEntry(entry *Entry) { + logger.entryPool.Put(entry) +} + +// Adds a field to the log entry, note that it doesn't log until you call +// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. +// If you want multiple fields, use `WithFields`. +func (logger *Logger) WithField(key string, value interface{}) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithField(key, value) +} + +// Adds a struct of fields to the log entry. All it does is call `WithField` for +// each `Field`. +func (logger *Logger) WithFields(fields Fields) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithFields(fields) +} + +// Add an error as single field to the log entry. All it does is call +// `WithError` for the given `error`. +func (logger *Logger) WithError(err error) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithError(err) +} + +func (logger *Logger) Debugf(format string, args ...interface{}) { + if logger.Level >= DebugLevel { + entry := logger.newEntry() + entry.Debugf(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Infof(format string, args ...interface{}) { + if logger.Level >= InfoLevel { + entry := logger.newEntry() + entry.Infof(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Printf(format string, args ...interface{}) { + entry := logger.newEntry() + entry.Printf(format, args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warnf(format string, args ...interface{}) { + if logger.Level >= WarnLevel { + entry := logger.newEntry() + entry.Warnf(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Warningf(format string, args ...interface{}) { + if logger.Level >= WarnLevel { + entry := logger.newEntry() + entry.Warnf(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Errorf(format string, args ...interface{}) { + if logger.Level >= ErrorLevel { + entry := logger.newEntry() + entry.Errorf(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Fatalf(format string, args ...interface{}) { + if logger.Level >= FatalLevel { + entry := logger.newEntry() + entry.Fatalf(format, args...) + logger.releaseEntry(entry) + } + Exit(1) +} + +func (logger *Logger) Panicf(format string, args ...interface{}) { + if logger.Level >= PanicLevel { + entry := logger.newEntry() + entry.Panicf(format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Debug(args ...interface{}) { + if logger.Level >= DebugLevel { + entry := logger.newEntry() + entry.Debug(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Info(args ...interface{}) { + if logger.Level >= InfoLevel { + entry := logger.newEntry() + entry.Info(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Print(args ...interface{}) { + entry := logger.newEntry() + entry.Info(args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warn(args ...interface{}) { + if logger.Level >= WarnLevel { + entry := logger.newEntry() + entry.Warn(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Warning(args ...interface{}) { + if logger.Level >= WarnLevel { + entry := logger.newEntry() + entry.Warn(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Error(args ...interface{}) { + if logger.Level >= ErrorLevel { + entry := logger.newEntry() + entry.Error(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Fatal(args ...interface{}) { + if logger.Level >= FatalLevel { + entry := logger.newEntry() + entry.Fatal(args...) + logger.releaseEntry(entry) + } + Exit(1) +} + +func (logger *Logger) Panic(args ...interface{}) { + if logger.Level >= PanicLevel { + entry := logger.newEntry() + entry.Panic(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Debugln(args ...interface{}) { + if logger.Level >= DebugLevel { + entry := logger.newEntry() + entry.Debugln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Infoln(args ...interface{}) { + if logger.Level >= InfoLevel { + entry := logger.newEntry() + entry.Infoln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Println(args ...interface{}) { + entry := logger.newEntry() + entry.Println(args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warnln(args ...interface{}) { + if logger.Level >= WarnLevel { + entry := logger.newEntry() + entry.Warnln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Warningln(args ...interface{}) { + if logger.Level >= WarnLevel { + entry := logger.newEntry() + entry.Warnln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Errorln(args ...interface{}) { + if logger.Level >= ErrorLevel { + entry := logger.newEntry() + entry.Errorln(args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Fatalln(args ...interface{}) { + if logger.Level >= FatalLevel { + entry := logger.newEntry() + entry.Fatalln(args...) + logger.releaseEntry(entry) + } + Exit(1) +} + +func (logger *Logger) Panicln(args ...interface{}) { + if logger.Level >= PanicLevel { + entry := logger.newEntry() + entry.Panicln(args...) + logger.releaseEntry(entry) + } +} + +//When file is opened with appending mode, it's safe to +//write concurrently to a file (within 4k message on Linux). +//In these cases user can choose to disable the lock. +func (logger *Logger) SetNoLock() { + logger.mu.Disable() +} diff --git a/vendor/github.com/Sirupsen/logrus/logrus.go b/vendor/github.com/Sirupsen/logrus/logrus.go new file mode 100644 index 000000000..e59669111 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/logrus.go @@ -0,0 +1,143 @@ +package logrus + +import ( + "fmt" + "log" + "strings" +) + +// Fields type, used to pass to `WithFields`. +type Fields map[string]interface{} + +// Level type +type Level uint8 + +// Convert the Level to a string. E.g. PanicLevel becomes "panic". +func (level Level) String() string { + switch level { + case DebugLevel: + return "debug" + case InfoLevel: + return "info" + case WarnLevel: + return "warning" + case ErrorLevel: + return "error" + case FatalLevel: + return "fatal" + case PanicLevel: + return "panic" + } + + return "unknown" +} + +// ParseLevel takes a string level and returns the Logrus log level constant. +func ParseLevel(lvl string) (Level, error) { + switch strings.ToLower(lvl) { + case "panic": + return PanicLevel, nil + case "fatal": + return FatalLevel, nil + case "error": + return ErrorLevel, nil + case "warn", "warning": + return WarnLevel, nil + case "info": + return InfoLevel, nil + case "debug": + return DebugLevel, nil + } + + var l Level + return l, fmt.Errorf("not a valid logrus Level: %q", lvl) +} + +// A constant exposing all logging levels +var AllLevels = []Level{ + PanicLevel, + FatalLevel, + ErrorLevel, + WarnLevel, + InfoLevel, + DebugLevel, +} + +// These are the different logging levels. You can set the logging level to log +// on your instance of logger, obtained with `logrus.New()`. +const ( + // PanicLevel level, highest level of severity. Logs and then calls panic with the + // message passed to Debug, Info, ... + PanicLevel Level = iota + // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the + // logging level is set to Panic. + FatalLevel + // ErrorLevel level. Logs. Used for errors that should definitely be noted. + // Commonly used for hooks to send errors to an error tracking service. + ErrorLevel + // WarnLevel level. Non-critical entries that deserve eyes. + WarnLevel + // InfoLevel level. General operational entries about what's going on inside the + // application. + InfoLevel + // DebugLevel level. Usually only enabled when debugging. Very verbose logging. + DebugLevel +) + +// Won't compile if StdLogger can't be realized by a log.Logger +var ( + _ StdLogger = &log.Logger{} + _ StdLogger = &Entry{} + _ StdLogger = &Logger{} +) + +// StdLogger is what your logrus-enabled library should take, that way +// it'll accept a stdlib logger and a logrus logger. There's no standard +// interface, this is the closest we get, unfortunately. +type StdLogger interface { + Print(...interface{}) + Printf(string, ...interface{}) + Println(...interface{}) + + Fatal(...interface{}) + Fatalf(string, ...interface{}) + Fatalln(...interface{}) + + Panic(...interface{}) + Panicf(string, ...interface{}) + Panicln(...interface{}) +} + +// The FieldLogger interface generalizes the Entry and Logger types +type FieldLogger interface { + WithField(key string, value interface{}) *Entry + WithFields(fields Fields) *Entry + WithError(err error) *Entry + + Debugf(format string, args ...interface{}) + Infof(format string, args ...interface{}) + Printf(format string, args ...interface{}) + Warnf(format string, args ...interface{}) + Warningf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) + Fatalf(format string, args ...interface{}) + Panicf(format string, args ...interface{}) + + Debug(args ...interface{}) + Info(args ...interface{}) + Print(args ...interface{}) + Warn(args ...interface{}) + Warning(args ...interface{}) + Error(args ...interface{}) + Fatal(args ...interface{}) + Panic(args ...interface{}) + + Debugln(args ...interface{}) + Infoln(args ...interface{}) + Println(args ...interface{}) + Warnln(args ...interface{}) + Warningln(args ...interface{}) + Errorln(args ...interface{}) + Fatalln(args ...interface{}) + Panicln(args ...interface{}) +} diff --git a/vendor/github.com/Sirupsen/logrus/terminal_appengine.go b/vendor/github.com/Sirupsen/logrus/terminal_appengine.go new file mode 100644 index 000000000..e011a8694 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/terminal_appengine.go @@ -0,0 +1,10 @@ +// +build appengine + +package logrus + +import "io" + +// IsTerminal returns true if stderr's file descriptor is a terminal. +func IsTerminal(f io.Writer) bool { + return true +} diff --git a/vendor/github.com/Sirupsen/logrus/terminal_bsd.go b/vendor/github.com/Sirupsen/logrus/terminal_bsd.go new file mode 100644 index 000000000..5f6be4d3c --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/terminal_bsd.go @@ -0,0 +1,10 @@ +// +build darwin freebsd openbsd netbsd dragonfly +// +build !appengine + +package logrus + +import "syscall" + +const ioctlReadTermios = syscall.TIOCGETA + +type Termios syscall.Termios diff --git a/vendor/github.com/Sirupsen/logrus/terminal_linux.go b/vendor/github.com/Sirupsen/logrus/terminal_linux.go new file mode 100644 index 000000000..308160ca8 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/terminal_linux.go @@ -0,0 +1,14 @@ +// Based on ssh/terminal: +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine + +package logrus + +import "syscall" + +const ioctlReadTermios = syscall.TCGETS + +type Termios syscall.Termios diff --git a/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go b/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go new file mode 100644 index 000000000..190297abf --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go @@ -0,0 +1,28 @@ +// Based on ssh/terminal: +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux darwin freebsd openbsd netbsd dragonfly +// +build !appengine + +package logrus + +import ( + "io" + "os" + "syscall" + "unsafe" +) + +// IsTerminal returns true if stderr's file descriptor is a terminal. +func IsTerminal(f io.Writer) bool { + var termios Termios + switch v := f.(type) { + case *os.File: + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 + default: + return false + } +} diff --git a/vendor/github.com/Sirupsen/logrus/terminal_solaris.go b/vendor/github.com/Sirupsen/logrus/terminal_solaris.go new file mode 100644 index 000000000..3c86b1abe --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/terminal_solaris.go @@ -0,0 +1,21 @@ +// +build solaris,!appengine + +package logrus + +import ( + "io" + "os" + + "golang.org/x/sys/unix" +) + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(f io.Writer) bool { + switch v := f.(type) { + case *os.File: + _, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA) + return err == nil + default: + return false + } +} diff --git a/vendor/github.com/Sirupsen/logrus/terminal_windows.go b/vendor/github.com/Sirupsen/logrus/terminal_windows.go new file mode 100644 index 000000000..05d2f91f1 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/terminal_windows.go @@ -0,0 +1,33 @@ +// Based on ssh/terminal: +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows,!appengine + +package logrus + +import ( + "io" + "os" + "syscall" + "unsafe" +) + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") + +var ( + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") +) + +// IsTerminal returns true if stderr's file descriptor is a terminal. +func IsTerminal(f io.Writer) bool { + switch v := f.(type) { + case *os.File: + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 + default: + return false + } +} diff --git a/vendor/github.com/Sirupsen/logrus/text_formatter.go b/vendor/github.com/Sirupsen/logrus/text_formatter.go new file mode 100644 index 000000000..ba8885406 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/text_formatter.go @@ -0,0 +1,189 @@ +package logrus + +import ( + "bytes" + "fmt" + "sort" + "strings" + "sync" + "time" +) + +const ( + nocolor = 0 + red = 31 + green = 32 + yellow = 33 + blue = 34 + gray = 37 +) + +var ( + baseTimestamp time.Time +) + +func init() { + baseTimestamp = time.Now() +} + +type TextFormatter struct { + // Set to true to bypass checking for a TTY before outputting colors. + ForceColors bool + + // Force disabling colors. + DisableColors bool + + // Disable timestamp logging. useful when output is redirected to logging + // system that already adds timestamps. + DisableTimestamp bool + + // Enable logging the full timestamp when a TTY is attached instead of just + // the time passed since beginning of execution. + FullTimestamp bool + + // TimestampFormat to use for display when a full timestamp is printed + TimestampFormat string + + // The fields are sorted by default for a consistent output. For applications + // that log extremely frequently and don't use the JSON formatter this may not + // be desired. + DisableSorting bool + + // QuoteEmptyFields will wrap empty fields in quotes if true + QuoteEmptyFields bool + + // QuoteCharacter can be set to the override the default quoting character " + // with something else. For example: ', or `. + QuoteCharacter string + + // Whether the logger's out is to a terminal + isTerminal bool + + sync.Once +} + +func (f *TextFormatter) init(entry *Entry) { + if len(f.QuoteCharacter) == 0 { + f.QuoteCharacter = "\"" + } + if entry.Logger != nil { + f.isTerminal = IsTerminal(entry.Logger.Out) + } +} + +func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { + var b *bytes.Buffer + keys := make([]string, 0, len(entry.Data)) + for k := range entry.Data { + keys = append(keys, k) + } + + if !f.DisableSorting { + sort.Strings(keys) + } + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + prefixFieldClashes(entry.Data) + + f.Do(func() { f.init(entry) }) + + isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = DefaultTimestampFormat + } + if isColored { + f.printColored(b, entry, keys, timestampFormat) + } else { + if !f.DisableTimestamp { + f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat)) + } + f.appendKeyValue(b, "level", entry.Level.String()) + if entry.Message != "" { + f.appendKeyValue(b, "msg", entry.Message) + } + for _, key := range keys { + f.appendKeyValue(b, key, entry.Data[key]) + } + } + + b.WriteByte('\n') + return b.Bytes(), nil +} + +func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) { + var levelColor int + switch entry.Level { + case DebugLevel: + levelColor = gray + case WarnLevel: + levelColor = yellow + case ErrorLevel, FatalLevel, PanicLevel: + levelColor = red + default: + levelColor = blue + } + + levelText := strings.ToUpper(entry.Level.String())[0:4] + + if f.DisableTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message) + } else if !f.FullTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message) + } else { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message) + } + for _, k := range keys { + v := entry.Data[k] + fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) + f.appendValue(b, v) + } +} + +func (f *TextFormatter) needsQuoting(text string) bool { + if f.QuoteEmptyFields && len(text) == 0 { + return true + } + for _, ch := range text { + if !((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '-' || ch == '.') { + return true + } + } + return false +} + +func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { + + b.WriteString(key) + b.WriteByte('=') + f.appendValue(b, value) + b.WriteByte(' ') +} + +func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { + switch value := value.(type) { + case string: + if !f.needsQuoting(value) { + b.WriteString(value) + } else { + fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter) + } + case error: + errmsg := value.Error() + if !f.needsQuoting(errmsg) { + b.WriteString(errmsg) + } else { + fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter) + } + default: + fmt.Fprint(b, value) + } +} diff --git a/vendor/github.com/Sirupsen/logrus/writer.go b/vendor/github.com/Sirupsen/logrus/writer.go new file mode 100644 index 000000000..7bdebedc6 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/writer.go @@ -0,0 +1,62 @@ +package logrus + +import ( + "bufio" + "io" + "runtime" +) + +func (logger *Logger) Writer() *io.PipeWriter { + return logger.WriterLevel(InfoLevel) +} + +func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { + return NewEntry(logger).WriterLevel(level) +} + +func (entry *Entry) Writer() *io.PipeWriter { + return entry.WriterLevel(InfoLevel) +} + +func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { + reader, writer := io.Pipe() + + var printFunc func(args ...interface{}) + + switch level { + case DebugLevel: + printFunc = entry.Debug + case InfoLevel: + printFunc = entry.Info + case WarnLevel: + printFunc = entry.Warn + case ErrorLevel: + printFunc = entry.Error + case FatalLevel: + printFunc = entry.Fatal + case PanicLevel: + printFunc = entry.Panic + default: + printFunc = entry.Print + } + + go entry.writerScanner(reader, printFunc) + runtime.SetFinalizer(writer, writerFinalizer) + + return writer +} + +func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + printFunc(scanner.Text()) + } + if err := scanner.Err(); err != nil { + entry.Errorf("Error while reading from Writer: %s", err) + } + reader.Close() +} + +func writerFinalizer(writer *io.PipeWriter) { + writer.Close() +} diff --git a/vendor/github.com/aokoli/goutils/LICENSE.txt b/vendor/github.com/aokoli/goutils/LICENSE.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/aokoli/goutils/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/github.com/aokoli/goutils/README.md b/vendor/github.com/aokoli/goutils/README.md new file mode 100644 index 000000000..9d8a42df8 --- /dev/null +++ b/vendor/github.com/aokoli/goutils/README.md @@ -0,0 +1,72 @@ +GoUtils +=========== + +GoUtils provides users with utility functions to manipulate strings in various ways. It is a Go implementation of some +string manipulation libraries of Java Apache Commons. GoUtils includes the following Java Apache Commons classes: +* WordUtils +* RandomStringUtils +* StringUtils (partial implementation) + +## Installation +If you have Go set up on your system, from the GOPATH directory within the command line/terminal, enter this: + + go get github.com/aokoli/goutils + +If you do not have Go set up on your system, please follow the [Go installation directions from the documenation](http://golang.org/doc/install), and then follow the instructions above to install GoUtils. + + +## Documentation +GoUtils doc is available here: [![GoDoc](https://godoc.org/github.com/aokoli/goutils?status.png)](https://godoc.org/github.com/aokoli/goutils) + + +## Usage +The code snippets below show examples of how to use GoUtils. Some functions return errors while others do not. The first instance below, which does not return an error, is the `Initials` function (located within the `wordutils.go` file). + + package main + + import ( + "fmt" + "github.com/aokoli/goutils" + ) + + func main() { + + // EXAMPLE 1: A goutils function which returns no errors + fmt.Println (goutils.Initials("John Doe Foo")) // Prints out "JDF" + + } +Some functions return errors mainly due to illegal arguements used as parameters. The code example below illustrates how to deal with function that returns an error. In this instance, the function is the `Random` function (located within the `randomstringutils.go` file). + + package main + + import ( + "fmt" + "github.com/aokoli/goutils" + ) + + func main() { + + // EXAMPLE 2: A goutils function which returns an error + rand1, err1 := goutils.Random (-1, 0, 0, true, true) + + if err1 != nil { + fmt.Println(err1) // Prints out error message because -1 was entered as the first parameter in goutils.Random(...) + } else { + fmt.Println(rand1) + } + + } + +## License +GoUtils is licensed under the Apache License, Version 2.0. Please check the LICENSE.txt file or visit http://www.apache.org/licenses/LICENSE-2.0 for a copy of the license. + +## Issue Reporting +Make suggestions or report issues using the Git issue tracker: https://github.com/aokoli/goutils/issues + +## Website +* [GoUtils webpage](http://aokoli.github.io/goutils/) + +## Mailing List +Contact [okolialex@gmail.com](mailto:okolialex@mail.com) to be added to the mailing list. You will get updates on the +status of the project and the potential direction it will be heading. + diff --git a/vendor/github.com/aokoli/goutils/randomstringutils.go b/vendor/github.com/aokoli/goutils/randomstringutils.go new file mode 100644 index 000000000..db395a0a1 --- /dev/null +++ b/vendor/github.com/aokoli/goutils/randomstringutils.go @@ -0,0 +1,259 @@ +/* +Copyright 2014 Alexander Okoli + +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 goutils + + +import ( + "fmt" + "unicode" + "math" + "math/rand" + "time" +) + + +// Provides the time-based seed used to generate random #s +var RANDOM = rand.New(rand.NewSource(time.Now().UnixNano())) + +/* +RandomNonAlphaNumeric creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of all characters (ASCII/Unicode values between 0 to 2,147,483,647 (math.MaxInt32)). + +Parameter: + count - the length of random string to create + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) +*/ +func RandomNonAlphaNumeric (count int) (string, error) { + return RandomAlphaNumericCustom(count, false, false) +} + + +/* +RandomAscii creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of characters whose ASCII value is between 32 and 126 (inclusive). + +Parameter: + count - the length of random string to create + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) +*/ +func RandomAscii(count int) (string, error) { + return Random(count, 32, 127, false, false) +} + + +/* +RandomNumeric creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of numeric characters. + +Parameter: + count - the length of random string to create + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) +*/ +func RandomNumeric (count int) (string, error) { + return Random(count, 0, 0, false, true) +} + + +/* +RandomAlphabetic creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments. + +Parameters: + count - the length of random string to create + letters - if true, generated string may include alphabetic characters + numbers - if true, generated string may include numeric characters + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) +*/ +func RandomAlphabetic (count int) (string, error) { + return Random(count, 0, 0, true, false) +} + + +/* +RandomAlphaNumeric creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of alpha-numeric characters. + +Parameter: + count - the length of random string to create + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) +*/ +func RandomAlphaNumeric (count int) (string, error) { + return Random(count, 0, 0, true, true) +} + +/* +RandomAlphaNumericCustom creates a random string whose length is the number of characters specified. +Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments. + +Parameters: + count - the length of random string to create + letters - if true, generated string may include alphabetic characters + numbers - if true, generated string may include numeric characters + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) +*/ +func RandomAlphaNumericCustom (count int, letters bool, numbers bool) (string, error) { + return Random(count, 0, 0, letters, numbers) +} + + +/* +Random creates a random string based on a variety of options, using default source of randomness. +This method has exactly the same semantics as RandomSeed(int, int, int, bool, bool, []char, *rand.Rand), but +instead of using an externally supplied source of randomness, it uses the internal *rand.Rand instance. + +Parameters: + count - the length of random string to create + start - the position in set of chars (ASCII/Unicode int) to start at + end - the position in set of chars (ASCII/Unicode int) to end before + letters - if true, generated string may include alphabetic characters + numbers - if true, generated string may include numeric characters + chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars. + +Returns: + string - the random string + error - an error stemming from an invalid parameter within underlying function, RandomSeed(...) +*/ +func Random (count int, start int, end int, letters bool, numbers bool, chars ...rune) (string, error) { + return RandomSeed (count, start, end, letters, numbers, chars, RANDOM) +} + + +/* +RandomSeed creates a random string based on a variety of options, using supplied source of randomness. +If the parameters start and end are both 0, start and end are set to ' ' and 'z', the ASCII printable characters, will be used, +unless letters and numbers are both false, in which case, start and end are set to 0 and math.MaxInt32, respectively. +If chars is not nil, characters stored in chars that are between start and end are chosen. +This method accepts a user-supplied *rand.Rand instance to use as a source of randomness. By seeding a single *rand.Rand instance +with a fixed seed and using it for each call, the same random sequence of strings can be generated repeatedly and predictably. + +Parameters: + count - the length of random string to create + start - the position in set of chars (ASCII/Unicode decimals) to start at + end - the position in set of chars (ASCII/Unicode decimals) to end before + letters - if true, generated string may include alphabetic characters + numbers - if true, generated string may include numeric characters + chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars. + random - a source of randomness. + +Returns: + string - the random string + error - an error stemming from invalid parameters: if count < 0; or the provided chars array is empty; or end <= start; or end > len(chars) +*/ +func RandomSeed (count int, start int, end int, letters bool, numbers bool, chars []rune, random *rand.Rand) (string, error) { + + if count == 0 { + return "", nil + } else if count < 0 { + err := fmt.Errorf("randomstringutils illegal argument: Requested random string length %v is less than 0.", count) // equiv to err := errors.New("...") + return "", err + } + if chars != nil && len(chars) == 0 { + err := fmt.Errorf("randomstringutils illegal argument: The chars array must not be empty") + return "", err + } + + if start == 0 && end == 0 { + if chars != nil { + end = len(chars) + } else { + if !letters && !numbers { + end = math.MaxInt32 + } else { + end = 'z' + 1 + start = ' ' + } + } + } else { + if end <= start { + err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) must be greater than start (%v)", end, start) + return "", err + } + + if chars != nil && end > len(chars) { + err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) cannot be greater than len(chars) (%v)", end, len(chars)) + return "", err + } + } + + buffer := make([]rune, count) + gap := end - start + + + // high-surrogates range, (\uD800-\uDBFF) = 55296 - 56319 + // low-surrogates range, (\uDC00-\uDFFF) = 56320 - 57343 + + for count != 0 { + count-- + var ch rune + if chars == nil { + ch = rune(random.Intn(gap) + start) + } else { + ch = chars[random.Intn(gap) + start] + } + + if letters && unicode.IsLetter(ch) || numbers && unicode.IsDigit(ch) || !letters && !numbers { + if ch >= 56320 && ch <= 57343 { // low surrogate range + if count == 0 { + count++ + } else { + // Insert low surrogate + buffer[count] = ch + count-- + // Insert high surrogate + buffer[count] = rune(55296 + random.Intn(128)) + } + } else if ch >= 55296 && ch <= 56191 { // High surrogates range (Partial) + if count == 0 { + count++ + } else { + // Insert low surrogate + buffer[count] = rune(56320 + random.Intn(128)) + count-- + // Insert high surrogate + buffer[count] = ch + } + } else if ch >= 56192 && ch <= 56319 { + // private high surrogate, skip it + count++ + } else { + // not one of the surrogates* + buffer[count] = ch + } + } else { + count++ + } + } + return string(buffer), nil +} diff --git a/vendor/github.com/aokoli/goutils/stringutils.go b/vendor/github.com/aokoli/goutils/stringutils.go new file mode 100644 index 000000000..6a956f25b --- /dev/null +++ b/vendor/github.com/aokoli/goutils/stringutils.go @@ -0,0 +1,232 @@ +/* +Copyright 2014 Alexander Okoli + +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 goutils + + +import ( + "fmt" + "unicode" + "bytes" + "strings" +) + +// Typically returned by functions where a searched item cannot be found +const INDEX_NOT_FOUND = -1 + + +/* +Abbreviate abbreviates a string using ellipses. This will turn the string "Now is the time for all good men" into "Now is the time for..." + +Specifically, the algorithm is as follows: + + - If str is less than maxWidth characters long, return it. + - Else abbreviate it to (str[0:maxWidth - 3] + "..."). + - If maxWidth is less than 4, return an illegal argument error. + - In no case will it return a string of length greater than maxWidth. + +Parameters: + str - the string to check + maxWidth - maximum length of result string, must be at least 4 + +Returns: + string - abbreviated string + error - if the width is too small +*/ +func Abbreviate (str string, maxWidth int) (string, error) { + return AbbreviateFull(str, 0, maxWidth) +} + + +/* +AbbreviateFull abbreviates a string using ellipses. This will turn the string "Now is the time for all good men" into "...is the time for..." +This function works like Abbreviate(string, int), but allows you to specify a "left edge" offset. Note that this left edge is not +necessarily going to be the leftmost character in the result, or the first character following the ellipses, but it will appear +somewhere in the result. +In no case will it return a string of length greater than maxWidth. + +Parameters: + str - the string to check + offset - left edge of source string + maxWidth - maximum length of result string, must be at least 4 + +Returns: + string - abbreviated string + error - if the width is too small +*/ +func AbbreviateFull (str string, offset int, maxWidth int) (string, error) { + if str == "" { + return "", nil + } + if maxWidth < 4 { + err := fmt.Errorf("stringutils illegal argument: Minimum abbreviation width is 4") + return "", err + } + if len(str) <= maxWidth { + return str, nil + } + if offset > len(str) { + offset = len(str) + } + if len(str) - offset < (maxWidth - 3) { // 15 - 5 < 10 - 3 = 10 < 7 + offset = len(str) - (maxWidth - 3) + } + abrevMarker := "..." + if offset <= 4 { + return str[0:maxWidth - 3] + abrevMarker, nil// str.substring(0, maxWidth - 3) + abrevMarker; + } + if maxWidth < 7 { + err := fmt.Errorf("stringutils illegal argument: Minimum abbreviation width with offset is 7") + return "", err + } + if (offset + maxWidth - 3) < len(str) { // 5 + (10-3) < 15 = 12 < 15 + abrevStr, _ := Abbreviate(str[offset:len(str)], (maxWidth - 3)) + return abrevMarker + abrevStr, nil// abrevMarker + abbreviate(str.substring(offset), maxWidth - 3); + } + return abrevMarker + str[(len(str) - (maxWidth - 3)):len(str)], nil // abrevMarker + str.substring(str.length() - (maxWidth - 3)); +} + + +/* +DeleteWhiteSpace deletes all whitespaces from a string as defined by unicode.IsSpace(rune). +It returns the string without whitespaces. + +Parameter: + str - the string to delete whitespace from, may be nil + +Returns: + the string without whitespaces +*/ +func DeleteWhiteSpace(str string) string { + if str == "" { + return str + } + sz := len(str) + var chs bytes.Buffer + count := 0 + for i := 0; i < sz; i++ { + ch := rune(str[i]) + if !unicode.IsSpace(ch) { + chs.WriteRune(ch) + count++ + } + } + if count == sz { + return str + } + return chs.String() +} + + +/* +IndexOfDifference compares two strings, and returns the index at which the strings begin to differ. + +Parameters: + str1 - the first string + str2 - the second string + +Returns: + the index where str1 and str2 begin to differ; -1 if they are equal +*/ +func IndexOfDifference(str1 string, str2 string) int { + if str1 == str2 { + return INDEX_NOT_FOUND + } + if IsEmpty(str1) || IsEmpty(str2) { + return 0 + } + var i int; + for i = 0; i < len(str1) && i < len(str2); i++ { + if rune(str1[i]) != rune(str2[i]) { + break + } + } + if i < len(str2) || i < len(str1) { + return i + } + return INDEX_NOT_FOUND +} + + + +/* +IsBlank checks if a string is whitespace or empty (""). Observe the following behavior: + + goutils.IsBlank("") = true + goutils.IsBlank(" ") = true + goutils.IsBlank("bob") = false + goutils.IsBlank(" bob ") = false + +Parameter: + str - the string to check + +Returns: + true - if the string is whitespace or empty ("") +*/ +func IsBlank(str string) bool { + strLen := len(str) + if str == "" || strLen == 0 { + return true + } + for i := 0; i < strLen; i++ { + if unicode.IsSpace(rune(str[i])) == false { + return false + } + } + return true +} + + +/* +IndexOf returns the index of the first instance of sub in str, with the search beginning from the +index start point specified. -1 is returned if sub is not present in str. + +An empty string ("") will return -1 (INDEX_NOT_FOUND). A negative start position is treated as zero. +A start position greater than the string length returns -1. + +Parameters: + str - the string to check + sub - the substring to find + start - the start position; negative treated as zero + +Returns: + the first index where the sub string was found (always >= start) +*/ +func IndexOf(str string, sub string, start int) int { + + if (start < 0) { + start = 0 + } + + if len(str) < start { + return INDEX_NOT_FOUND + } + + if IsEmpty(str) || IsEmpty(sub) { + return INDEX_NOT_FOUND + } + + partialIndex := strings.Index(str[start:len(str)], sub) + if partialIndex == -1 { + return INDEX_NOT_FOUND + } + return partialIndex + start +} + +// IsEmpty checks if a string is empty (""). Returns true if empty, and false otherwise. +func IsEmpty(str string) bool { + return len(str) == 0 +} diff --git a/vendor/github.com/aokoli/goutils/wordutils.go b/vendor/github.com/aokoli/goutils/wordutils.go new file mode 100644 index 000000000..872964af0 --- /dev/null +++ b/vendor/github.com/aokoli/goutils/wordutils.go @@ -0,0 +1,365 @@ +/* +Copyright 2014 Alexander Okoli + +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 goutils provides utility functions to manipulate strings in various ways. +The code snippets below show examples of how to use goutils. Some functions return +errors while others do not, so usage would vary as a result. + +Example: + + package main + + import ( + "fmt" + "github.com/aokoli/goutils" + ) + + func main() { + + // EXAMPLE 1: A goutils function which returns no errors + fmt.Println (goutils.Initials("John Doe Foo")) // Prints out "JDF" + + + + // EXAMPLE 2: A goutils function which returns an error + rand1, err1 := goutils.Random (-1, 0, 0, true, true) + + if err1 != nil { + fmt.Println(err1) // Prints out error message because -1 was entered as the first parameter in goutils.Random(...) + } else { + fmt.Println(rand1) + } + } +*/ +package goutils + +import ( + "bytes" + "strings" + "unicode" +) + +// VERSION indicates the current version of goutils +const VERSION = "1.0.0" + +/* +Wrap wraps a single line of text, identifying words by ' '. +New lines will be separated by '\n'. Very long words, such as URLs will not be wrapped. +Leading spaces on a new line are stripped. Trailing spaces are not stripped. + +Parameters: + str - the string to be word wrapped + wrapLength - the column (a column can fit only one character) to wrap the words at, less than 1 is treated as 1 + +Returns: + a line with newlines inserted +*/ +func Wrap (str string, wrapLength int) string { + return WrapCustom (str, wrapLength, "", false) +} + +/* +WrapCustom wraps a single line of text, identifying words by ' '. +Leading spaces on a new line are stripped. Trailing spaces are not stripped. + +Parameters: + str - the string to be word wrapped + wrapLength - the column number (a column can fit only one character) to wrap the words at, less than 1 is treated as 1 + newLineStr - the string to insert for a new line, "" uses '\n' + wrapLongWords - true if long words (such as URLs) should be wrapped + +Returns: + a line with newlines inserted +*/ +func WrapCustom (str string, wrapLength int, newLineStr string, wrapLongWords bool) string { + + if str == "" { + return "" + } + if newLineStr == "" { + newLineStr = "\n" // TODO Assumes "\n" is seperator. Explore SystemUtils.LINE_SEPARATOR from Apache Commons + } + if wrapLength < 1 { + wrapLength = 1 + } + + inputLineLength := len(str) + offset := 0 + + var wrappedLine bytes.Buffer + + for inputLineLength-offset > wrapLength { + + if rune(str[offset]) == ' ' { + offset++ + continue + } + + end := wrapLength + offset + 1 + spaceToWrapAt := strings.LastIndex(str[offset:end], " ") + offset + + if spaceToWrapAt >= offset { + // normal word (not longer than wrapLength) + wrappedLine.WriteString(str[offset:spaceToWrapAt]) + wrappedLine.WriteString(newLineStr) + offset = spaceToWrapAt + 1 + + } else { + // long word or URL + if wrapLongWords { + end := wrapLength + offset + // long words are wrapped one line at a time + wrappedLine.WriteString(str[offset:end]) + wrappedLine.WriteString(newLineStr) + offset += wrapLength + } else { + // long words aren't wrapped, just extended beyond limit + end := wrapLength + offset + spaceToWrapAt = strings.IndexRune(str[end:len(str)], ' ') + end + if spaceToWrapAt >= 0 { + wrappedLine.WriteString(str[offset:spaceToWrapAt]) + wrappedLine.WriteString(newLineStr) + offset = spaceToWrapAt + 1 + } else { + wrappedLine.WriteString(str[offset:len(str)]) + offset = inputLineLength + } + } + } + } + + wrappedLine.WriteString(str[offset:len(str)]) + + return wrappedLine.String() + +} + + +/* +Capitalize capitalizes all the delimiter separated words in a string. Only the first letter of each word is changed. +To convert the rest of each word to lowercase at the same time, use CapitalizeFully(str string, delimiters ...rune). +The delimiters represent a set of characters understood to separate words. The first string character +and the first non-delimiter character after a delimiter will be capitalized. A "" input string returns "". +Capitalization uses the Unicode title case, normally equivalent to upper case. + +Parameters: + str - the string to capitalize + delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter + +Returns: + capitalized string +*/ +func Capitalize (str string, delimiters ...rune) string { + + var delimLen int + + if delimiters == nil { + delimLen = -1 + } else { + delimLen = len(delimiters) + } + + if str == "" || delimLen == 0 { + return str; + } + + buffer := []rune(str) + capitalizeNext := true + for i := 0; i < len(buffer); i++ { + ch := buffer[i] + if isDelimiter(ch, delimiters...) { + capitalizeNext = true + } else if capitalizeNext { + buffer[i] = unicode.ToTitle(ch) + capitalizeNext = false + } + } + return string(buffer) + +} + + + +/* +CapitalizeFully converts all the delimiter separated words in a string into capitalized words, that is each word is made up of a +titlecase character and then a series of lowercase characters. The delimiters represent a set of characters understood +to separate words. The first string character and the first non-delimiter character after a delimiter will be capitalized. +Capitalization uses the Unicode title case, normally equivalent to upper case. + +Parameters: + str - the string to capitalize fully + delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter + +Returns: + capitalized string +*/ +func CapitalizeFully (str string, delimiters ...rune) string { + + var delimLen int + + if delimiters == nil { + delimLen = -1 + } else { + delimLen = len(delimiters) + } + + + if str == "" || delimLen == 0 { + return str; + } + str = strings.ToLower(str) + return Capitalize(str, delimiters...); +} + + +/* +Uncapitalize uncapitalizes all the whitespace separated words in a string. Only the first letter of each word is changed. +The delimiters represent a set of characters understood to separate words. The first string character and the first non-delimiter +character after a delimiter will be uncapitalized. Whitespace is defined by unicode.IsSpace(char). + +Parameters: + str - the string to uncapitalize fully + delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter + +Returns: + uncapitalized string +*/ +func Uncapitalize (str string, delimiters ...rune) string { + + var delimLen int + + if delimiters == nil { + delimLen = -1 + } else { + delimLen = len(delimiters) + } + + if str == "" || delimLen == 0 { + return str; + } + + buffer := []rune(str) + uncapitalizeNext := true // TODO Always makes capitalize/un apply to first char. + for i := 0; i < len(buffer); i++ { + ch := buffer[i] + if isDelimiter(ch, delimiters...) { + uncapitalizeNext = true + } else if uncapitalizeNext { + buffer[i] = unicode.ToLower(ch) + uncapitalizeNext = false + } + } + return string(buffer) +} + + +/* +SwapCase swaps the case of a string using a word based algorithm. + +Conversion algorithm: + + Upper case character converts to Lower case + Title case character converts to Lower case + Lower case character after Whitespace or at start converts to Title case + Other Lower case character converts to Upper case + Whitespace is defined by unicode.IsSpace(char). + +Parameters: + str - the string to swap case + +Returns: + the changed string +*/ +func SwapCase(str string) string { + if str == "" { + return str + } + buffer := []rune(str) + + whitespace := true + + for i := 0; i < len(buffer); i++ { + ch := buffer[i] + if unicode.IsUpper(ch) { + buffer[i] = unicode.ToLower(ch) + whitespace = false + } else if unicode.IsTitle(ch) { + buffer[i] = unicode.ToLower(ch) + whitespace = false + } else if unicode.IsLower(ch) { + if whitespace { + buffer[i] = unicode.ToTitle(ch) + whitespace = false + } else { + buffer[i] = unicode.ToUpper(ch) + } + } else { + whitespace = unicode.IsSpace(ch) + } + } + return string(buffer); +} + + +/* +Initials extracts the initial letters from each word in the string. The first letter of the string and all first +letters after the defined delimiters are returned as a new string. Their case is not changed. If the delimiters +parameter is excluded, then Whitespace is used. Whitespace is defined by unicode.IsSpacea(char). An empty delimiter array returns an empty string. + +Parameters: + str - the string to get initials from + delimiters - set of characters to determine words, exclusion of this parameter means whitespace would be delimeter +Returns: + string of initial letters +*/ +func Initials(str string, delimiters ...rune) string { + if str == "" { + return str + } + if delimiters != nil && len(delimiters) == 0 { + return "" + } + strLen := len(str) + var buf bytes.Buffer + lastWasGap := true + for i := 0; i < strLen; i++ { + ch := rune(str[i]) + + if isDelimiter(ch, delimiters...) { + lastWasGap = true + } else if lastWasGap { + buf.WriteRune(ch) + lastWasGap = false + } + } + return buf.String() + } + + + + // private function (lower case func name) +func isDelimiter(ch rune, delimiters ...rune) bool { + if delimiters == nil { + return unicode.IsSpace(ch) + } + for _, delimiter := range delimiters { + if ch == delimiter { + return true + } + } + return false +} \ No newline at end of file diff --git a/tools/infrakit.hyperkit/vendor/github.com/armon/go-radix/LICENSE b/vendor/github.com/armon/go-radix/LICENSE similarity index 100% rename from tools/infrakit.hyperkit/vendor/github.com/armon/go-radix/LICENSE rename to vendor/github.com/armon/go-radix/LICENSE diff --git a/tools/infrakit.hyperkit/vendor/github.com/armon/go-radix/README.md b/vendor/github.com/armon/go-radix/README.md similarity index 100% rename from tools/infrakit.hyperkit/vendor/github.com/armon/go-radix/README.md rename to vendor/github.com/armon/go-radix/README.md diff --git a/tools/infrakit.hyperkit/vendor/github.com/armon/go-radix/radix.go b/vendor/github.com/armon/go-radix/radix.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/github.com/armon/go-radix/radix.go rename to vendor/github.com/armon/go-radix/radix.go diff --git a/vendor/github.com/docker/infrakit/LICENSE b/vendor/github.com/docker/infrakit/LICENSE new file mode 100644 index 000000000..6d630cf59 --- /dev/null +++ b/vendor/github.com/docker/infrakit/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 Docker, Inc. + + 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. diff --git a/vendor/github.com/docker/infrakit/README.md b/vendor/github.com/docker/infrakit/README.md new file mode 100644 index 000000000..dd6901c5a --- /dev/null +++ b/vendor/github.com/docker/infrakit/README.md @@ -0,0 +1,235 @@ +InfraKit +======== + +[![Circle CI](https://circleci.com/gh/docker/infrakit.png?style=shield&circle-token=50d2063f283f98b7d94746416c979af3102275b5)](https://circleci.com/gh/docker/infrakit) +[![Go Report Card](https://goreportcard.com/badge/github.com/docker/infrakit)](https://goreportcard.com/report/github.com/docker/infrakit) +[![codecov.io](https://codecov.io/github/docker/infrakit/coverage.svg?branch=master&token=z08ZKeIJfA)](https://codecov.io/github/docker/infrakit?branch=master) + +_InfraKit_ is a toolkit for creating and managing declarative, self-healing infrastructure. +It breaks infrastructure automation down into simple, pluggable components. These components work together to actively +ensure the infrastructure state matches the user's specifications. +Although _InfraKit_ emphasizes primitives for building self-healing infrastructure, it also can be used passively like +conventional tools. + +To get started, try the [tutorial](docs/tutorial.md). + +### Who InfraKit is for + +_InfraKit_ is designed to support setup and management of base infrastructure. For example, it can help you manage a +system like a cluster or container orchestrator, ideally relieving you of building custom release and maintenance tools. +As a result, it is a low-level tool intended to be used by infrastructure operators directly or indirectly +(as a toolkit) through a higher-level tool. Since _InfraKit_ is pluggable, it allows you to manage resources in diverse +environments while using shared components and consistent interfaces. + +## Plugins +_InfraKit_ makes extensive use of _Plugins_ to manage arbitrary systems in diverse environments, which can be composed +to meet different needs. + +See the [plugins](docs/plugins) documentation for more details. + + +## Building +### Your Environment + +Make sure you check out the project following a convention for building Go projects. For example, + +```shell + +# Install Go - https://golang.org/dl/ +# Assuming your go compiler is in /usr/local/go +export PATH=/usr/local/go/bin:$PATH + +# Your dev environment +mkdir -p ~/go +export GOPATH=!$ +export PATH=$GOPATH/bin:$PATH + +mkdir -p ~/go/src/github.com/docker +cd !$ +git clone git@github.com:docker/infrakit.git +cd infrakit +``` + +We recommended go version 1.7.1 or greater for all platforms. + +Also install a few build tools: +```shell +make get-tools +``` + +### Running tests +```shell +$ make ci +``` + +### Binaries +```shell +$ make binaries +``` +Executables will be placed in the `./build` directory. +This will produce binaries for tools and several reference Plugin implementations: + + [`infrakit`](cmd/cli/README.md): a command line interface to interact with plugins + + [`infrakit-group-default`](cmd/group/README.md): the default [Group plugin](./pkg/spi/group) + + [`infrakit-instance-file`](examples/instance/file): an Instance plugin using dummy files to represent instances + + [`infrakit-instance-terraform`](examples/instance/terraform): + an Instance plugin integrating [Terraform](https://www.terraform.io) + + [`infrakit-instance-vagrant`](examples/instance/vagrant): + an Instance plugin using [Vagrant](https://www.vagrantup.com/) + + [`infrakit-instance-maas`](examples/instance/maas): + an Instance plugin using [MaaS](https://maas.io) + + [`infrakit-flavor-vanilla`](examples/flavor/vanilla): + a Flavor plugin for plain vanilla set up with user data and labels + + [`infrakit-flavor-zookeeper`](examples/flavor/zookeeper): + a Flavor plugin for [Apache ZooKeeper](https://zookeeper.apache.org/) ensemble members + + [`infrakit-flavor-swarm`](examples/flavor/swarm): + a Flavor plugin for Docker in [Swarm mode](https://docs.docker.com/engine/swarm/). + +All provided binaries have a `help` sub-command to get usage and a `version` sub-command to identify the build revision. + + +# Design + +## Configuration +_InfraKit_ uses JSON for configuration because it is composable and a widely accepted format for many +infrastructure SDKs and tools. Since the system is highly component-driven, our JSON format follows +simple patterns to support the composition of components. + +A common pattern for a JSON object looks like this: + +```json +{ + "SomeKey": "ValueForTheKey", + "Properties": { + } +} +``` + +There is only one `Properties` field in this JSON and its value is a JSON object. The opaque +JSON value for `Properties` is decoded via the Go `Spec` struct defined within the package of the plugin -- +for example -- [`vanilla.Spec`](pkg/plugin/flavor/vanilla/flavor.go). + +The JSON above is a _value_, but the type of the value belongs outside the structure. For example, the +default Group [Spec](pkg/plugin/group/types/types.go) is composed of an Instance plugin, a Flavor plugin, and an +Allocation: + +```json +{ + "ID": "name-of-the-group", + "Properties": { + "Allocation": { + }, + "Instance": { + "Plugin": "name-of-the-instance-plugin", + "Properties": { + } + }, + "Flavor": { + "Plugin": "name-of-the-flavor-plugin", + "Properties": { + } + } + } +} +``` +The group's Spec has `Instance` and `Flavor` fields which are used to indicate the type, and the value of the +fields follow the pattern of `` and `Properties` as shown above. + +The `Allocation` determines how the Group is managed. Allocation has two properties: + - `Size`: an integer for the number of instances to maintain in the Group + - `LogicalIDs`: a list of string identifiers, one will be associated with each Instance + +Exactly one of these fields must be set, which defines whether the Group is treated as 'cattle' (`Size`) or 'pets' +(`LogicalIDs`). It is up to the Instance and Flavor plugins to determine how to use `LogicalID` values. + +As an example, if you wanted to manage a Group of NGINX servers, you could +write a custom Group plugin for ultimate customization. The most concise configuration looks something like this: + +```json +{ + "ID": "nginx", + "Plugin": "my-nginx-group-plugin", + "Properties": { + "port": 8080 + } +} +```` + +However, you would likely prefer to use the default Group plugin and implement a Flavor plugin to focus on +application-specific behavior. This gives you immediate support for any infrastructure that has an Instance plugin. +Your resulting configuration might look something like this: + +```json +{ + "ID": "nginx", + "Plugin": "group", + "Properties": { + "Allocation": { + "Size": 10 + }, + "Instance": { + "Plugin": "aws", + "Properties": { + "region": "us-west-2", + "ami": "ami-123456" + } + }, + "Flavor": { + "Plugin": "nginx", + "Properties": { + "port": 8080 + } + } + } +} +``` + +Once the configuration is ready, you will tell a Group plugin to + + watch it + + update it + + destroy it + +Watching the group as specified in the configuration means that the Group plugin will create +the instances if they don't already exist. New instances will be created if for any reason +existing instances have disappeared such that the state doesn't match your specifications. + +Updating the group tells the Group plugin that your configuration may have changed. It will +then determine the changes necessary to ensure the state of the infrastructure matches the new +specification. + +## Docs + +Additional documentation can be found [here](docs). + +## Reporting security issues + +The maintainers take security seriously. If you discover a security issue, +please bring it to their attention right away! + +Please **DO NOT** file a public issue, instead send your report privately to +[security@docker.com](mailto:security@docker.com). + +Security reports are greatly appreciated and we will publicly thank you for it. +We also like to send gifts—if you're into Docker schwag, make sure to let +us know. We currently do not offer a paid security bounty program, but are not +ruling it out in the future. + + +## Design goals + +_InfraKit_ is currently focused on supporting setup and management of base infrastructure, such as a cluster +orchestrator. The image below illustrates an architecture we are working towards supporting - a Docker cluster in Swarm +mode. + +![arch image](docs/images/arch.png) + +This configuration co-locates _InfraKit_ with Swarm manager nodes and offers high availability of _InfraKit_ itself and +Swarm managers (using attached storage). _InfraKit_ is shown managing two groups - managers and workers that will be +continuously monitored, and may be modified with rolling updates. + +Countless configurations are possible with _InfraKit_, but we believe achieving support for this configuration will +enable a large number of real-world use cases. + +## Copyright and license + +Copyright © 2016 Docker, Inc. All rights reserved. Released under the Apache 2.0 +license. See [LICENSE](LICENSE) for the full license text. diff --git a/vendor/github.com/docker/infrakit/pkg/broker/server/interceptor.go b/vendor/github.com/docker/infrakit/pkg/broker/server/interceptor.go new file mode 100644 index 000000000..6178b25f2 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/broker/server/interceptor.go @@ -0,0 +1,74 @@ +package server + +import ( + "fmt" + "net/http" + "strings" + + log "github.com/Sirupsen/logrus" +) + +// Interceptor implements http Handler and is used to intercept incoming requests to subscribe +// to topics and perform some validations before allowing the subscription to be established. +// Tasks that the interceptor can do include authn and authz, topic validation, etc. +type Interceptor struct { + + // Do is the body of the http handler -- required + Do http.HandlerFunc + + // Pre is called to before actual subscription to a topic happens. + // This is the hook where validation and authentication / authorization checks happen. + Pre func(topic string, headers map[string][]string) error + + // Post is called when the client disconnects. This is optional. + Post func(topic string) +} + +// ServeHTTP calls the before and after subscribe methods. +func (i *Interceptor) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + + topic := clean(req.URL.Query().Get("topic")) + + // need to strip out the / because it was added by the client + if strings.Index(topic, "/") == 0 { + topic = topic[1:] + } + + err := i.Pre(topic, req.Header) + if err != nil { + log.Warningln("Error:", err) + http.Error(rw, err.Error(), getStatusCode(err)) + return + } + + i.Do.ServeHTTP(rw, req) + + if i.Post != nil { + i.Post(topic) + } +} + +func getStatusCode(e error) int { + switch e.(type) { + case ErrInvalidTopic: + return http.StatusNotFound + case ErrNotAuthorized: + return http.StatusUnauthorized + default: + return http.StatusInternalServerError + } +} + +// ErrInvalidTopic is the error raised when topic is invalid +type ErrInvalidTopic string + +func (e ErrInvalidTopic) Error() string { + return fmt.Sprintf("invalid topic: %s", string(e)) +} + +// ErrNotAuthorized is the error raised when the user isn't authorized +type ErrNotAuthorized string + +func (e ErrNotAuthorized) Error() string { + return fmt.Sprintf("not authorized: %s", string(e)) +} diff --git a/vendor/github.com/docker/infrakit/pkg/broker/server/server.go b/vendor/github.com/docker/infrakit/pkg/broker/server/server.go new file mode 100644 index 000000000..842d5e2dd --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/broker/server/server.go @@ -0,0 +1,27 @@ +package server + +import ( + "net" + "net/http" +) + +// ListenAndServeOnSocket starts a minimal server (mostly for testing) listening at the given unix socket path. +func ListenAndServeOnSocket(socketPath string, optionalURLPattern ...string) (*Broker, error) { + urlPattern := "/" + if len(optionalURLPattern) > 0 { + urlPattern = optionalURLPattern[0] + } + listener, err := net.Listen("unix", socketPath) + if err != nil { + return nil, err + } + broker := NewBroker() + mux := http.NewServeMux() + mux.Handle(urlPattern, broker) + httpServer := &http.Server{ + Handler: mux, + } + go httpServer.Serve(listener) + + return broker, nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/broker/server/sse.go b/vendor/github.com/docker/infrakit/pkg/broker/server/sse.go new file mode 100644 index 000000000..9a10d6d33 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/broker/server/sse.go @@ -0,0 +1,266 @@ +package server + +import ( + "bytes" + "fmt" + "net/http" + "strings" + "time" + + log "github.com/Sirupsen/logrus" + "github.com/armon/go-radix" + "github.com/docker/infrakit/pkg/types" +) + +// the amount of time to wait when pushing a message to +// a slow client or a client that closed after `range clients` started. +const patience time.Duration = time.Second * 1 + +type subscription struct { + topic string + exactMatch bool + ch chan []byte +} + +type event struct { + topic string + data []byte +} + +// Broker is the event message broker +type Broker struct { + + // Close this to stop + stop chan struct{} + + // Close this to stop the run loop + finish chan struct{} + + // Events are pushed to this channel by the main events-gathering routine + notifier chan *event + + // New client connections + newClients chan subscription + + // Closed client connections + closingClients chan subscription + + // Client connections registry + clients *radix.Tree + + // how many clients + count int +} + +// NewBroker returns an instance of the broker +func NewBroker() *Broker { + b := &Broker{ + stop: make(chan struct{}), + finish: make(chan struct{}), + notifier: make(chan *event, 1), + newClients: make(chan subscription), + closingClients: make(chan subscription), + clients: radix.New(), + } + go b.run() + return b +} + +// Stop stops the broker and exits the goroutine +func (b *Broker) Stop() { + close(b.stop) +} + +func clean(topic string) string { + if len(topic) == 0 || topic == "." { + return "/" + } + + if topic[0] != '/' { + return "/" + topic + } + return topic +} + +//Check the topic ends with `/` +func checkExactMatch(topic string) bool { + return strings.LastIndex(topic, "/") != len(topic)-1 +} + +// Publish publishes a message at the topic +func (b *Broker) Publish(topic string, data interface{}, optionalTimeout ...time.Duration) error { + any, err := types.AnyValue(data) + if err != nil { + return err + } + + topic = clean(topic) + + if len(optionalTimeout) > 0 { + select { + case b.notifier <- &event{topic: topic, data: any.Bytes()}: + case <-time.After(optionalTimeout[0]): + return fmt.Errorf("timeout sending %v", topic) + } + } else { + b.notifier <- &event{topic: topic, data: any.Bytes()} + } + + return nil +} + +// ServerHTTP implements the HTTP handler +func (b *Broker) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + defer func() { + if v := recover(); v != nil { + log.Warningln("broker.ServeHTTP recovered:", v) + } + }() + + topic := clean(req.URL.Query().Get("topic")) + + // flusher is required for streaming + flusher, ok := rw.(http.Flusher) + if !ok { + http.Error(rw, "Streaming unsupported!", http.StatusInternalServerError) + return + } + + rw.Header().Set("Content-Type", "text/event-stream") + rw.Header().Set("Cache-Control", "no-cache") + rw.Header().Set("Connection", "keep-alive") + rw.Header().Set("Access-Control-Allow-Origin", "*") + + // Each connection registers its own message channel with the Broker's connections registry + messageChan := make(chan []byte) + + // Signal the broker that we have a new connection + b.newClients <- subscription{topic: topic, exactMatch: checkExactMatch(topic), ch: messageChan} + + // Remove this client from the map of connected clients + // when this handler exits. + defer func() { + b.closingClients <- subscription{topic: topic, ch: messageChan} + }() + + // Listen to connection close and un-register messageChan + notify := rw.(http.CloseNotifier).CloseNotify() + + for { + select { + case <-b.stop: + close(b.finish) + return + + case <-notify: + return + default: + + // Write to the ResponseWriter + // Server Sent Events compatible + fmt.Fprintf(rw, "data: %s\n\n", <-messageChan) + + // Flush the data immediatly instead of buffering it for later. + flusher.Flush() + } + } +} + +func (b *Broker) run() { + for { + select { + case <-b.finish: + + // Disconnect all clients + b.clients.Walk( + func(key string, value interface{}) bool { + chset, ok := value.(map[chan []byte]bool) + if !ok { + panic("assert-failed") + } + for ch := range chset { + log.Infoln("Closing client connection at", key, "ch=", ch) + close(ch) + } + return false + }) + + log.Infoln("Broker finished") + return + + case subscription := <-b.newClients: + + // A new client has connected. + // Register their message channel + subs := map[chan []byte]bool{subscription.ch: subscription.exactMatch} + v, has := b.clients.Get(subscription.topic) + if has { + if v, ok := v.(map[chan []byte]bool); !ok { + panic("assert-failed: not a map of channels") + } else { + v[subscription.ch] = subscription.exactMatch + subs = v + } + } + + b.clients.Insert(subscription.topic, subs) + b.count++ + log.Infof("Connected: topic=%s => %d registered clients, ch=%v", subscription.topic, b.count, subscription.ch) + + case subscription := <-b.closingClients: + + // A client has dettached and we want to stop sending messages + if v, has := b.clients.Get(subscription.topic); has { + if subs, ok := v.(map[chan []byte]bool); !ok { + panic("assert-failed: not a map of channels") + + } else { + + delete(subs, subscription.ch) + + if len(subs) == 0 { + b.clients.Delete(subscription.topic) + } else { + b.clients.Insert(subscription.topic, subs) + } + + b.count-- + log.Infof("Disconnected: topic=%s => %d registered clients, ch=%v", subscription.topic, b.count, subscription.ch) + } + } + + case event, open := <-b.notifier: + + if !open { + log.Infoln("Stopping broker") + return + } + + // Remove any \n because it's meaningful in SSE spec. + // We could use base64 encode, but it hurts interoperability with browser/ javascript clients. + data := bytes.Replace(event.data, []byte("\n"), nil, -1) + + b.clients.WalkPath(event.topic, + + func(key string, value interface{}) bool { + chset, ok := value.(map[chan []byte]bool) + if !ok { + panic("assert-failed") + } + + for ch, exact := range chset { + if exact && event.topic != key { + return false + } + select { + case ch <- data: + case <-time.After(patience): + log.Print("Skipping client.") + } + } + return false + }) + } + } + +} diff --git a/vendor/github.com/docker/infrakit/pkg/cli/logging.go b/vendor/github.com/docker/infrakit/pkg/cli/logging.go new file mode 100644 index 000000000..2a36e14e2 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/cli/logging.go @@ -0,0 +1,16 @@ +package cli + +import log "github.com/Sirupsen/logrus" + +// DefaultLogLevel is the default log level value. +var DefaultLogLevel = len(log.AllLevels) - 2 + +// SetLogLevel adjusts the logrus level. +func SetLogLevel(level int) { + if level > len(log.AllLevels)-1 { + level = len(log.AllLevels) - 1 + } else if level < 0 { + level = 0 + } + log.SetLevel(log.AllLevels[level]) +} diff --git a/vendor/github.com/docker/infrakit/pkg/cli/serverutil.go b/vendor/github.com/docker/infrakit/pkg/cli/serverutil.go new file mode 100644 index 000000000..a13a74ba9 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/cli/serverutil.go @@ -0,0 +1,47 @@ +package cli + +import ( + "fmt" + "io/ioutil" + "os" + "path" + + log "github.com/Sirupsen/logrus" + "github.com/docker/infrakit/pkg/discovery" + "github.com/docker/infrakit/pkg/rpc/server" +) + +// EnsureDirExists makes sure the directory where the socket file will be placed exists. +func EnsureDirExists(dir string) { + os.MkdirAll(dir, 0700) +} + +// RunPlugin runs a plugin server, advertising with the provided name for discovery. +// The plugin should conform to the rpc call convention as implemented in the rpc package. +func RunPlugin(name string, plugin server.VersionedInterface, more ...server.VersionedInterface) { + + dir := discovery.Dir() + EnsureDirExists(dir) + + socketPath := path.Join(dir, name) + pidPath := path.Join(dir, name+".pid") + + stoppable, err := server.StartPluginAtPath(socketPath, plugin, more...) + if err != nil { + log.Error(err) + } + + // write PID file + err = ioutil.WriteFile(pidPath, []byte(fmt.Sprintf("%v", os.Getpid())), 0644) + if err != nil { + log.Error(err) + } + log.Infoln("PID file at", pidPath) + if stoppable != nil { + stoppable.AwaitStopped() + } + + // clean up + os.Remove(pidPath) + log.Infoln("Removed PID file at", pidPath) +} diff --git a/vendor/github.com/docker/infrakit/pkg/cli/version.go b/vendor/github.com/docker/infrakit/pkg/cli/version.go new file mode 100644 index 000000000..c2c14e407 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/cli/version.go @@ -0,0 +1,45 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var ( + // Version is the build release identifier. + Version = "Unspecified" + + // Revision is the build source control revision. + Revision = "Unspecified" +) + +var info = map[string]map[string]interface{}{} + +// RegisterInfo allows any packages that use this register additional information to be displayed by the command. +// For example, a swarm flavor could register the docker api version. This allows us to selectively incorporate +// only required dependencies based on package registration (in their init()) without explicitly pulling unused +// dependencies. +func RegisterInfo(key string, data map[string]interface{}) { + info[key] = data +} + +// VersionCommand creates a cobra Command that prints build version information. +func VersionCommand() *cobra.Command { + return &cobra.Command{ + Use: "version", + Short: "print build version information", + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("\n%-24s: %v", "Version", Version) + fmt.Printf("\n%-24s: %v", "Revision", Revision) + for k, m := range info { + fmt.Printf("\n\n%s", k) + for kk, vv := range m { + fmt.Printf("\n%-24s: %v", kk, vv) + } + fmt.Printf("\n") + } + fmt.Println() + }, + } +} diff --git a/vendor/github.com/docker/infrakit/pkg/discovery/dir.go b/vendor/github.com/docker/infrakit/pkg/discovery/dir.go new file mode 100644 index 000000000..e8ffddbec --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/discovery/dir.go @@ -0,0 +1,106 @@ +package discovery + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sync" + + log "github.com/Sirupsen/logrus" + "github.com/docker/infrakit/pkg/plugin" +) + +type errNotUnixSocket string + +func (e errNotUnixSocket) Error() string { + return string(e) +} + +// IsErrNotUnixSocket returns true if the error is due to the file not being a valid unix socket. +func IsErrNotUnixSocket(e error) bool { + _, is := e.(errNotUnixSocket) + return is +} + +type dirPluginDiscovery struct { + dir string + lock sync.Mutex +} + +// Find returns a plugin by name +func (r *dirPluginDiscovery) Find(name plugin.Name) (*plugin.Endpoint, error) { + lookup, _ := name.GetLookupAndType() + plugins, err := r.List() + if err != nil { + return nil, err + } + + p, exists := plugins[lookup] + if !exists { + return nil, fmt.Errorf("Plugin not found: %s (looked up using %s)", name, lookup) + } + + return p, nil +} + +// newDirPluginDiscovery creates a registry instance with the given file directory path. +func newDirPluginDiscovery(dir string) (*dirPluginDiscovery, error) { + d := &dirPluginDiscovery{dir: dir} + + // Perform a dummy read to catch obvious issues early (such as the directory not existing). + _, err := d.List() + return d, err +} + +func (r *dirPluginDiscovery) dirLookup(entry os.FileInfo) (*plugin.Endpoint, error) { + if entry.Mode()&os.ModeSocket != 0 { + socketPath := filepath.Join(r.dir, entry.Name()) + return &plugin.Endpoint{ + Protocol: "unix", + Address: socketPath, + Name: entry.Name(), + }, nil + } + + return nil, errNotUnixSocket(fmt.Sprintf("File is not a socket: %s", entry)) +} + +// List returns a list of plugins known, keyed by the name +func (r *dirPluginDiscovery) List() (map[string]*plugin.Endpoint, error) { + + r.lock.Lock() + defer r.lock.Unlock() + + log.Debugln("Opening:", r.dir) + entries, err := ioutil.ReadDir(r.dir) + if err != nil { + return nil, err + } + + plugins := map[string]*plugin.Endpoint{} + + for _, entry := range entries { + if !entry.IsDir() { + + instance, err := r.dirLookup(entry) + + if err != nil { + if !IsErrNotUnixSocket(err) { + log.Warningln("Loading plugin err=", err) + } + continue + } + + if instance == nil { + log.Warningln("Plugin in nil=") + continue + } + + log.Debugln("Discovered plugin at", instance.Address) + plugins[instance.Name] = instance + } + } + + return plugins, nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/discovery/discovery.go b/vendor/github.com/docker/infrakit/pkg/discovery/discovery.go new file mode 100644 index 000000000..9f962141e --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/discovery/discovery.go @@ -0,0 +1,60 @@ +package discovery + +import ( + "fmt" + "os" + "os/user" + "path" + + "github.com/docker/infrakit/pkg/plugin" +) + +// Plugins provides access to plugin discovery. +type Plugins interface { + // Find looks up the plugin by name. The name can be of the form $lookup[/$subtype]. See GetLookupAndType(). + Find(name plugin.Name) (*plugin.Endpoint, error) + List() (map[string]*plugin.Endpoint, error) +} + +const ( + // PluginDirEnvVar is the environment variable that may be used to customize the plugin discovery path. + PluginDirEnvVar = "INFRAKIT_PLUGINS_DIR" +) + +// Dir returns the directory to use for plugin discovery, which may be customized by the environment. +func Dir() string { + if pluginDir := os.Getenv(PluginDirEnvVar); pluginDir != "" { + return pluginDir + } + + home := os.Getenv("HOME") + if usr, err := user.Current(); err == nil { + home = usr.HomeDir + } + return path.Join(home, ".infrakit/plugins") +} + +// NewPluginDiscovery creates a plugin discovery based on the environment configuration. +func NewPluginDiscovery() (Plugins, error) { + return NewPluginDiscoveryWithDirectory(Dir()) +} + +// NewPluginDiscoveryWithDirectory creates a plugin discovery based on the directory given. +func NewPluginDiscoveryWithDirectory(pluginDir string) (Plugins, error) { + stat, err := os.Stat(pluginDir) + if err == nil { + if !stat.IsDir() { + return nil, fmt.Errorf("Plugin dir %s is a file", pluginDir) + } + } else { + if os.IsNotExist(err) { + if err := os.MkdirAll(pluginDir, 0700); err != nil { + return nil, fmt.Errorf("Failed to create plugin dir %s: %s", pluginDir, err) + } + } else { + return nil, fmt.Errorf("Failed to access plugin dir %s: %s", pluginDir, err) + } + } + + return newDirPluginDiscovery(pluginDir) +} diff --git a/vendor/github.com/docker/infrakit/pkg/plugin/metadata/path.go b/vendor/github.com/docker/infrakit/pkg/plugin/metadata/path.go new file mode 100644 index 000000000..4a2c5de84 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/plugin/metadata/path.go @@ -0,0 +1,30 @@ +package metadata + +import ( + "path/filepath" + "strings" + + "github.com/docker/infrakit/pkg/spi/metadata" +) + +// Path returns the path compoments of a / separated path +func Path(path string) metadata.Path { + return metadata.Path(strings.Split(filepath.Clean(path), "/")) +} + +// PathFromStrings returns the path from a list of strings +func PathFromStrings(a string, b ...string) metadata.Path { + if a != "" { + return metadata.Path(append([]string{a}, b...)) + } + return metadata.Path(b) +} + +// String returns the string representation of path +func String(p metadata.Path) string { + s := strings.Join([]string(p), "/") + if len(s) == 0 { + return "." + } + return s +} diff --git a/vendor/github.com/docker/infrakit/pkg/plugin/metadata/plugin.go b/vendor/github.com/docker/infrakit/pkg/plugin/metadata/plugin.go new file mode 100644 index 000000000..91bdb6ba3 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/plugin/metadata/plugin.go @@ -0,0 +1,90 @@ +package metadata + +import ( + log "github.com/Sirupsen/logrus" + "github.com/docker/infrakit/pkg/spi/metadata" + "github.com/docker/infrakit/pkg/types" +) + +// NewPluginFromData creates a plugin out of a simple data map. Note the updates to the map +// is not guarded and synchronized with the reads. +func NewPluginFromData(data map[string]interface{}) metadata.Plugin { + return &plugin{data: data} +} + +// NewPluginFromChannel returns a plugin implementation where reads and writes are serialized +// via channel of functions that have a view to the metadata. Closing the write channel stops +// the serialized read/writes and falls back to unserialized reads. +func NewPluginFromChannel(writes <-chan func(map[string]interface{})) metadata.Plugin { + + readChan := make(chan func(map[string]interface{})) + p := &plugin{reads: readChan} + + go func() { + + defer func() { + if r := recover(); r != nil { + log.Warningln("Plugin stopped:", r) + } + }() + + data := map[string]interface{}{} + for { + select { + case writer, open := <-writes: + if !open { + close(readChan) + p.reads = nil + return + } + writer(data) + + case reader := <-p.reads: + copy := data + reader(copy) + } + } + }() + return p +} + +type plugin struct { + data map[string]interface{} + reads chan func(data map[string]interface{}) +} + +// List returns a list of *child nodes* given a path, which is specified as a slice +// where for i > j path[i] is the parent of path[j] +func (p *plugin) List(path metadata.Path) ([]string, error) { + if p.reads == nil && p.data != nil { + return List(path, p.data), nil + } + + children := make(chan []string) + + p.reads <- func(data map[string]interface{}) { + children <- List(path, data) + return + } + + return <-children, nil +} + +// Get retrieves the value at path given. +func (p *plugin) Get(path metadata.Path) (*types.Any, error) { + if p.reads == nil && p.data != nil { + return types.AnyValue(Get(path, p.data)) + } + + value := make(chan *types.Any) + err := make(chan error) + + p.reads <- func(data map[string]interface{}) { + v, e := types.AnyValue(Get(path, data)) + value <- v + err <- e + return + } + + return <-value, <-err +} diff --git a/vendor/github.com/docker/infrakit/pkg/plugin/metadata/reflect.go b/vendor/github.com/docker/infrakit/pkg/plugin/metadata/reflect.go new file mode 100644 index 000000000..b6c9cd374 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/plugin/metadata/reflect.go @@ -0,0 +1,230 @@ +package metadata + +import ( + "fmt" + "reflect" + "regexp" + "sort" + "strconv" + "strings" + + "github.com/docker/infrakit/pkg/types" +) + +var ( + indexRoot = "\\[(([+|-]*[0-9]+)|((.*)=(.*)))\\]$" + arrayIndexExp = regexp.MustCompile("(.*)" + indexRoot) + indexExp = regexp.MustCompile("^" + indexRoot) +) + +// Put sets the attribute of an object at path to the given value +func Put(path []string, value interface{}, object map[string]interface{}) bool { + return put(path, value, object) +} + +// Get returns the attribute of the object at path +func Get(path []string, object interface{}) interface{} { + return get(path, object) +} + +// GetValue returns the attribute of the object at path, as serialized blob +func GetValue(path []string, object interface{}) (*types.Any, error) { + if any, is := object.(*types.Any); is { + return any, nil + } + return types.AnyValue(Get(path, object)) +} + +// List lists the members at the path +func List(path []string, object interface{}) []string { + list := []string{} + v := get(path, object) + if v == nil { + return list + } + + val := reflect.Indirect(reflect.ValueOf(v)) + + if any, is := v.(*types.Any); is { + var temp interface{} + if err := any.Decode(&temp); err == nil { + val = reflect.ValueOf(temp) + } + } + + switch val.Kind() { + case reflect.Slice: + // this is a slice, so return the name as '[%d]' + for i := 0; i < val.Len(); i++ { + list = append(list, fmt.Sprintf("[%d]", i)) + } + + case reflect.Map: + for _, k := range val.MapKeys() { + list = append(list, k.String()) + } + + case reflect.Struct: + vt := val.Type() + for i := 0; i < vt.NumField(); i++ { + if vt.Field(i).PkgPath == "" { + list = append(list, vt.Field(i).Name) + } + } + } + + sort.Strings(list) + return list +} + +func put(p []string, value interface{}, store map[string]interface{}) bool { + if len(p) == 0 { + return false + } + + key := p[0] + if key == "" { + return put(p[1:], value, store) + } + // check if key is an array index of the form <1>[<2>] + matches := arrayIndexExp.FindStringSubmatch(key) + if len(matches) > 2 && matches[1] != "" { + key = matches[1] + p = append([]string{key, fmt.Sprintf("[%s]", matches[2])}, p[1:]...) + return put(p, value, store) + } + + s := reflect.Indirect(reflect.ValueOf(store)) + switch s.Kind() { + case reflect.Slice: + return false // not supported + + case reflect.Map: + if reflect.TypeOf(p[0]).AssignableTo(s.Type().Key()) { + m := s.MapIndex(reflect.ValueOf(p[0])) + if !m.IsValid() { + m = reflect.ValueOf(map[string]interface{}{}) + s.SetMapIndex(reflect.ValueOf(p[0]), m) + } + if len(p) > 1 { + return put(p[1:], value, m.Interface().(map[string]interface{})) + } + s.SetMapIndex(reflect.ValueOf(p[0]), reflect.ValueOf(value)) + return true + } + } + return false +} + +func get(path []string, object interface{}) (value interface{}) { + if f, is := object.(func() interface{}); is { + object = f() + } + + if len(path) == 0 { + return object + } + + if any, is := object.(*types.Any); is { + var temp interface{} + if err := any.Decode(&temp); err == nil { + return get(path, temp) + } + return nil + } + + key := path[0] + + switch key { + case ".": + return object + case "": + return get(path[1:], object) + } + + // check if key is an array index of the form <1>[<2>] + matches := arrayIndexExp.FindStringSubmatch(key) + if len(matches) > 2 && matches[1] != "" { + key = matches[1] + path = append([]string{key, fmt.Sprintf("[%s]", matches[2])}, path[1:]...) + return get(path, object) + } + + v := reflect.Indirect(reflect.ValueOf(object)) + switch v.Kind() { + case reflect.Slice: + i := 0 + matches = indexExp.FindStringSubmatch(key) + if len(matches) > 0 { + if matches[2] != "" { + // numeric index + if index, err := strconv.Atoi(matches[1]); err == nil { + switch { + case index >= 0 && v.Len() > index: + i = index + case index < 0 && v.Len() > -index: // negative index like python + i = v.Len() + index + } + } + return get(path[1:], v.Index(i).Interface()) + + } else if matches[3] != "" { + // equality search index for 'field=check' + lhs := matches[4] // supports another select expression for extracting deeply from the struct + rhs := matches[5] + // loop through the array looking for field that matches the check value + for j := 0; j < v.Len(); j++ { + if el := get(tokenize(lhs), v.Index(j).Interface()); el != nil { + if fmt.Sprintf("%v", el) == rhs { + return get(path[1:], v.Index(j).Interface()) + } + } + } + } + } + case reflect.Map: + value := v.MapIndex(reflect.ValueOf(key)) + if value.IsValid() { + return get(path[1:], value.Interface()) + } + case reflect.Struct: + fv := v.FieldByName(key) + if !fv.IsValid() { + return nil + } + if !fv.CanInterface() { + return nil + } + return get(path[1:], fv.Interface()) + } + return nil +} + +// With quoting to support azure rm type names: e.g. Microsoft.Network/virtualNetworks +// This will split a sting like /Resources/'Microsoft.Network/virtualNetworks'/managerSubnet/Name" into +// [ , Resources, Microsoft.Network/virtualNetworks, managerSubnet, Name] +func tokenize(s string) []string { + if len(s) == 0 { + return []string{} + } + + a := []string{} + start := 0 + quoted := false + for i := 0; i < len(s); i++ { + switch s[i] { + case '/': + if !quoted { + a = append(a, strings.Replace(s[start:i], "'", "", -1)) + start = i + 1 + } + case '\'': + quoted = !quoted + } + } + if start < len(s)-1 { + a = append(a, strings.Replace(s[start:], "'", "", -1)) + } + + return a +} diff --git a/vendor/github.com/docker/infrakit/pkg/plugin/name.go b/vendor/github.com/docker/infrakit/pkg/plugin/name.go new file mode 100644 index 000000000..ced56c24a --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/plugin/name.go @@ -0,0 +1,45 @@ +package plugin + +import ( + "fmt" + "strings" +) + +// Name is a reference to the plugin. Places where it appears include JSON files as type of field `Plugin`. +type Name string + +// GetLookupAndType returns the plugin name for lookup and sub-type supported by the plugin. +// The name follows a microformat of $plugin[/$subtype] where $plugin is used for the discovery / lookup by name. +// The $subtype is used for the Type parameter in the RPC requests. +// Example: instance-file/json means lookup socket file 'instance-file' and the type is 'json'. +func (r Name) GetLookupAndType() (string, string) { + name := string(r) + if first := strings.Index(name, "/"); first >= 0 { + return name[0:first], name[first+1:] + } + return name, "" +} + +// String returns the string representation +func (r Name) String() string { + return string(r) +} + +// MarshalJSON implements the JSON marshaler interface +func (r Name) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, r.String())), nil +} + +// UnmarshalJSON implements the JSON unmarshaler interface +func (r *Name) UnmarshalJSON(data []byte) error { + str := string(data) + start := strings.Index(str, "\"") + last := strings.LastIndex(str, "\"") + if start == 0 && last == len(str)-1 { + str = str[start+1 : last] + } else { + return fmt.Errorf("bad-format-for-name:%v", string(data)) + } + *r = Name(str) + return nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/plugin/plugin.go b/vendor/github.com/docker/infrakit/pkg/plugin/plugin.go new file mode 100644 index 000000000..1dec82ba1 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/plugin/plugin.go @@ -0,0 +1,97 @@ +package plugin + +import ( + "github.com/docker/infrakit/pkg/spi" + "github.com/docker/infrakit/pkg/template" + "github.com/docker/infrakit/pkg/types" +) + +// Spec models a canonical pattern of fields that exist in a struct/ map / union that indicates the block is a plugin. +type Spec struct { + + // Plugin is the name of the plugin + Plugin Name + + // Properties is the configuration of the plugin + Properties *types.Any +} + +// Informer is the interface that gives information about the plugin such as version and interface methods +type Informer interface { + + // GetInfo returns metadata about the plugin + GetInfo() (Info, error) + + // GetFunctions returns metadata about the plugin's template functions, if the plugin supports templating. + GetFunctions() (map[string][]template.Function, error) +} + +// Info is metadata for the plugin +type Info struct { + + // Vendor captures vendor-specific information about this plugin + Vendor *spi.VendorInfo + + // Implements is a list of plugin interface and versions this plugin supports + Implements []spi.InterfaceSpec + + // Interfaces (optional) is a slice of interface descriptions by the type and version + Interfaces []InterfaceDescription `json:",omitempty"` +} + +// InterfaceDescription is a holder for RPC interface version and method descriptions +type InterfaceDescription struct { + spi.InterfaceSpec + Methods []MethodDescription +} + +// MethodDescription contains information about the RPC method such as the request and response +// example structs. The request value can be used as an example input, possibly with example +// plugin-custom properties if the underlying plugin implements the InputExample interface. +// The response value gives an example of the example response. +type MethodDescription struct { + // Request is the RPC request example + Request Request + + // Response is the RPC response example + Response Response +} + +// Request models the RPC request payload +type Request struct { + + // Version is the version of the JSON RPC protocol + Version string `json:"jsonrpc"` + + // Method is the rpc method to use in the payload field 'method' + Method string `json:"method"` + + // Params contains example inputs. This can be a zero value struct or one with defaults + Params interface{} `json:"params"` + + // ID is the request is + ID string `json:"id"` +} + +// Response is the RPC response struct +type Response struct { + + // Result is the result of the call + Result interface{} `json:"result"` + + // ID is id matching the request ID + ID string `json:"id"` +} + +// Endpoint is the address of the plugin service +type Endpoint struct { + + // Name is the key used to refer to this plugin in all JSON configs + Name string + + // Protocol is the transport protocol -- unix, tcp, etc. + Protocol string + + // Address is the how to connect - socket file, host:port, etc. + Address string +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/client/client.go b/vendor/github.com/docker/infrakit/pkg/rpc/client/client.go new file mode 100644 index 000000000..f194ee8bb --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/client/client.go @@ -0,0 +1,76 @@ +package client + +import ( + "bytes" + log "github.com/Sirupsen/logrus" + "github.com/docker/infrakit/pkg/spi" + "github.com/gorilla/rpc/v2/json2" + "net" + "net/http" + "net/http/httputil" + "sync" +) + +type client struct { + http http.Client + addr string +} + +// New creates a new Client that communicates with a unix socket and validates the remote API. +func New(socketPath string, api spi.InterfaceSpec) (Client, error) { + dialUnix := func(proto, addr string) (conn net.Conn, err error) { + return net.Dial("unix", socketPath) + } + + unvalidatedClient := &client{addr: socketPath, http: http.Client{Transport: &http.Transport{Dial: dialUnix}}} + cl := &handshakingClient{client: unvalidatedClient, iface: api, lock: &sync.Mutex{}} + + // check handshake + if err := cl.handshake(); err != nil { + // Note - we still return the client with the possibility of doing a handshake later on + // if we provide an api for the plugin to recheck later. This way, individual components + // can stay running and recalibrate themselves after the user has corrected the problems. + return cl, err + } + return cl, nil +} + +func (c client) Addr() string { + return c.addr +} + +func (c client) Call(method string, arg interface{}, result interface{}) error { + message, err := json2.EncodeClientRequest(method, arg) + if err != nil { + return err + } + + req, err := http.NewRequest("POST", "http://a/", bytes.NewReader(message)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + requestData, err := httputil.DumpRequest(req, true) + if err == nil { + log.Debugf("Sending request %s", string(requestData)) + } else { + log.Error(err) + } + + resp, err := c.http.Do(req) + if err != nil { + return err + } + + defer resp.Body.Close() + + responseData, err := httputil.DumpResponse(resp, true) + if err == nil { + log.Debugf("Received response %s", string(responseData)) + } else { + log.Error(err) + } + + return json2.DecodeClientResponse(resp.Body, result) +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/client/handshake.go b/vendor/github.com/docker/infrakit/pkg/rpc/client/handshake.go new file mode 100644 index 000000000..ef8da67e6 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/client/handshake.go @@ -0,0 +1,88 @@ +package client + +import ( + "fmt" + + "github.com/docker/infrakit/pkg/rpc" + "github.com/docker/infrakit/pkg/spi" + "sync" +) + +type handshakingClient struct { + client Client + iface spi.InterfaceSpec + + // handshakeResult handles the tri-state outcome of handshake state: + // - handshake has not yet completed (nil) + // - handshake completed successfully (non-nil result, nil error) + // - handshake failed (non-nil result, non-nil error) + handshakeResult *handshakeResult + + // lock guards handshakeResult + lock *sync.Mutex +} + +type handshakeResult struct { + err error +} + +type errVersionMismatch string + +// Error implements error interface +func (e errVersionMismatch) Error() string { + return string(e) +} + +// IsErrVersionMismatch return true if the error is from mismatched api versions. +func IsErrVersionMismatch(e error) bool { + _, is := e.(errVersionMismatch) + return is +} + +func (c *handshakingClient) handshake() error { + c.lock.Lock() + defer c.lock.Unlock() + + if c.handshakeResult == nil { + req := rpc.ImplementsRequest{} + resp := rpc.ImplementsResponse{} + + if err := c.client.Call("Handshake.Implements", req, &resp); err != nil { + return err + } + + err := fmt.Errorf("Plugin does not support interface %v", c.iface) + if resp.APIs != nil { + for _, iface := range resp.APIs { + if iface.Name == c.iface.Name { + if iface.Version == c.iface.Version { + err = nil + break + } else { + err = errVersionMismatch(fmt.Sprintf( + "Plugin supports %s interface version %s, client requires %s", + iface.Name, + iface.Version, + c.iface.Version)) + } + } + } + } + + c.handshakeResult = &handshakeResult{err: err} + } + + return c.handshakeResult.err +} + +func (c *handshakingClient) Addr() string { + return c.client.Addr() +} + +func (c *handshakingClient) Call(method string, arg interface{}, result interface{}) error { + if err := c.handshake(); err != nil { + return err + } + + return c.client.Call(method, arg, result) +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/client/info.go b/vendor/github.com/docker/infrakit/pkg/rpc/client/info.go new file mode 100644 index 000000000..24a3ebadb --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/client/info.go @@ -0,0 +1,48 @@ +package client + +import ( + "encoding/json" + "net" + "net/http" + + "github.com/docker/infrakit/pkg/plugin" + "github.com/docker/infrakit/pkg/rpc" + "github.com/docker/infrakit/pkg/template" +) + +// NewPluginInfoClient returns a plugin informer that can give metadata about a plugin +func NewPluginInfoClient(socketPath string) *InfoClient { + dialUnix := func(proto, addr string) (conn net.Conn, err error) { + return net.Dial("unix", socketPath) + } + return &InfoClient{client: &http.Client{Transport: &http.Transport{Dial: dialUnix}}} +} + +// InfoClient is the client for retrieving plugin info +type InfoClient struct { + client *http.Client +} + +// GetInfo implements the Info interface and returns the metadata about the plugin +func (i *InfoClient) GetInfo() (plugin.Info, error) { + meta := plugin.Info{} + resp, err := i.client.Get("http://d" + rpc.URLAPI) + if err != nil { + return meta, err + } + defer resp.Body.Close() + err = json.NewDecoder(resp.Body).Decode(&meta) + return meta, err +} + +// GetFunctions returns metadata about the plugin's template functions, if the plugin supports templating. +func (i *InfoClient) GetFunctions() (map[string][]template.Function, error) { + meta := map[string][]template.Function{} + resp, err := i.client.Get("http://d" + rpc.URLFunctions) + if err != nil { + return meta, err + } + defer resp.Body.Close() + err = json.NewDecoder(resp.Body).Decode(&meta) + return meta, err +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/client/rpc.go b/vendor/github.com/docker/infrakit/pkg/rpc/client/rpc.go new file mode 100644 index 000000000..5aa839647 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/client/rpc.go @@ -0,0 +1,11 @@ +package client + +// Client allows execution of RPCs. +type Client interface { + + // Addr returns the address -- e.g. unix socket path + Addr() string + + // Call invokes an RPC method with an argument and a pointer to a result that will hold the return value. + Call(method string, arg interface{}, result interface{}) error +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/handshake.go b/vendor/github.com/docker/infrakit/pkg/rpc/handshake.go new file mode 100644 index 000000000..28891e247 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/handshake.go @@ -0,0 +1,25 @@ +package rpc + +import ( + "net/http" + + "github.com/docker/infrakit/pkg/spi" +) + +// ImplementsRequest is the rpc wrapper for the Implements method args. +type ImplementsRequest struct { +} + +// ImplementsResponse is the rpc wrapper for the Implements return value. +type ImplementsResponse struct { + APIs []spi.InterfaceSpec +} + +// Handshake is a simple RPC object for doing handshake +type Handshake []spi.InterfaceSpec + +// Implements responds to a request for the supported plugin interfaces. +func (h Handshake) Implements(_ *http.Request, req *ImplementsRequest, resp *ImplementsResponse) error { + resp.APIs = []spi.InterfaceSpec(h) + return nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/info.go b/vendor/github.com/docker/infrakit/pkg/rpc/info.go new file mode 100644 index 000000000..eb9c21231 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/info.go @@ -0,0 +1,21 @@ +package rpc + +const ( + // URLAPI is the well-known HTTP GET endpoint that retrieves description of the plugin's interfaces. + URLAPI = "/info/api.json" + + // URLFunctions exposes the templates functions that are available via this plugin + URLFunctions = "/info/functions.json" + + // URLEventsPrefix is the prefix of the events endpoint + URLEventsPrefix = "/events" +) + +// InputExample is the interface implemented by the rpc implementations for +// group, instance, and flavor to set example input using custom/ vendored data types. +type InputExample interface { + + // SetExampleProperties updates the parameter with example properties. + // The request param must be a pointer + SetExampleProperties(request interface{}) +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/instance/client.go b/vendor/github.com/docker/infrakit/pkg/rpc/instance/client.go new file mode 100644 index 000000000..e6ea49052 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/instance/client.go @@ -0,0 +1,75 @@ +package instance + +import ( + "github.com/docker/infrakit/pkg/plugin" + rpc_client "github.com/docker/infrakit/pkg/rpc/client" + "github.com/docker/infrakit/pkg/spi/instance" + "github.com/docker/infrakit/pkg/types" +) + +// NewClient returns a plugin interface implementation connected to a plugin +func NewClient(name plugin.Name, socketPath string) (instance.Plugin, error) { + rpcClient, err := rpc_client.New(socketPath, instance.InterfaceSpec) + if err != nil { + return nil, err + } + return &client{name: name, client: rpcClient}, nil +} + +type client struct { + name plugin.Name + client rpc_client.Client +} + +// Validate performs local validation on a provision request. +func (c client) Validate(properties *types.Any) error { + _, instanceType := c.name.GetLookupAndType() + req := ValidateRequest{Properties: properties, Type: instanceType} + resp := ValidateResponse{} + + return c.client.Call("Instance.Validate", req, &resp) +} + +// Provision creates a new instance based on the spec. +func (c client) Provision(spec instance.Spec) (*instance.ID, error) { + _, instanceType := c.name.GetLookupAndType() + req := ProvisionRequest{Spec: spec, Type: instanceType} + resp := ProvisionResponse{} + + if err := c.client.Call("Instance.Provision", req, &resp); err != nil { + return nil, err + } + + return resp.ID, nil +} + +// Label labels the instance +func (c client) Label(instance instance.ID, labels map[string]string) error { + _, instanceType := c.name.GetLookupAndType() + req := LabelRequest{Type: instanceType, Instance: instance, Labels: labels} + resp := LabelResponse{} + + return c.client.Call("Instance.Label", req, &resp) +} + +// Destroy terminates an existing instance. +func (c client) Destroy(instance instance.ID) error { + _, instanceType := c.name.GetLookupAndType() + req := DestroyRequest{Instance: instance, Type: instanceType} + resp := DestroyResponse{} + + return c.client.Call("Instance.Destroy", req, &resp) +} + +// DescribeInstances returns descriptions of all instances matching all of the provided tags. +func (c client) DescribeInstances(tags map[string]string) ([]instance.Description, error) { + _, instanceType := c.name.GetLookupAndType() + req := DescribeInstancesRequest{Tags: tags, Type: instanceType} + resp := DescribeInstancesResponse{} + + err := c.client.Call("Instance.DescribeInstances", req, &resp) + if err != nil { + return nil, err + } + return resp.Descriptions, nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/instance/service.go b/vendor/github.com/docker/infrakit/pkg/rpc/instance/service.go new file mode 100644 index 000000000..c93e11dc1 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/instance/service.go @@ -0,0 +1,154 @@ +package instance + +import ( + "fmt" + "net/http" + + "github.com/docker/infrakit/pkg/spi" + "github.com/docker/infrakit/pkg/spi/instance" +) + +// PluginServer returns a RPCService that conforms to the net/rpc rpc call convention. +func PluginServer(p instance.Plugin) *Instance { + return &Instance{plugin: p, typedPlugins: map[string]instance.Plugin{}} +} + +// PluginServerWithTypes which supports multiple types of instance plugins. The de-multiplexing +// is done by the server's RPC method implementations. +func PluginServerWithTypes(typed map[string]instance.Plugin) *Instance { + return &Instance{typedPlugins: typed} +} + +// Instance is the JSON RPC service representing the Instance Plugin. It must be exported in order to be +// registered by the rpc server package. +type Instance struct { + plugin instance.Plugin // the default plugin + typedPlugins map[string]instance.Plugin // by type, as qualified in the name of the plugin +} + +// VendorInfo returns a metadata object about the plugin, if the plugin implements it. +func (p *Instance) VendorInfo() *spi.VendorInfo { + // TODO(chungers) - support typed plugins + if p.plugin == nil { + return nil + } + + if m, is := p.plugin.(spi.Vendor); is { + return m.VendorInfo() + } + return nil +} + +// SetExampleProperties sets the rpc request with any example properties/ custom type +func (p *Instance) SetExampleProperties(request interface{}) { + // TODO(chungers) - support typed plugins + if p.plugin == nil { + return + } + + i, is := p.plugin.(spi.InputExample) + if !is { + return + } + example := i.ExampleProperties() + if example == nil { + return + } + + switch request := request.(type) { + case *ValidateRequest: + request.Properties = example + case *ProvisionRequest: + request.Spec.Properties = example + } +} + +// ImplementedInterface returns the interface implemented by this RPC service. +func (p *Instance) ImplementedInterface() spi.InterfaceSpec { + return instance.InterfaceSpec +} + +func (p *Instance) getPlugin(instanceType string) instance.Plugin { + if instanceType == "" { + return p.plugin + } + if p, has := p.typedPlugins[instanceType]; has { + return p + } + return nil +} + +// Validate performs local validation on a provision request. +func (p *Instance) Validate(_ *http.Request, req *ValidateRequest, resp *ValidateResponse) error { + c := p.getPlugin(req.Type) + if c == nil { + return fmt.Errorf("no-plugin:%s", req.Type) + } + resp.Type = req.Type + err := c.Validate(req.Properties) + if err != nil { + return err + } + resp.OK = true + return nil +} + +// Provision creates a new instance based on the spec. +func (p *Instance) Provision(_ *http.Request, req *ProvisionRequest, resp *ProvisionResponse) error { + resp.Type = req.Type + c := p.getPlugin(req.Type) + if c == nil { + return fmt.Errorf("no-plugin:%s", req.Type) + } + id, err := c.Provision(req.Spec) + if err != nil { + return err + } + resp.ID = id + return nil +} + +// Label labels the instance +func (p *Instance) Label(_ *http.Request, req *LabelRequest, resp *LabelResponse) error { + resp.Type = req.Type + c := p.getPlugin(req.Type) + if c == nil { + return fmt.Errorf("no-plugin:%s", req.Type) + } + err := c.Label(req.Instance, req.Labels) + if err != nil { + return err + } + resp.OK = true + return nil +} + +// Destroy terminates an existing instance. +func (p *Instance) Destroy(_ *http.Request, req *DestroyRequest, resp *DestroyResponse) error { + resp.Type = req.Type + c := p.getPlugin(req.Type) + if c == nil { + return fmt.Errorf("no-plugin:%s", req.Type) + } + err := c.Destroy(req.Instance) + if err != nil { + return err + } + resp.OK = true + return nil +} + +// DescribeInstances returns descriptions of all instances matching all of the provided tags. +func (p *Instance) DescribeInstances(_ *http.Request, req *DescribeInstancesRequest, resp *DescribeInstancesResponse) error { + resp.Type = req.Type + c := p.getPlugin(req.Type) + if c == nil { + return fmt.Errorf("no-plugin:%s", req.Type) + } + desc, err := c.DescribeInstances(req.Tags) + if err != nil { + return err + } + resp.Descriptions = desc + return nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/instance/types.go b/vendor/github.com/docker/infrakit/pkg/rpc/instance/types.go new file mode 100644 index 000000000..b91f677b1 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/instance/types.go @@ -0,0 +1,67 @@ +package instance + +import ( + "github.com/docker/infrakit/pkg/spi/instance" + "github.com/docker/infrakit/pkg/types" +) + +// ValidateRequest is the rpc wrapper for the Validate method args +type ValidateRequest struct { + Type string + Properties *types.Any +} + +// ValidateResponse is the rpc wrapper for the Validate response values +type ValidateResponse struct { + Type string + OK bool +} + +// ProvisionRequest is the rpc wrapper for Provision request +type ProvisionRequest struct { + Type string + Spec instance.Spec +} + +// ProvisionResponse is the rpc wrapper for Provision response +type ProvisionResponse struct { + Type string + ID *instance.ID +} + +// LabelRequest is the rpc wrapper for Label request +type LabelRequest struct { + Type string + Instance instance.ID + Labels map[string]string +} + +// LabelResponse is the rpc wrapper for Label response +type LabelResponse struct { + Type string + OK bool +} + +// DestroyRequest is the rpc wrapper for Destroy request +type DestroyRequest struct { + Type string + Instance instance.ID +} + +// DestroyResponse is the rpc wrapper for Destroy response +type DestroyResponse struct { + Type string + OK bool +} + +// DescribeInstancesRequest is the rpc wrapper for DescribeInstances request +type DescribeInstancesRequest struct { + Type string + Tags map[string]string +} + +// DescribeInstancesResponse is the rpc wrapper for the DescribeInstances response +type DescribeInstancesResponse struct { + Type string + Descriptions []instance.Description +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/metadata/client.go b/vendor/github.com/docker/infrakit/pkg/rpc/metadata/client.go new file mode 100644 index 000000000..4b77d0fd9 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/metadata/client.go @@ -0,0 +1,44 @@ +package metadata + +import ( + rpc_client "github.com/docker/infrakit/pkg/rpc/client" + "github.com/docker/infrakit/pkg/spi/metadata" + "github.com/docker/infrakit/pkg/types" +) + +// NewClient returns a plugin interface implementation connected to a remote plugin +func NewClient(socketPath string) (metadata.Plugin, error) { + rpcClient, err := rpc_client.New(socketPath, metadata.InterfaceSpec) + if err != nil { + return nil, err + } + return &client{client: rpcClient}, nil +} + +// Adapt converts a rpc client to a Metadata plugin object +func Adapt(rpcClient rpc_client.Client) metadata.Plugin { + return &client{client: rpcClient} +} + +type client struct { + client rpc_client.Client +} + +// List returns a list of nodes under path. +func (c client) List(path metadata.Path) ([]string, error) { + req := ListRequest{Path: path} + resp := ListResponse{} + err := c.client.Call("Metadata.List", req, &resp) + return resp.Nodes, err +} + +// Get retrieves the metadata at path. +func (c client) Get(path metadata.Path) (*types.Any, error) { + req := GetRequest{Path: path} + resp := GetResponse{} + err := c.client.Call("Metadata.Get", req, &resp) + if err != nil { + return nil, err + } + return resp.Value, err +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/metadata/service.go b/vendor/github.com/docker/infrakit/pkg/rpc/metadata/service.go new file mode 100644 index 000000000..ef503512b --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/metadata/service.go @@ -0,0 +1,180 @@ +package metadata + +import ( + "net/http" + "sort" + + "github.com/docker/infrakit/pkg/spi" + "github.com/docker/infrakit/pkg/spi/metadata" + "github.com/docker/infrakit/pkg/template" +) + +// PluginServer returns a Metadata that conforms to the net/rpc rpc call convention. +func PluginServer(p metadata.Plugin) *Metadata { + return &Metadata{plugin: p} +} + +// PluginServerWithTypes which supports multiple types of metadata plugins. The de-multiplexing +// is done by the server's RPC method implementations. +func PluginServerWithTypes(typed map[string]metadata.Plugin) *Metadata { + return &Metadata{typedPlugins: typed} +} + +// Metadata the exported type needed to conform to json-rpc call convention +type Metadata struct { + plugin metadata.Plugin + typedPlugins map[string]metadata.Plugin // by type, as qualified in the name of the plugin +} + +// WithBase sets the base plugin to the given plugin object +func (p *Metadata) WithBase(m metadata.Plugin) *Metadata { + p.plugin = m + return p +} + +// WithTypes sets the typed plugins to the given map of plugins (by type name) +func (p *Metadata) WithTypes(typed map[string]metadata.Plugin) *Metadata { + p.typedPlugins = typed + return p +} + +// VendorInfo returns a metadata object about the plugin, if the plugin implements it. See spi.Vendor +func (p *Metadata) VendorInfo() *spi.VendorInfo { + // TODO(chungers) - support typed plugins + if p.plugin == nil { + return nil + } + + if m, is := p.plugin.(spi.Vendor); is { + return m.VendorInfo() + } + return nil +} + +// Funcs implements the template.FunctionExporter method to expose help for plugin's template functions +func (p *Metadata) Funcs() []template.Function { + f, is := p.plugin.(template.FunctionExporter) + if !is { + return []template.Function{} + } + return f.Funcs() +} + +// Types implements server.TypedFunctionExporter +func (p *Metadata) Types() []string { + if p.typedPlugins == nil { + return nil + } + list := []string{} + for k := range p.typedPlugins { + list = append(list, k) + } + return list +} + +// FuncsByType implements server.TypedFunctionExporter +func (p *Metadata) FuncsByType(t string) []template.Function { + if p.typedPlugins == nil { + return nil + } + fp, has := p.typedPlugins[t] + if !has { + return nil + } + exp, is := fp.(template.FunctionExporter) + if !is { + return nil + } + return exp.Funcs() +} + +// ImplementedInterface returns the interface implemented by this RPC service. +func (p *Metadata) ImplementedInterface() spi.InterfaceSpec { + return metadata.InterfaceSpec +} + +func (p *Metadata) getPlugin(metadataType string) metadata.Plugin { + if metadataType == "" { + return p.plugin + } + if p, has := p.typedPlugins[metadataType]; has { + return p + } + return nil +} + +// List returns a list of child nodes given a path. +func (p *Metadata) List(_ *http.Request, req *ListRequest, resp *ListResponse) error { + nodes := []string{} + + // the . case - list the typed plugins and the default's first level. + if len(req.Path) == 0 || req.Path[0] == "" || req.Path[0] == "." { + if p.plugin != nil { + n, err := p.plugin.List(req.Path) + if err != nil { + return err + } + nodes = append(nodes, n...) + } + for k := range p.typedPlugins { + nodes = append(nodes, k) + } + sort.Strings(nodes) + resp.Nodes = nodes + return nil + } + + c, has := p.typedPlugins[req.Path[0]] + if !has { + + if p.plugin == nil { + return nil + } + + nodes, err := p.plugin.List(req.Path) + if err != nil { + return err + } + sort.Strings(nodes) + resp.Nodes = nodes + return nil + } + + nodes, err := c.List(req.Path[1:]) + if err != nil { + return err + } + + sort.Strings(nodes) + resp.Nodes = nodes + return nil +} + +// Get retrieves the value at path given. +func (p *Metadata) Get(_ *http.Request, req *GetRequest, resp *GetResponse) error { + if len(req.Path) == 0 { + return nil + } + + c, has := p.typedPlugins[req.Path[0]] + if !has { + + if p.plugin == nil { + return nil + } + + value, err := p.plugin.Get(req.Path) + if err != nil { + return err + } + resp.Value = value + return nil + } + + value, err := c.Get(req.Path[1:]) + if err != nil { + return err + } + resp.Value = value + return nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/metadata/types.go b/vendor/github.com/docker/infrakit/pkg/rpc/metadata/types.go new file mode 100644 index 000000000..18d30d10c --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/metadata/types.go @@ -0,0 +1,26 @@ +package metadata + +import ( + "github.com/docker/infrakit/pkg/spi/metadata" + "github.com/docker/infrakit/pkg/types" +) + +// ListRequest is the rpc wrapper for request parameters to List +type ListRequest struct { + Path metadata.Path +} + +// ListResponse is the rpc wrapper for the results of List +type ListResponse struct { + Nodes []string +} + +// GetRequest is the rpc wrapper of the params to Get +type GetRequest struct { + Path metadata.Path +} + +// GetResponse is the rpc wrapper of the result of Get +type GetResponse struct { + Value *types.Any +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/server/info.go b/vendor/github.com/docker/infrakit/pkg/rpc/server/info.go new file mode 100644 index 000000000..e4695648c --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/server/info.go @@ -0,0 +1,134 @@ +package server + +import ( + "encoding/json" + "net/http" + + "github.com/docker/infrakit/pkg/plugin" + "github.com/docker/infrakit/pkg/spi" + "github.com/docker/infrakit/pkg/template" +) + +// TypedFunctionExporter is an interface implemented by plugins that supports multiple types in a single RPC endpoint. +// Each typed plugin can export some functions and this interface provides metadata about them. +type TypedFunctionExporter interface { + + // Types returns a list of types in this plugin + Types() []string + + // FuncsByType returns the template functions exported by each typed plugin + FuncsByType(string) []template.Function +} + +// PluginInfo is the service object for the RPC metadata service +type PluginInfo struct { + vendor spi.Vendor + reflectors []*reflector + receiver interface{} +} + +// NewPluginInfo returns an instance of the metadata service +func NewPluginInfo(receiver interface{}) (*PluginInfo, error) { + m := &PluginInfo{ + reflectors: []*reflector{}, + receiver: receiver, + } + if v, is := receiver.(spi.Vendor); is { + m.vendor = v + } + return m, m.Register(receiver) +} + +// Register registers an rpc-capable object for introspection and metadata service +func (m *PluginInfo) Register(receiver interface{}) error { + r := &reflector{target: receiver} + m.reflectors = append(m.reflectors, r) + return nil +} + +// ShowAPI responds by returning information about the plugin. +func (m *PluginInfo) ShowAPI(resp http.ResponseWriter, req *http.Request) { + meta := m.getInfo() + buff, err := json.Marshal(meta) + if err != nil { + resp.WriteHeader(http.StatusInternalServerError) + resp.Write([]byte(err.Error())) + return + } + resp.Write(buff) + return +} + +// ShowTemplateFunctions responds by returning information about template functions the plugin expopses. +func (m *PluginInfo) ShowTemplateFunctions(resp http.ResponseWriter, req *http.Request) { + result := map[string][]template.Function{} + exporter, is := m.receiver.(template.FunctionExporter) + if is { + base := template.UpdateDocumentation(exporter.Funcs()) + if len(base) > 0 { + result["base"] = base + } + } + + texporter, is := m.receiver.(TypedFunctionExporter) + if is { + for _, t := range texporter.Types() { + typed := template.UpdateDocumentation(texporter.FuncsByType(t)) + if len(typed) > 0 { + result[t] = typed + } + } + } + + if t, err := template.NewTemplate("str://", template.Options{}); err == nil { + builtin := template.UpdateDocumentation(t.DefaultFuncs()) + if len(builtin) > 0 { + result["builtin"] = builtin + } + } + + buff, err := json.MarshalIndent(result, "", " ") + if err != nil { + resp.WriteHeader(http.StatusInternalServerError) + resp.Write([]byte(err.Error())) + return + } + resp.Write(buff) + return +} + +func (m *PluginInfo) getInfo() *plugin.Info { + meta := &plugin.Info{} + myImplements := []spi.InterfaceSpec{} + myInterfaces := []plugin.InterfaceDescription{} + + for _, r := range m.reflectors { + + iface := r.Interface() + myImplements = append(myImplements, iface) + + descriptions := []plugin.MethodDescription{} + for _, method := range r.pluginMethods() { + + desc := r.toDescription(method) + descriptions = append(descriptions, desc) + + // sets the example properties which are the custom types for the plugin + r.setExampleProperties(desc.Request.Params) + } + + myInterfaces = append(myInterfaces, + plugin.InterfaceDescription{ + InterfaceSpec: iface, + Methods: descriptions, + }) + } + + if m.vendor != nil { + meta.Vendor = m.vendor.VendorInfo() + } + + meta.Implements = myImplements + meta.Interfaces = myInterfaces + return meta +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/server/reflector.go b/vendor/github.com/docker/infrakit/pkg/rpc/server/reflector.go new file mode 100644 index 000000000..9ae6d31c9 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/server/reflector.go @@ -0,0 +1,145 @@ +package server + +import ( + "fmt" + "net/http" + "reflect" + "time" + "unicode" + "unicode/utf8" + + "github.com/docker/infrakit/pkg/plugin" + "github.com/docker/infrakit/pkg/rpc" + "github.com/docker/infrakit/pkg/spi" + "github.com/docker/infrakit/pkg/types" +) + +var ( + // Precompute the reflect.Type of error and http.Request -- from gorilla/rpc + typeOfError = reflect.TypeOf((*error)(nil)).Elem() + typeOfHTTPRequest = reflect.TypeOf((*http.Request)(nil)).Elem() +) + +type reflector struct { + target interface{} +} + +func (r *reflector) VendorInfo() *spi.VendorInfo { + if i, is := r.target.(spi.Vendor); is { + return i.VendorInfo() + } + return nil +} + +func (r *reflector) exampleProperties() *types.Any { + if example, is := r.target.(spi.InputExample); is { + return example.ExampleProperties() + } + return nil +} + +// Type returns the target's type, taking into account of pointer receiver +func (r *reflector) targetType() reflect.Type { + return reflect.Indirect(reflect.ValueOf(r.target)).Type() +} + +// Interface returns the plugin type and version. +func (r *reflector) Interface() spi.InterfaceSpec { + if v, is := r.target.(VersionedInterface); is { + return v.ImplementedInterface() + } + return spi.InterfaceSpec{} +} + +// isExported returns true of a string is an exported (upper case) name. -- from gorilla/rpc +func isExported(name string) bool { + rune, _ := utf8.DecodeRuneInString(name) + return unicode.IsUpper(rune) +} + +// isExportedOrBuiltin returns true if a type is exported or a builtin -- from gorilla/rpc +func isExportedOrBuiltin(t reflect.Type) bool { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + // PkgPath will be non-empty even for an exported type, + // so we need to check the type name as well. + return isExported(t.Name()) || t.PkgPath() == "" +} + +func (r *reflector) getPluginTypeName() string { + return r.targetType().Name() +} + +func (r *reflector) setExampleProperties(param interface{}) { + if example, is := r.target.(rpc.InputExample); is { + example.SetExampleProperties(param) + } +} + +func (r *reflector) toDescription(m reflect.Method) plugin.MethodDescription { + method := fmt.Sprintf("%s.%s", r.getPluginTypeName(), m.Name) + input := reflect.New(m.Type.In(2).Elem()) + ts := fmt.Sprintf("%v", time.Now().Unix()) + d := plugin.MethodDescription{ + + Request: plugin.Request{ + Version: "2.0", + Method: method, + Params: input.Interface(), + ID: ts, + }, + + Response: plugin.Response{ + Result: reflect.Zero(m.Type.In(3).Elem()).Interface(), + ID: ts, + }, + } + return d +} + +// pluginMethods returns a slice of methods that match the criteria for exporting as RPC service +func (r *reflector) pluginMethods() []reflect.Method { + matches := []reflect.Method{} + receiverT := reflect.TypeOf(r.target) + for i := 0; i < receiverT.NumMethod(); i++ { + + method := receiverT.Method(i) + mtype := method.Type + + // Code from gorilla/rpc + // Method must be exported. + if method.PkgPath != "" { + continue + } + // Method needs four ins: receiver, *http.Request, *args, *reply. + if mtype.NumIn() != 4 { + continue + } + // First argument must be a pointer and must be http.Request. + reqType := mtype.In(1) + if reqType.Kind() != reflect.Ptr || reqType.Elem() != typeOfHTTPRequest { + continue + } + // Second argument must be a pointer and must be exported. + args := mtype.In(2) + if args.Kind() != reflect.Ptr || !isExportedOrBuiltin(args) { + continue + } + // Third argument must be a pointer and must be exported. + reply := mtype.In(3) + if reply.Kind() != reflect.Ptr || !isExportedOrBuiltin(reply) { + continue + } + // Method needs one out: error. + if mtype.NumOut() != 1 { + continue + } + if returnType := mtype.Out(0); returnType != typeOfError { + continue + } + + matches = append(matches, method) + } + return matches +} diff --git a/vendor/github.com/docker/infrakit/pkg/rpc/server/server.go b/vendor/github.com/docker/infrakit/pkg/rpc/server/server.go new file mode 100644 index 000000000..7532651e7 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/rpc/server/server.go @@ -0,0 +1,177 @@ +package server + +import ( + "fmt" + "net" + "net/http" + "net/http/httptest" + "net/http/httputil" + "time" + + log "github.com/Sirupsen/logrus" + broker "github.com/docker/infrakit/pkg/broker/server" + rpc_server "github.com/docker/infrakit/pkg/rpc" + "github.com/docker/infrakit/pkg/spi" + "github.com/docker/infrakit/pkg/spi/event" + "github.com/docker/infrakit/pkg/types" + "github.com/gorilla/mux" + "github.com/gorilla/rpc/v2" + "github.com/gorilla/rpc/v2/json2" + "gopkg.in/tylerb/graceful.v1" +) + +// Stoppable support proactive stopping, and blocking until stopped. +type Stoppable interface { + Stop() + AwaitStopped() +} + +type stoppableServer struct { + server *graceful.Server +} + +func (s *stoppableServer) Stop() { + s.server.Stop(10 * time.Second) +} + +func (s *stoppableServer) AwaitStopped() { + <-s.server.StopChan() +} + +type loggingHandler struct { + handler http.Handler +} + +func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + requestData, err := httputil.DumpRequest(req, true) + if err == nil { + log.Debugf("Received request %s", string(requestData)) + } else { + log.Error(err) + } + + recorder := httptest.NewRecorder() + + h.handler.ServeHTTP(recorder, req) + + responseData, err := httputil.DumpResponse(recorder.Result(), true) + if err == nil { + log.Debugf("Sending response %s", string(responseData)) + } else { + log.Error(err) + } + + w.WriteHeader(recorder.Code) + recorder.Body.WriteTo(w) +} + +// A VersionedInterface identifies which Interfaces a plugin supports. +type VersionedInterface interface { + // ImplementedInterface returns the interface being provided. + ImplementedInterface() spi.InterfaceSpec +} + +// StartPluginAtPath starts an HTTP server listening on a unix socket at the specified path. +// Returns a Stoppable that can be used to stop or block on the server. +func StartPluginAtPath(socketPath string, receiver VersionedInterface, more ...VersionedInterface) (Stoppable, error) { + server := rpc.NewServer() + server.RegisterCodec(json2.NewCodec(), "application/json") + + targets := append([]VersionedInterface{receiver}, more...) + + interfaces := []spi.InterfaceSpec{} + for _, t := range targets { + interfaces = append(interfaces, t.ImplementedInterface()) + + if err := server.RegisterService(t, ""); err != nil { + return nil, err + } + } + + // handshake service that can exchange interface versions with client + if err := server.RegisterService(rpc_server.Handshake(interfaces), ""); err != nil { + return nil, err + } + + // events handler + events := broker.NewBroker() + + // wire up the publish event source channel to the plugin implementations + for _, t := range targets { + + pub, is := t.(event.Publisher) + if !is { + continue + } + + // We give one channel per source to provide some isolation. This we won't have the + // whole event bus stop just because one plugin closes the channel. + eventChan := make(chan *event.Event) + pub.PublishOn(eventChan) + go func() { + for { + event, ok := <-eventChan + if !ok { + return + } + events.Publish(event.Topic.String(), event, 1*time.Second) + } + }() + } + + // info handler + info, err := NewPluginInfo(receiver) + if err != nil { + return nil, err + } + + httpLog := log.New() + httpLog.Level = log.GetLevel() + + router := mux.NewRouter() + router.HandleFunc(rpc_server.URLAPI, info.ShowAPI) + router.HandleFunc(rpc_server.URLFunctions, info.ShowTemplateFunctions) + + intercept := broker.Interceptor{ + Pre: func(topic string, headers map[string][]string) error { + for _, target := range targets { + if v, is := target.(event.Validator); is { + if err := v.Validate(types.PathFromString(topic)); err == nil { + return nil + } + } + } + return broker.ErrInvalidTopic(topic) + }, + Do: events.ServeHTTP, + Post: func(topic string) { + log.Infoln("Client left", topic) + }, + } + router.HandleFunc(rpc_server.URLEventsPrefix, intercept.ServeHTTP) + + logger := loggingHandler{handler: server} + router.Handle("/", logger) + + gracefulServer := graceful.Server{ + Timeout: 10 * time.Second, + Server: &http.Server{Addr: fmt.Sprintf("unix://%s", socketPath), Handler: router}, + } + + listener, err := net.Listen("unix", socketPath) + if err != nil { + return nil, err + } + + log.Infof("Listening at: %s", socketPath) + + go func() { + err := gracefulServer.Serve(listener) + if err != nil { + log.Warn(err) + } + events.Stop() + }() + + return &stoppableServer{server: &gracefulServer}, nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/spi/event/spi.go b/vendor/github.com/docker/infrakit/pkg/spi/event/spi.go new file mode 100644 index 000000000..fa823fe28 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/spi/event/spi.go @@ -0,0 +1,42 @@ +package event + +import ( + "github.com/docker/infrakit/pkg/spi" + "github.com/docker/infrakit/pkg/types" +) + +// InterfaceSpec is the current name and version of the Flavor API. +var InterfaceSpec = spi.InterfaceSpec{ + Name: "Event", + Version: "0.1.0", +} + +// Plugin must be implemented for the object to be able to publish events. +type Plugin interface { + + // List returns a list of *child nodes* given a path for a topic. + // A topic of "." is the top level + List(topic types.Path) (child []string, err error) +} + +// Validator is the interface for validating the topic +type Validator interface { + + // Validate validates the topic + Validate(topic types.Path) error +} + +// Publisher is the interface that event sources also implement to be assigned +// a publish function. +type Publisher interface { + + // PublishOn sets the channel to publish + PublishOn(chan<- *Event) +} + +// Subscriber is the interface given to clients interested in events +type Subscriber interface { + + // SubscribeOn returns the channel for the topic + SubscribeOn(topic types.Path) (<-chan *Event, error) +} diff --git a/vendor/github.com/docker/infrakit/pkg/spi/event/types.go b/vendor/github.com/docker/infrakit/pkg/spi/event/types.go new file mode 100644 index 000000000..96ebb927e --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/spi/event/types.go @@ -0,0 +1,105 @@ +package event + +import ( + "time" + + "github.com/docker/infrakit/pkg/types" +) + +// Type is the type of an event. This gives hint about what struct types to map to, etc. +// It also marks one instance of an event as of different nature from another. +type Type string + +const ( + // TypeError is the type to use for sending errors in the transport of the events. + TypeError = Type("error") +) + +// Event holds information about when, what, etc. +type Event struct { + + // Topic is the topic to which this event is published + Topic types.Path + + // Type of the event. This is usually used as a hint to what struct types to use to unmarshal data + Type Type `json:",omitempty"` + + // ID is unique id for the event. + ID string + + // Timestamp is the time.UnixNano() value -- this is the timestamp when event occurred + Timestamp time.Time + + // Received is the timestamp when the message is received. + Received time.Time `json:",omitempty"` + + // Data contains some application specific payload + Data *types.Any `json:",omitempty"` + + // Error contains any errors that occurred during delivery of the mesasge + Error error `json:",omitempty"` +} + +// Init creates an instance with the value initialized to the state of receiver. +func (event Event) Init() *Event { + copy := event + return © +} + +// WithError sets the error +func (event *Event) WithError(err error) *Event { + event.Error = err + return event +} + +// WithTopic sets the topic from input string +func (event *Event) WithTopic(s string) *Event { + event.Topic = types.PathFromString(s) + return event +} + +// WithType sets the type from a string +func (event *Event) WithType(s string) *Event { + event.Type = Type(s) + return event +} + +// Now sets the timestamp of this event to now. +func (event *Event) Now() *Event { + event.Timestamp = time.Now() + return event +} + +// ReceivedNow marks the receipt timestamp with now +func (event *Event) ReceivedNow() *Event { + event.Received = time.Now() + return event +} + +// WithData converts the data into an any and sets this event's data to it. +func (event *Event) WithData(data interface{}) (*Event, error) { + any, err := types.AnyValue(data) + if err != nil { + return nil, err + } + event.Data = any + return event, nil +} + +// WithDataMust does what WithData does but will panic on error +func (event *Event) WithDataMust(data interface{}) *Event { + e, err := event.WithData(data) + if err != nil { + panic(err) + } + return e +} + +// FromAny sets the fields of this Event from the contents of Any +func (event *Event) FromAny(any *types.Any) *Event { + err := any.Decode(event) + if err != nil { + event.Error = err + } + return event +} diff --git a/vendor/github.com/docker/infrakit/pkg/spi/instance/spi.go b/vendor/github.com/docker/infrakit/pkg/spi/instance/spi.go new file mode 100644 index 000000000..befb47292 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/spi/instance/spi.go @@ -0,0 +1,30 @@ +package instance + +import ( + "github.com/docker/infrakit/pkg/spi" + "github.com/docker/infrakit/pkg/types" +) + +// InterfaceSpec is the current name and version of the Instance API. +var InterfaceSpec = spi.InterfaceSpec{ + Name: "Instance", + Version: "0.3.0", +} + +// Plugin is a vendor-agnostic API used to create and manage resources with an infrastructure provider. +type Plugin interface { + // Validate performs local validation on a provision request. + Validate(req *types.Any) error + + // Provision creates a new instance based on the spec. + Provision(spec Spec) (*ID, error) + + // Label labels the instance + Label(instance ID, labels map[string]string) error + + // Destroy terminates an existing instance. + Destroy(instance ID) error + + // DescribeInstances returns descriptions of all instances matching all of the provided tags. + DescribeInstances(labels map[string]string) ([]Description, error) +} diff --git a/vendor/github.com/docker/infrakit/pkg/spi/instance/types.go b/vendor/github.com/docker/infrakit/pkg/spi/instance/types.go new file mode 100644 index 000000000..50feb6b52 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/spi/instance/types.go @@ -0,0 +1,46 @@ +package instance + +import ( + "github.com/docker/infrakit/pkg/types" +) + +// ID is the identifier for an instance. +type ID string + +// Description contains details about an instance. +type Description struct { + ID ID + LogicalID *LogicalID + Tags map[string]string +} + +// LogicalID is the logical identifier to associate with an instance. +type LogicalID string + +// Attachment is an identifier for a resource to attach to an instance. +type Attachment struct { + // ID is the unique identifier for the attachment. + ID string + + // Type is the kind of attachment. This allows multiple attachments of different types, with the supported + // types defined by the plugin. + Type string +} + +// Spec is a specification of an instance to be provisioned +type Spec struct { + // Properties is the opaque instance plugin configuration. + Properties *types.Any + + // Tags are metadata that describes an instance. + Tags map[string]string + + // Init is the boot script to execute when the instance is created. + Init string + + // LogicalID is the logical identifier assigned to this instance, which may be absent. + LogicalID *LogicalID + + // Attachments are instructions for external entities that should be attached to the instance. + Attachments []Attachment +} diff --git a/vendor/github.com/docker/infrakit/pkg/spi/metadata/path.go b/vendor/github.com/docker/infrakit/pkg/spi/metadata/path.go new file mode 100644 index 000000000..51ab524cc --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/spi/metadata/path.go @@ -0,0 +1,102 @@ +package metadata + +var ( + // NullPath means no path + NullPath = Path([]string{}) +) + +// Path is used to identify a particle of metadata. The path can be strings separated by / as in a URL. +type Path []string + +// Clean scrubs the path to remove any empty string or . or .. and collapse the path into a concise form. +// It's similar to path/filepath.Clean in the standard lib. +func (p Path) Clean() Path { + this := []string(p) + copy := []string{} + for _, v := range this { + switch v { + case "", ".": + case "..": + if len(copy) == 0 { + copy = append(copy, "..") + } else { + copy = copy[0 : len(copy)-1] + if len(copy) == 0 { + return NullPath + } + } + default: + copy = append(copy, v) + + } + } + return Path(copy) +} + +// Len returns the length of the path +func (p Path) Len() int { + return len([]string(p)) +} + +// Index returns the ith component in the path +func (p Path) Index(i int) *string { + if p.Len() <= i { + return nil + } + copy := []string(p)[i] + return © +} + +// Shift returns a new path that's shifted i positions to the left -- ith child of the head at index=0 +func (p Path) Shift(i int) Path { + len := p.Len() - i + if len <= 0 { + return Path([]string{}) + } + new := make([]string, len) + copy(new, []string(p)[i:]) + return Path(new) +} + +// Dir returns the 'dir' of the path +func (p Path) Dir() Path { + pp := p.Clean() + if len(pp) > 1 { + return p[0 : len(pp)-1] + } + return Path([]string{"."}) +} + +// Base returns the base of the path +func (p Path) Base() string { + pp := p.Clean() + return pp[len(pp)-1] +} + +// Join joins the input as a child of this path +func (p Path) Join(child string) Path { + return p.Sub(Path([]string{child})) +} + +// Sub joins the child to the parent +func (p Path) Sub(child Path) Path { + pp := p.Clean() + return Path(append(pp, []string(child)...)) +} + +// Rel returns a new path that is a child of the input from this path. +// e.g. For a path a/b/c/d Rel(a/b/) returns c/d. NullPath is returned if +// the two are not relative to one another. +func (p Path) Rel(path Path) Path { + this := []string(p.Clean()) + parent := []string(path.Clean()) + if len(this) < len(parent) { + return NullPath + } + for i := 0; i < len(parent); i++ { + if parent[i] != this[i] { + return NullPath + } + } + return Path(this[len(parent):]) +} diff --git a/vendor/github.com/docker/infrakit/pkg/spi/metadata/spi.go b/vendor/github.com/docker/infrakit/pkg/spi/metadata/spi.go new file mode 100644 index 000000000..350bedd92 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/spi/metadata/spi.go @@ -0,0 +1,22 @@ +package metadata + +import ( + "github.com/docker/infrakit/pkg/spi" + "github.com/docker/infrakit/pkg/types" +) + +// InterfaceSpec is the current name and version of the Metadata API. +var InterfaceSpec = spi.InterfaceSpec{ + Name: "Metadata", + Version: "0.1.0", +} + +// Plugin is the interface for metadata-related operations. +type Plugin interface { + + // List returns a list of *child nodes* given a path, which is specified as a slice + List(path Path) (child []string, err error) + + // Get retrieves the value at path given. + Get(path Path) (value *types.Any, err error) +} diff --git a/vendor/github.com/docker/infrakit/pkg/spi/plugin.go b/vendor/github.com/docker/infrakit/pkg/spi/plugin.go new file mode 100644 index 000000000..fb7f70350 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/spi/plugin.go @@ -0,0 +1,39 @@ +package spi + +import ( + "github.com/docker/infrakit/pkg/types" +) + +// InterfaceSpec is metadata about an API. +type InterfaceSpec struct { + // Name of the interface. + Name string + + // Version is the identifier for the API version. + Version string +} + +// VendorInfo provides vendor-specific information +type VendorInfo struct { + InterfaceSpec // vendor-defined name / version + + // URL is the informational url for the plugin. It can container help and docs, etc. + URL string +} + +// Vendor is an optional interface that has vendor-specific information methods +type Vendor interface { + // VendorInfo returns a vendor-defined interface spec + VendorInfo() *VendorInfo +} + +// InputExample interface is an optional interface implemented by the plugin that will provide +// example input struct to document the vendor-specific api of the plugin. An example of this +// is to provide a sample JSON for all the Properties field in the plugin API. +type InputExample interface { + + // ExampleProperties returns an example JSON raw message that the vendor plugin understands. + // This is an example of what the user will configure and what will be used as the opaque + // blob in all the plugin methods where raw JSON messages are referenced. + ExampleProperties() *types.Any +} diff --git a/vendor/github.com/docker/infrakit/pkg/template/defaults.go b/vendor/github.com/docker/infrakit/pkg/template/defaults.go new file mode 100644 index 000000000..44e322d24 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/template/defaults.go @@ -0,0 +1,16 @@ +package template + +import ( + "os" +) + +// defaultContextURL returns the default context URL if none is known. +func defaultContextURL() string { + pwd := "/" + if wd, err := os.Getwd(); err == nil { + pwd = wd + } else { + pwd = os.Getenv("PWD") + } + return "file://localhost" + pwd + "/" +} diff --git a/vendor/github.com/docker/infrakit/pkg/template/fetch.go b/vendor/github.com/docker/infrakit/pkg/template/fetch.go new file mode 100644 index 000000000..391b9c13c --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/template/fetch.go @@ -0,0 +1,64 @@ +package template + +import ( + "fmt" + "io/ioutil" + "net" + "net/http" + "net/url" + "os" + "path/filepath" +) + +// Fetch fetchs content from the given URL string. Supported schemes are http:// https:// file:// unix:// +func Fetch(s string, opt Options) ([]byte, error) { + u, err := url.Parse(s) + if err != nil { + return nil, err + } + switch u.Scheme { + case "file": + return ioutil.ReadFile(u.Path) + + case "http", "https": + resp, err := http.Get(u.String()) + if err != nil { + return nil, err + } + defer resp.Body.Close() + return ioutil.ReadAll(resp.Body) + + case "unix": + // unix: will look for a socket that matches the host name at a + // directory path set by environment variable. + c, err := socketClient(u, opt.SocketDir) + if err != nil { + return nil, err + } + u.Scheme = "http" + resp, err := c.Get(u.String()) + if err != nil { + return nil, err + } + defer resp.Body.Close() + return ioutil.ReadAll(resp.Body) + } + + return nil, fmt.Errorf("unsupported url:%s", s) +} + +func socketClient(u *url.URL, socketDir string) (*http.Client, error) { + socketPath := filepath.Join(socketDir, u.Host) + if f, err := os.Stat(socketPath); err != nil { + return nil, err + } else if f.Mode()&os.ModeSocket == 0 { + return nil, fmt.Errorf("not-a-socket:%v", socketPath) + } + return &http.Client{ + Transport: &http.Transport{ + Dial: func(proto, addr string) (conn net.Conn, err error) { + return net.Dial("unix", socketPath) + }, + }, + }, nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/template/funcs.go b/vendor/github.com/docker/infrakit/pkg/template/funcs.go new file mode 100644 index 000000000..dbf96c964 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/template/funcs.go @@ -0,0 +1,361 @@ +package template + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + "strings" + "time" + + "github.com/docker/infrakit/pkg/types" + "github.com/jmespath/go-jmespath" +) + +// DeepCopyObject makes a deep copy of the argument, using encoding/gob encode/decode. +func DeepCopyObject(from interface{}) (interface{}, error) { + var mod bytes.Buffer + enc := json.NewEncoder(&mod) + dec := json.NewDecoder(&mod) + err := enc.Encode(from) + if err != nil { + return nil, err + } + + copy := reflect.New(reflect.TypeOf(from)) + err = dec.Decode(copy.Interface()) + if err != nil { + return nil, err + } + return reflect.Indirect(copy).Interface(), nil +} + +// QueryObject applies a JMESPath query specified by the expression, against the target object. +func QueryObject(exp string, target interface{}) (interface{}, error) { + query, err := jmespath.Compile(exp) + if err != nil { + return nil, err + } + return query.Search(target) +} + +// SplitLines splits the input into a string slice. +func SplitLines(o interface{}) ([]string, error) { + ret := []string{} + switch o := o.(type) { + case string: + return strings.Split(o, "\n"), nil + case []byte: + return strings.Split(string(o), "\n"), nil + } + return ret, fmt.Errorf("not-supported-value-type") +} + +// FromJSON decode the input JSON encoded as string or byte slice into a map. +func FromJSON(o interface{}) (interface{}, error) { + var ret interface{} + switch o := o.(type) { + case string: + err := json.Unmarshal([]byte(o), &ret) + return ret, err + case []byte: + err := json.Unmarshal(o, &ret) + return ret, err + case *types.Any: + err := json.Unmarshal(o.Bytes(), &ret) + return ret, err + } + return ret, fmt.Errorf("not-supported-value-type") +} + +// ToJSON encodes the input struct into a JSON string. +func ToJSON(o interface{}) (string, error) { + buff, err := json.MarshalIndent(o, "", " ") + return string(buff), err +} + +// ToJSONFormat encodes the input struct into a JSON string with format prefix, and indent. +func ToJSONFormat(prefix, indent string, o interface{}) (string, error) { + buff, err := json.MarshalIndent(o, prefix, indent) + return string(buff), err +} + +// FromMap decodes map into raw struct +func FromMap(m map[string]interface{}, raw interface{}) error { + // The safest way, but the slowest, is to just marshal and unmarshal back + buff, err := ToJSON(m) + if err != nil { + return err + } + return json.Unmarshal([]byte(buff), raw) +} + +// ToMap encodes the input as a map +func ToMap(raw interface{}) (map[string]interface{}, error) { + buff, err := ToJSON(raw) + if err != nil { + return nil, err + } + out, err := FromJSON(buff) + return out.(map[string]interface{}), err +} + +// UnixTime returns a timestamp in unix time +func UnixTime() interface{} { + return time.Now().Unix() +} + +// IndexOf returns the index of search in array. -1 if not found or array is not iterable. An optional true will +// turn on strict type check while by default string representations are used to compare values. +func IndexOf(srch interface{}, array interface{}, strictOptional ...bool) int { + strict := false + if len(strictOptional) > 0 { + strict = strictOptional[0] + } + switch reflect.TypeOf(array).Kind() { + case reflect.Slice: + s := reflect.ValueOf(array) + for i := 0; i < s.Len(); i++ { + if reflect.DeepEqual(srch, s.Index(i).Interface()) { + return i + } + if !strict { + // by string value which is useful for text based compares + search := reflect.Indirect(reflect.ValueOf(srch)).Interface() + value := reflect.Indirect(s.Index(i)).Interface() + searchStr := fmt.Sprintf("%v", search) + check := fmt.Sprintf("%v", value) + if searchStr == check { + return i + } + } + } + } + return -1 +} + +// DefaultFuncs returns a list of default functions for binding in the template +func (t *Template) DefaultFuncs() []Function { + return []Function{ + { + Name: "source", + Description: []string{ + "Source / evaluate the template at the input location (as URL).", + "This will make all of the global variables declared there visible in this template's context.", + "Similar to 'source' in bash, sourcing another template means applying it in the same context ", + "as the calling template. The context (e.g. variables) of the calling template as a result can be mutated.", + }, + Func: func(p string, opt ...interface{}) (string, error) { + var o interface{} + if len(opt) > 0 { + o = opt[0] + } + loc := p + if strings.Index(loc, "str://") == -1 { + buff, err := getURL(t.url, p) + if err != nil { + return "", err + } + loc = buff + } + sourced, err := NewTemplate(loc, t.options) + if err != nil { + return "", err + } + // set this as the parent of the sourced template so its global can mutate the globals in this + sourced.parent = t + sourced.forkFrom(t) + sourced.context = t.context + + if o == nil { + o = sourced.context + } + // TODO(chungers) -- let the sourced template define new functions that can be called in the parent. + return sourced.Render(o) + }, + }, + { + Name: "include", + Description: []string{ + "Render content found at URL as template and include here.", + "The optional second parameter is the context to use when rendering the template.", + "Conceptually similar to exec in bash, where the template included is applied using a fork ", + "of current context in the calling template. Any mutations to the context via 'global' will not ", + "be visible in the calling template's context.", + }, + Func: func(p string, opt ...interface{}) (string, error) { + var o interface{} + if len(opt) > 0 { + o = opt[0] + } + loc := p + if strings.Index(loc, "str://") == -1 { + buff, err := getURL(t.url, p) + if err != nil { + return "", err + } + loc = buff + } + included, err := NewTemplate(loc, t.options) + if err != nil { + return "", err + } + dotCopy, err := included.forkFrom(t) + if err != nil { + return "", err + } + included.context = dotCopy + + if o == nil { + o = included.context + } + + return included.Render(o) + }, + }, + { + Name: "loop", + Description: []string{ + "Loop generates a slice of length specified by the input. For use like {{ range loop 5 }}...{{ end }}", + }, + Func: func(c int) []struct{} { + return make([]struct{}, c) + }, + }, + { + Name: "global", + Description: []string{ + "Sets a global variable named after the first argument, with the value as the second argument.", + "This is similar to def (which sets the default value).", + "Global variables are propagated to all templates that are rendered via the 'include' function.", + }, + Func: func(n string, v interface{}) Void { + t.Global(n, v) + return voidValue + }, + }, + { + Name: "def", + Description: []string{ + "Defines a variable with the first argument as name and last argument value as the default.", + "It's also ok to pass a third optional parameter, in the middle, as the documentation string.", + }, + Func: func(name string, args ...interface{}) (Void, error) { + if _, has := t.defaults[name]; has { + // not sure if this is good, but should complain loudly + return voidValue, fmt.Errorf("already defined: %v", name) + } + var doc string + var value interface{} + switch len(args) { + case 1: + // just value, no docs + value = args[0] + case 2: + // docs and value + doc = fmt.Sprintf("%v", args[0]) + value = args[1] + } + t.Def(name, value, doc) + return voidValue, nil + }, + }, + { + Name: "ref", + Description: []string{ + "References / gets the variable named after the first argument.", + "The values must be set first by either def or global.", + }, + Func: t.Ref, + }, + { + Name: "q", + Description: []string{ + "Runs a JMESPath (http://jmespath.org/) query (first arg) on the object (second arg).", + "The return value is an object which needs to be rendered properly for the format of the document.", + "Example: {{ include \"https://httpbin.org/get\" | from_json | q \"origin\" }} returns the origin of http request.", + }, + Func: QueryObject, + }, + { + Name: "to_json", + Description: []string{ + "Encodes the input as a JSON string", + "This is useful for taking an object (interface{}) and render it inline as proper JSON.", + "Example: {{ include \"https://httpbin.org/get\" | from_json | to_json }}", + }, + Func: ToJSON, + }, + { + Name: "jsonEncode", + Description: []string{ + "Encodes the input as a JSON string", + "This is useful for taking an object (interface{}) and render it inline as proper JSON.", + "Example: {{ include \"https://httpbin.org/get\" | from_json | to_json }}", + }, + Func: ToJSON, + }, + { + Name: "to_json_format", + Description: []string{ + "Encodes the input as a JSON string with first arg as prefix, second arg the indentation, then the object", + }, + Func: ToJSONFormat, + }, + { + Name: "jsonEncodeIndent", + Description: []string{ + "Encodes the input as a JSON string with first arg as prefix, second arg the indentation, then the object", + }, + Func: ToJSONFormat, + }, + { + Name: "from_json", + Description: []string{ + "Decodes the input (first arg) into a structure (a map[string]interface{} or []interface{}).", + "This is useful for parsing arbitrary resources in JSON format as object. The object is the queryable via 'q'", + "For example: {{ include \"https://httpbin.org/get\" | from_json | q \"origin\" }} returns the origin of request.", + }, + Func: FromJSON, + }, + { + Name: "jsonDecode", + Description: []string{ + "Decodes the input (first arg) into a structure (a map[string]interface{} or []interface{}).", + "This is useful for parsing arbitrary resources in JSON format as object. The object is the queryable via 'q'", + "For example: {{ include \"https://httpbin.org/get\" | from_json | q \"origin\" }} returns the origin of request.", + }, + Func: FromJSON, + }, + { + Name: "unixtime", + Description: []string{ + "Returns the unix timestamp as the number of seconds elapsed since January 1, 1970 UTC.", + }, + Func: UnixTime, + }, + { + Name: "lines", + Description: []string{ + "Splits the input string (first arg) into a slice by '\n'", + }, + Func: SplitLines, + }, + { + Name: "index_of", + Description: []string{ + "Returns the index of first argument in the second argument which is a slice.", + "Example: {{ index_of \"foo\" (from_json \"[\"bar\",\"foo\",\"baz\"]\") }} returns 1 (int).", + }, + Func: IndexOf, + }, + { + Name: "indexOf", + Description: []string{ + "Returns the index of first argument in the second argument which is a slice.", + "Example: {{ index_of \"foo\" (from_json \"[\"bar\",\"foo\",\"baz\"]\") }} returns 1 (int).", + }, + Func: IndexOf, + }, + } +} diff --git a/vendor/github.com/docker/infrakit/pkg/template/help.go b/vendor/github.com/docker/infrakit/pkg/template/help.go new file mode 100644 index 000000000..d6994663d --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/template/help.go @@ -0,0 +1,83 @@ +package template + +import ( + "fmt" + "reflect" + "strings" +) + +// UpdateDocumentation uses reflection to generate documentation on usage and function signature. +func UpdateDocumentation(in []Function) []Function { + out := []Function{} + for _, f := range in { + copy := f + copy.Function = functionSignature(f.Name, f.Func) + copy.Usage = functionUsage(f.Name, f.Func) + if len(f.Description) == 0 { + copy.Description = []string{"None"} + } + out = append(out, copy) + } + return out +} + +func isFunc(f interface{}) (string, bool) { + if f == nil { + return "no-function", false + } + + ft := reflect.TypeOf(f) + if ft.Kind() != reflect.Func { + return "not-a-function", false + } + return ft.String(), true +} + +func functionSignature(name string, f interface{}) string { + s, is := isFunc(f) + if !is { + return s + } + return s +} + +func functionUsage(name string, f interface{}) string { + if s, is := isFunc(f); !is { + return s + } + + ft := reflect.TypeOf(f) + if ft.Kind() != reflect.Func { + return "not-a-function" + } + + args := make([]string, ft.NumIn()) + for i := 0; i < len(args); i++ { + t := ft.In(i) + + v := "" + switch { + case t == reflect.TypeOf(""): + v = fmt.Sprintf("\"%s\"", t.Name()) + + case t.Kind() == reflect.Slice && i == len(args)-1: + tt := t.Elem().Name() + if t.Elem() == reflect.TypeOf("") { + tt = fmt.Sprintf("\"%s\"", t.Name()) + } + v = fmt.Sprintf("[ %s ... ]", tt) + case t.String() == "interface {}": + v = "any" + default: + v = strings.Replace(t.String(), " ", "", -1) + } + + args[i] = v + } + + arglist := strings.Join(args, " ") + if len(arglist) > 0 { + arglist = arglist + " " + } + return fmt.Sprintf("{{ %s %s}}", name, arglist) +} diff --git a/vendor/github.com/docker/infrakit/pkg/template/template.go b/vendor/github.com/docker/infrakit/pkg/template/template.go new file mode 100644 index 000000000..8a2b9b6f0 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/template/template.go @@ -0,0 +1,385 @@ +package template + +import ( + "bytes" + "fmt" + "io" + "reflect" + "strings" + "sync" + "text/template" + + "github.com/Masterminds/sprig" + log "github.com/Sirupsen/logrus" +) + +// Function contains the description of an exported template function +type Function struct { + + // Name is the function name to bind in the template + Name string + + // Description provides help for the function + Description []string `json:",omitempty"` + + // Func is the reference to the actual function + Func interface{} `json:"-"` + + // Function is the signature of the function + Function string + + // Usage shows how to use it + Usage string `json:",omitempty"` +} + +// FunctionExporter is implemented by any plugins wishing to show help on the function it exports. +type FunctionExporter interface { + // Funcs returns a list of special template functions of the form func(template.Context, arg1, arg2) interface{} + Funcs() []Function +} + +// Context is a marker interface for a user-defined struct that is passed into the template engine (as context) +// and accessible in the exported template functions. Template functions can have the signature +// func(template.Context, arg1, arg2 ...) (string, error) and when functions like this are registered, the template +// engine will dynamically create and export a function of the form func(arg1, arg2...) (string, error) where +// the context instance becomes an out-of-band struct that can be mutated by functions. This in essence allows +// structured data as output of the template, in addition to a string from evaluating the template. +type Context interface { + // Funcs returns a list of special template functions of the form func(template.Context, arg1, arg2) interface{} + Funcs() []Function +} + +// Options contains parameters for customizing the behavior of the engine +type Options struct { + + // SocketDir is the directory for locating the socket file for + // a template URL of the form unix://socket_file/path/to/resource + SocketDir string +} + +type defaultValue struct { + Name string + Value interface{} + Doc string +} + +// Template is the templating engine +type Template struct { + options Options + + url string + body []byte + parsed *template.Template + functions []func() []Function + funcs map[string]interface{} + globals map[string]interface{} + defaults map[string]defaultValue + context interface{} + + registered []Function + lock sync.Mutex + + parent *Template +} + +// Void is used in the template functions return value type to indicate a void. +// Golang template does not allow functions with no return types to be bound. +type Void string + +const voidValue Void = "" + +// NewTemplate fetches the content at the url and returns a template. If the string begins +// with str:// as scheme, then the rest of the string is interpreted as the body of the template. +func NewTemplate(s string, opt Options) (*Template, error) { + var buff []byte + contextURL := s + // Special case of specifying the entire template as a string; otherwise treat as url + if strings.Index(s, "str://") == 0 { + buff = []byte(strings.Replace(s, "str://", "", 1)) + contextURL = defaultContextURL() + } else { + b, err := Fetch(s, opt) + if err != nil { + return nil, err + } + buff = b + } + return NewTemplateFromBytes(buff, contextURL, opt) +} + +// NewTemplateFromBytes builds the template from buffer with a contextURL which is used to deduce absolute +// path of any 'included' templates e.g. {{ include "./another.tpl" . }} +func NewTemplateFromBytes(buff []byte, contextURL string, opt Options) (*Template, error) { + if contextURL == "" { + log.Warningln("Context is not known. Included templates may not work properly.") + } + + return &Template{ + options: opt, + url: contextURL, + body: buff, + funcs: map[string]interface{}{}, + globals: map[string]interface{}{}, + defaults: map[string]defaultValue{}, + functions: []func() []Function{}, + }, nil +} + +// SetOptions sets the runtime flags for the engine +func (t *Template) SetOptions(opt Options) *Template { + t.lock.Lock() + defer t.lock.Unlock() + t.options = opt + return t +} + +// WithFunctions allows client code to extend the template by adding its own functions. +func (t *Template) WithFunctions(functions func() []Function) *Template { + t.lock.Lock() + defer t.lock.Unlock() + t.functions = append(t.functions, functions) + return t +} + +// AddFunc adds a new function to support in template +func (t *Template) AddFunc(name string, f interface{}) *Template { + t.lock.Lock() + defer t.lock.Unlock() + t.funcs[name] = f + return t +} + +// Ref returns the value keyed by name in the context of this template. See 'ref' template function. +func (t *Template) Ref(name string) interface{} { + if found, has := t.globals[name]; has { + return found + } else if v, has := t.defaults[name]; has { + return v.Value + } + return nil +} + +// Dot returns the '.' in this template. +func (t *Template) Dot() interface{} { + return t.context +} + +func (t *Template) forkFrom(parent *Template) (dotCopy interface{}, err error) { + t.lock.Lock() + defer t.lock.Unlock() + + // copy the globals in the parent scope into the child + for k, v := range parent.globals { + t.globals[k] = v + } + // copy the defaults in the parent scope into the child + for k, v := range parent.defaults { + t.defaults[k] = v + } + // inherit the functions defined for this template + for k, v := range parent.funcs { + t.AddFunc(k, v) + } + // inherit other functions + for _, ff := range parent.functions { + t.functions = append(t.functions, ff) + } + if parent.context != nil { + return DeepCopyObject(parent.context) + } + return nil, nil +} + +// Global sets the a key, value in the context of this template. It is visible to all the 'included' +// and 'sourced' templates by the calling template. +func (t *Template) Global(name string, value interface{}) *Template { + for here := t; here != nil; here = here.parent { + here.updateGlobal(name, value) + } + return t +} + +func (t *Template) updateGlobal(name string, value interface{}) { + t.lock.Lock() + defer t.lock.Unlock() + t.globals[name] = value +} + +// Def is equivalent to a {{ def "key" value "description" }} in defining a variable with a default value. +// The value is accessible via a {{ ref "key" }} in the template. +func (t *Template) Def(name string, value interface{}, doc string) *Template { + for here := t; here != nil; here = here.parent { + here.updateDef(name, value, doc) + } + return t +} + +func (t *Template) updateDef(name string, val interface{}, doc ...string) *Template { + t.lock.Lock() + defer t.lock.Unlock() + t.defaults[name] = defaultValue{ + Name: name, + Value: val, + Doc: strings.Join(doc, " "), + } + return t +} + +// Validate parses the template and checks for validity. +func (t *Template) Validate() (*Template, error) { + t.lock.Lock() + t.parsed = nil + t.lock.Unlock() + return t, t.build(nil) +} + +// Funcs returns a list of registered functions used by the template when it rendered the view. +func (t *Template) Funcs() []Function { + return t.registered +} + +func (t *Template) build(context Context) error { + t.lock.Lock() + defer t.lock.Unlock() + + if t.parsed != nil { + return nil + } + + registered := []Function{} + fm := map[string]interface{}{} + + for k, v := range sprig.TxtFuncMap() { + fm[k] = v + } + + for k, v := range t.funcs { + if tf, err := makeTemplateFunc(context, v); err == nil { + fm[k] = tf + } else { + return err + } + } + + // the default functions cannot be overriden + for _, f := range t.DefaultFuncs() { + tf, err := makeTemplateFunc(context, f.Func) + if err != nil { + return err + } + fm[f.Name] = tf + registered = append(registered, f) + } + + // If there are any function sources that was set via WithFunctions() + for _, exp := range t.functions { + for _, f := range exp() { + tf, err := makeTemplateFunc(context, f.Func) + if err != nil { + return err + } + fm[f.Name] = tf + registered = append(registered, f) + } + } + + // If the context implements the FunctionExporter interface, it can add more functions + // and potentially override existing. + if context != nil { + for _, f := range context.Funcs() { + if tf, err := makeTemplateFunc(context, f.Func); err == nil { + fm[f.Name] = tf + registered = append(registered, f) + } else { + return err + } + } + } + + t.registered = registered + + parsed, err := template.New(t.url).Funcs(fm).Parse(string(t.body)) + if err != nil { + return err + } + + t.parsed = parsed + return nil +} + +// Execute is a drop-in replace of the execute method of template +func (t *Template) Execute(output io.Writer, context interface{}) error { + if err := t.build(toContext(context)); err != nil { + return err + } + t.context = context + return t.parsed.Execute(output, context) +} + +// returns as Context if input implements the interface; otherwise nil +func toContext(in interface{}) Context { + var context Context + if in != nil { + if s, is := in.(Context); is { + context = s + } + } + return context +} + +// Render renders the template given the context +func (t *Template) Render(context interface{}) (string, error) { + if err := t.build(toContext(context)); err != nil { + return "", err + } + var buff bytes.Buffer + err := t.Execute(&buff, context) + return buff.String(), err +} + +// converts a function of f(Context, ags...) to a regular template function +func makeTemplateFunc(ctx Context, f interface{}) (interface{}, error) { + + contextType := reflect.TypeOf((*Context)(nil)).Elem() + + ff := reflect.Indirect(reflect.ValueOf(f)) + // first we check to see if f has the special signature where the first + // parameter is the context parameter... + if ff.Kind() != reflect.Func { + return nil, fmt.Errorf("not a function:%v", f) + } + + if ff.Type().NumIn() > 0 && ff.Type().In(0).AssignableTo(contextType) { + + in := make([]reflect.Type, ff.Type().NumIn()-1) // exclude the context param + out := make([]reflect.Type, ff.Type().NumOut()) + + for i := 1; i < ff.Type().NumIn(); i++ { + in[i-1] = ff.Type().In(i) + } + variadic := false + if len(in) > 0 { + variadic = in[len(in)-1].Kind() == reflect.Slice + } + for i := 0; i < ff.Type().NumOut(); i++ { + out[i] = ff.Type().Out(i) + } + funcType := reflect.FuncOf(in, out, variadic) + funcImpl := func(in []reflect.Value) []reflect.Value { + if !variadic { + return ff.Call(append([]reflect.Value{reflect.ValueOf(ctx)}, in...)) + } + + variadicParam := in[len(in)-1] + last := make([]reflect.Value, variadicParam.Len()) + for i := 0; i < variadicParam.Len(); i++ { + last[i] = variadicParam.Index(i) + } + return ff.Call(append(append([]reflect.Value{reflect.ValueOf(ctx)}, in[0:len(in)-1]...), last...)) + } + + newFunc := reflect.MakeFunc(funcType, funcImpl) + return newFunc.Interface(), nil + } + return ff.Interface(), nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/template/util.go b/vendor/github.com/docker/infrakit/pkg/template/util.go new file mode 100644 index 000000000..d11f3d812 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/template/util.go @@ -0,0 +1,28 @@ +package template + +import ( + "net/url" + "path/filepath" + "strings" +) + +// returns a url string of the base and a relative path. +// e.g. http://host/foo/bar/baz, ./boo.tpl gives http://host/foo/bar/boo.tpl +func getURL(root, rel string) (string, error) { + + // handle the case when rel is actually a full url + if strings.Index(rel, "://") > 0 { + u, err := url.Parse(rel) + if err != nil { + return "", err + } + return u.String(), nil + } + + u, err := url.Parse(root) + if err != nil { + return "", err + } + u.Path = filepath.Clean(filepath.Join(filepath.Dir(u.Path), rel)) + return u.String(), nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/types/any.go b/vendor/github.com/docker/infrakit/pkg/types/any.go new file mode 100644 index 000000000..a21f2938a --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/types/any.go @@ -0,0 +1,92 @@ +package types + +import ( + "encoding/json" +) + +// Any is the raw configuration for the plugin +type Any json.RawMessage + +// AnyString returns an Any from a string that represents the marshaled/encoded data +func AnyString(s string) *Any { + return AnyBytes([]byte(s)) +} + +// AnyBytes returns an Any from the encoded message bytes +func AnyBytes(data []byte) *Any { + any := &Any{} + *any = data + return any +} + +// AnyCopy makes a copy of the data in the given ptr. +func AnyCopy(any *Any) *Any { + if any == nil { + return &Any{} + } + return AnyBytes(any.Bytes()) +} + +// AnyValue returns an Any from a value by marshaling / encoding the input +func AnyValue(v interface{}) (*Any, error) { + if v == nil { + return nil, nil // So that any omitempty will see an empty/zero value + } + any := &Any{} + err := any.marshal(v) + return any, err +} + +// AnyValueMust returns an Any from a value by marshaling / encoding the input. It panics if there's error. +func AnyValueMust(v interface{}) *Any { + any, err := AnyValue(v) + if err != nil { + panic(err) + } + return any +} + +// Decode decodes the any into the input typed struct +func (c *Any) Decode(typed interface{}) error { + if c == nil || len([]byte(*c)) == 0 { + return nil // no effect on typed + } + return json.Unmarshal([]byte(*c), typed) +} + +// marshal populates this raw message with a decoded form of the input struct. +func (c *Any) marshal(typed interface{}) error { + buff, err := json.MarshalIndent(typed, "", "") + if err != nil { + return err + } + *c = Any(json.RawMessage(buff)) + return nil +} + +// Bytes returns the encoded bytes +func (c *Any) Bytes() []byte { + if c == nil { + return nil + } + return []byte(*c) +} + +// String returns the string representation. +func (c *Any) String() string { + return string([]byte(*c)) +} + +// MarshalJSON implements the json Marshaler interface +func (c *Any) MarshalJSON() ([]byte, error) { + if c == nil { + return nil, nil + } + return []byte(*c), nil +} + +// UnmarshalJSON implements the json Unmarshaler interface +func (c *Any) UnmarshalJSON(data []byte) error { + *c = Any(json.RawMessage(data)) + return nil +} diff --git a/vendor/github.com/docker/infrakit/pkg/types/link.go b/vendor/github.com/docker/infrakit/pkg/types/link.go new file mode 100644 index 000000000..0e172cd3a --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/types/link.go @@ -0,0 +1,124 @@ +package types + +import ( + "fmt" + "math/rand" + "time" +) + +const ( + letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" +) + +func init() { + rand.Seed(int64(time.Now().Nanosecond())) +} + +// Link is a struct that represents an association between an infrakit managed resource +// and an entity in some other system. The mechanism of linkage is via labels or tags +// on both sides. +type Link struct { + value string + context string +} + +// NewLink creates a link +func NewLink() *Link { + return &Link{ + value: randomAlphaNumericString(16), + } +} + +// NewLinkFromMap constructs a link from data in the map +func NewLinkFromMap(m map[string]string) *Link { + l := &Link{} + if v, has := m["infrakit-link"]; has { + l.value = v + } + + if v, has := m["infrakit-link-context"]; has { + l.context = v + } + return l +} + +// Valid returns true if the link value is set +func (l Link) Valid() bool { + return l.value != "" +} + +// Value returns the value of the link +func (l Link) Value() string { + return l.value +} + +// Label returns the label to look for the link +func (l Link) Label() string { + return "infrakit-link" +} + +// Context returns the context of the link +func (l Link) Context() string { + return l.context +} + +// WithContext sets a context for this link +func (l *Link) WithContext(s string) *Link { + l.context = s + return l +} + +// KVPairs returns the link representation as a slice of Key=Value pairs +func (l *Link) KVPairs() []string { + out := []string{} + for k, v := range l.Map() { + out = append(out, fmt.Sprintf("%s=%s", k, v)) + } + return out +} + +// Map returns a representation that is easily converted to JSON or YAML +func (l *Link) Map() map[string]string { + return map[string]string{ + "infrakit-link": l.value, + "infrakit-link-context": l.context, + } +} + +// WriteMap writes to the target map. This will overwrite values of same key +func (l *Link) WriteMap(target map[string]string) { + for k, v := range l.Map() { + target[k] = v + } +} + +// InMap returns true if the link is contained in the map +func (l *Link) InMap(m map[string]string) bool { + c, has := m["infrakit-link-context"] + if !has { + return false + } + if c != l.context { + return false + } + + v, has := m["infrakit-link"] + if !has { + return false + } + return v == l.value +} + +// Equal returns true if the links are the same - same value and context +func (l *Link) Equal(other Link) bool { + return l.value == other.value && l.context == other.context +} + +// randomAlphaNumericString generates a non-secure random alpha-numeric string of a given length. +func randomAlphaNumericString(length int) string { + b := make([]byte, length) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} diff --git a/vendor/github.com/docker/infrakit/pkg/types/path.go b/vendor/github.com/docker/infrakit/pkg/types/path.go new file mode 100644 index 000000000..da3c90b77 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/types/path.go @@ -0,0 +1,200 @@ +package types + +import ( + "sort" + "strings" +) + +var ( + // NullPath means no path + NullPath = Path([]string{}) +) + +// Path is used to identify a particle of metadata. The path can be strings separated by / as in a URL. +type Path []string + +// PathFromString returns the path components of a / separated path +func PathFromString(path string) Path { + return Path(strings.Split(path, "/")).Clean() +} + +// PathFrom return a single path of the given components +func PathFrom(a string, b ...string) Path { + p := Path(append([]string{a}, b...)) + return p.Clean() +} + +// PathFromStrings returns the path from a list of strings +func PathFromStrings(a string, b ...string) []Path { + list := []Path{PathFromString(a)} + for _, p := range b { + list = append(list, PathFromString(p)) + } + return list +} + +// String returns the string representation of path +func (p Path) String() string { + s := strings.Join([]string(p), "/") + if len(s) == 0 { + return "." + } + return s +} + +// Valid returns true if is a valid path +func (p Path) Valid() bool { + return p.Len() > 0 +} + +// Dot returns true if this is a . +func (p Path) Dot() bool { + return len(p) == 1 && p[0] == "." +} + +// Clean scrubs the path to remove any empty string or . or .. and collapse the path into a concise form. +// It's similar to path.Clean in the standard lib. +func (p Path) Clean() Path { + this := []string(p) + copy := []string{} + for _, v := range this { + switch v { + case "", ".": + case "..": + if len(copy) == 0 { + copy = append(copy, "..") + } else { + copy = copy[0 : len(copy)-1] + if len(copy) == 0 { + return NullPath + } + } + default: + copy = append(copy, v) + } + } + if len(copy) == 0 { + copy = []string{"."} + } else if this[len(this)-1] == "" || this[len(this)-1] == "." { + copy = append(copy, "") + } + + return Path(copy) +} + +// Len returns the length of the path +func (p Path) Len() int { + return len([]string(p)) +} + +// Index returns the ith component in the path +func (p Path) Index(i int) *string { + if p.Len() <= i { + return nil + } + copy := []string(p)[i] + return © +} + +// Shift returns a new path that's shifted i positions to the left -- ith child of the head at index=0 +func (p Path) Shift(i int) Path { + len := p.Len() - i + if len <= 0 { + return Path([]string{}) + } + new := make([]string, len) + copy(new, []string(p)[i:]) + return Path(new) +} + +// Dir returns the 'dir' of the path +func (p Path) Dir() Path { + pp := p.Clean() + if len(pp) > 1 { + return p[0 : len(pp)-1] + } + return Path([]string{"."}) +} + +// Base returns the base of the path +func (p Path) Base() string { + pp := p.Clean() + return pp[len(pp)-1] +} + +// JoinString joins the input as a child of this path +func (p Path) JoinString(child string) Path { + return p.Join(Path([]string{child})) +} + +// Join joins the child to the parent +func (p Path) Join(child Path) Path { + pp := p.Clean() + this := []string(pp) + if this[len(this)-1] == "" { + pp = Path(this[:len(this)-1]) + } + return Path(append(pp, []string(child)...)) +} + +// Rel returns a new path that is a child of the input from this path. +// e.g. For a path a/b/c/d Rel(a/b/) returns c/d. NullPath is returned if +// the two are not relative to one another. +func (p Path) Rel(path Path) Path { + if path.Equal(PathFromString(".")) { + return p + } + + this := []string(p.Clean()) + parent := []string(path.Clean()) + if parent[len(parent)-1] == "" { + parent = parent[:len(parent)-1] + } + if len(this) < len(parent) { + return NullPath + } + for i := 0; i < len(parent); i++ { + if parent[i] != this[i] { + return NullPath + } + } + return Path(this[len(parent):]) +} + +// Equal returns true if the path is lexicographically equal to the other +func (p Path) Equal(other Path) bool { + if len(p) != len(other) { + return false + } + for i := 0; i < len(p); i++ { + if p[i] != other[i] { + return false + } + } + return true +} + +// Less return true if the path is lexicographically less than the other +func (p Path) Less(other Path) bool { + min := len(p) + if len(other) < min { + min = len(other) + } + for i := 0; i < min; i++ { + if string(p[i]) != string(other[i]) { + return string(p[i]) < string(other[i]) + } + } + return len(p) < len(other) +} + +type pathSorter []Path + +func (p pathSorter) Len() int { return len(p) } +func (p pathSorter) Less(i, j int) bool { return Path(p[i]).Less(Path(p[j])) } +func (p pathSorter) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// Sort sorts the paths +func Sort(p []Path) { + sort.Sort(pathSorter(p)) +} diff --git a/vendor/github.com/docker/infrakit/pkg/types/reflect.go b/vendor/github.com/docker/infrakit/pkg/types/reflect.go new file mode 100644 index 000000000..2cb1c3d36 --- /dev/null +++ b/vendor/github.com/docker/infrakit/pkg/types/reflect.go @@ -0,0 +1,233 @@ +package types + +import ( + "fmt" + "reflect" + "regexp" + "sort" + "strconv" + "strings" +) + +var ( + indexRoot = "\\[(([+|-]*[0-9]+)|((.*)=(.*)))\\]$" + arrayIndexExp = regexp.MustCompile("(.*)" + indexRoot) + indexExp = regexp.MustCompile("^" + indexRoot) +) + +// Put sets the attribute of an object at path to the given value +func Put(path []string, value interface{}, object map[string]interface{}) bool { + return put(path, value, object) +} + +// Get returns the attribute of the object at path +func Get(path []string, object interface{}) interface{} { + return get(path, object) +} + +// GetValue returns the attribute of the object at path, as serialized blob +func GetValue(path []string, object interface{}) (*Any, error) { + if any, is := object.(*Any); is { + return any, nil + } + return AnyValue(Get(path, object)) +} + +// List lists the members at the path +// If the value at the path is listable, then a slice of the children (unqualified) will be +// returned. If the value at the path doesn't exist, a nil will be returned. +// A value is listable if it is 1. a slice, 2. a map, 3. a struct (fields will be listed) +// or a 4. a types.Any where the any object will be unpacked and the same rules above will be +// applied to the decoded struct. +func List(path []string, object interface{}) []string { + list := []string{} + v := get(path, object) + if v == nil { + return nil + } + + val := reflect.Indirect(reflect.ValueOf(v)) + + if any, is := v.(*Any); is { + var temp interface{} + if err := any.Decode(&temp); err == nil { + val = reflect.ValueOf(temp) + } + } + + switch val.Kind() { + case reflect.Slice: + // this is a slice, so return the name as '[%d]' + for i := 0; i < val.Len(); i++ { + list = append(list, fmt.Sprintf("[%d]", i)) + } + + case reflect.Map: + for _, k := range val.MapKeys() { + list = append(list, k.String()) + } + + case reflect.Struct: + vt := val.Type() + for i := 0; i < vt.NumField(); i++ { + if vt.Field(i).PkgPath == "" { + list = append(list, vt.Field(i).Name) + } + } + } + + sort.Strings(list) + return list +} + +func put(p []string, value interface{}, store map[string]interface{}) bool { + if len(p) == 0 { + return false + } + + key := p[0] + if key == "" { + return put(p[1:], value, store) + } + // check if key is an array index of the form <1>[<2>] + matches := arrayIndexExp.FindStringSubmatch(key) + if len(matches) > 2 && matches[1] != "" { + key = matches[1] + p = append([]string{key, fmt.Sprintf("[%s]", matches[2])}, p[1:]...) + return put(p, value, store) + } + + s := reflect.Indirect(reflect.ValueOf(store)) + switch s.Kind() { + case reflect.Slice: + return false // not supported + + case reflect.Map: + if reflect.TypeOf(p[0]).AssignableTo(s.Type().Key()) { + m := s.MapIndex(reflect.ValueOf(p[0])) + if !m.IsValid() { + m = reflect.ValueOf(map[string]interface{}{}) + s.SetMapIndex(reflect.ValueOf(p[0]), m) + } + if len(p) > 1 { + return put(p[1:], value, m.Interface().(map[string]interface{})) + } + s.SetMapIndex(reflect.ValueOf(p[0]), reflect.ValueOf(value)) + return true + } + } + return false +} + +func get(path []string, object interface{}) (value interface{}) { + if f, is := object.(func() interface{}); is { + object = f() + } + + if len(path) == 0 { + return object + } + + if any, is := object.(*Any); is { + var temp interface{} + if err := any.Decode(&temp); err == nil { + return get(path, temp) + } + return nil + } + + key := path[0] + + switch key { + case ".": + return object + case "": + return get(path[1:], object) + } + + // check if key is an array index of the form <1>[<2>] + matches := arrayIndexExp.FindStringSubmatch(key) + if len(matches) > 2 && matches[1] != "" { + key = matches[1] + path = append([]string{key, fmt.Sprintf("[%s]", matches[2])}, path[1:]...) + return get(path, object) + } + + v := reflect.Indirect(reflect.ValueOf(object)) + switch v.Kind() { + case reflect.Slice: + i := 0 + matches = indexExp.FindStringSubmatch(key) + if len(matches) > 0 { + if matches[2] != "" { + // numeric index + if index, err := strconv.Atoi(matches[1]); err == nil { + switch { + case index >= 0 && v.Len() > index: + i = index + case index < 0 && v.Len() > -index: // negative index like python + i = v.Len() + index + } + } + return get(path[1:], v.Index(i).Interface()) + + } else if matches[3] != "" { + // equality search index for 'field=check' + lhs := matches[4] // supports another select expression for extracting deeply from the struct + rhs := matches[5] + // loop through the array looking for field that matches the check value + for j := 0; j < v.Len(); j++ { + if el := get(tokenize(lhs), v.Index(j).Interface()); el != nil { + if fmt.Sprintf("%v", el) == rhs { + return get(path[1:], v.Index(j).Interface()) + } + } + } + } + } + case reflect.Map: + value := v.MapIndex(reflect.ValueOf(key)) + if value.IsValid() { + return get(path[1:], value.Interface()) + } + case reflect.Struct: + fv := v.FieldByName(key) + if !fv.IsValid() { + return nil + } + if !fv.CanInterface() { + return nil + } + return get(path[1:], fv.Interface()) + } + return nil +} + +// With quoting to support azure rm type names: e.g. Microsoft.Network/virtualNetworks +// This will split a sting like /Resources/'Microsoft.Network/virtualNetworks'/managerSubnet/Name" into +// [ , Resources, Microsoft.Network/virtualNetworks, managerSubnet, Name] +func tokenize(s string) []string { + if len(s) == 0 { + return []string{} + } + + a := []string{} + start := 0 + quoted := false + for i := 0; i < len(s); i++ { + switch s[i] { + case '/': + if !quoted { + a = append(a, strings.Replace(s[start:i], "'", "", -1)) + start = i + 1 + } + case '\'': + quoted = !quoted + } + } + if start < len(s)-1 { + a = append(a, strings.Replace(s[start:], "'", "", -1)) + } + + return a +} diff --git a/vendor/github.com/gorilla/context/LICENSE b/vendor/github.com/gorilla/context/LICENSE new file mode 100644 index 000000000..0e5fb8728 --- /dev/null +++ b/vendor/github.com/gorilla/context/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/context/README.md b/vendor/github.com/gorilla/context/README.md new file mode 100644 index 000000000..08f86693b --- /dev/null +++ b/vendor/github.com/gorilla/context/README.md @@ -0,0 +1,10 @@ +context +======= +[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context) + +gorilla/context is a general purpose registry for global request variables. + +> Note: gorilla/context, having been born well before `context.Context` existed, does not play well +> with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs. You should either use *just* gorilla/context, or moving forward, the new `http.Request.Context()`. + +Read the full documentation here: http://www.gorillatoolkit.org/pkg/context diff --git a/vendor/github.com/gorilla/context/context.go b/vendor/github.com/gorilla/context/context.go new file mode 100644 index 000000000..81cb128b1 --- /dev/null +++ b/vendor/github.com/gorilla/context/context.go @@ -0,0 +1,143 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package context + +import ( + "net/http" + "sync" + "time" +) + +var ( + mutex sync.RWMutex + data = make(map[*http.Request]map[interface{}]interface{}) + datat = make(map[*http.Request]int64) +) + +// Set stores a value for a given key in a given request. +func Set(r *http.Request, key, val interface{}) { + mutex.Lock() + if data[r] == nil { + data[r] = make(map[interface{}]interface{}) + datat[r] = time.Now().Unix() + } + data[r][key] = val + mutex.Unlock() +} + +// Get returns a value stored for a given key in a given request. +func Get(r *http.Request, key interface{}) interface{} { + mutex.RLock() + if ctx := data[r]; ctx != nil { + value := ctx[key] + mutex.RUnlock() + return value + } + mutex.RUnlock() + return nil +} + +// GetOk returns stored value and presence state like multi-value return of map access. +func GetOk(r *http.Request, key interface{}) (interface{}, bool) { + mutex.RLock() + if _, ok := data[r]; ok { + value, ok := data[r][key] + mutex.RUnlock() + return value, ok + } + mutex.RUnlock() + return nil, false +} + +// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. +func GetAll(r *http.Request) map[interface{}]interface{} { + mutex.RLock() + if context, ok := data[r]; ok { + result := make(map[interface{}]interface{}, len(context)) + for k, v := range context { + result[k] = v + } + mutex.RUnlock() + return result + } + mutex.RUnlock() + return nil +} + +// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if +// the request was registered. +func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { + mutex.RLock() + context, ok := data[r] + result := make(map[interface{}]interface{}, len(context)) + for k, v := range context { + result[k] = v + } + mutex.RUnlock() + return result, ok +} + +// Delete removes a value stored for a given key in a given request. +func Delete(r *http.Request, key interface{}) { + mutex.Lock() + if data[r] != nil { + delete(data[r], key) + } + mutex.Unlock() +} + +// Clear removes all values stored for a given request. +// +// This is usually called by a handler wrapper to clean up request +// variables at the end of a request lifetime. See ClearHandler(). +func Clear(r *http.Request) { + mutex.Lock() + clear(r) + mutex.Unlock() +} + +// clear is Clear without the lock. +func clear(r *http.Request) { + delete(data, r) + delete(datat, r) +} + +// Purge removes request data stored for longer than maxAge, in seconds. +// It returns the amount of requests removed. +// +// If maxAge <= 0, all request data is removed. +// +// This is only used for sanity check: in case context cleaning was not +// properly set some request data can be kept forever, consuming an increasing +// amount of memory. In case this is detected, Purge() must be called +// periodically until the problem is fixed. +func Purge(maxAge int) int { + mutex.Lock() + count := 0 + if maxAge <= 0 { + count = len(data) + data = make(map[*http.Request]map[interface{}]interface{}) + datat = make(map[*http.Request]int64) + } else { + min := time.Now().Unix() - int64(maxAge) + for r := range data { + if datat[r] < min { + clear(r) + count++ + } + } + } + mutex.Unlock() + return count +} + +// ClearHandler wraps an http.Handler and clears request values at the end +// of a request lifetime. +func ClearHandler(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer Clear(r) + h.ServeHTTP(w, r) + }) +} diff --git a/vendor/github.com/gorilla/context/doc.go b/vendor/github.com/gorilla/context/doc.go new file mode 100644 index 000000000..448d1bfca --- /dev/null +++ b/vendor/github.com/gorilla/context/doc.go @@ -0,0 +1,88 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package context stores values shared during a request lifetime. + +Note: gorilla/context, having been born well before `context.Context` existed, +does not play well > with the shallow copying of the request that +[`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) +(added to net/http Go 1.7 onwards) performs. You should either use *just* +gorilla/context, or moving forward, the new `http.Request.Context()`. + +For example, a router can set variables extracted from the URL and later +application handlers can access those values, or it can be used to store +sessions values to be saved at the end of a request. There are several +others common uses. + +The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: + + http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 + +Here's the basic usage: first define the keys that you will need. The key +type is interface{} so a key can be of any type that supports equality. +Here we define a key using a custom int type to avoid name collisions: + + package foo + + import ( + "github.com/gorilla/context" + ) + + type key int + + const MyKey key = 0 + +Then set a variable. Variables are bound to an http.Request object, so you +need a request instance to set a value: + + context.Set(r, MyKey, "bar") + +The application can later access the variable using the same key you provided: + + func MyHandler(w http.ResponseWriter, r *http.Request) { + // val is "bar". + val := context.Get(r, foo.MyKey) + + // returns ("bar", true) + val, ok := context.GetOk(r, foo.MyKey) + // ... + } + +And that's all about the basic usage. We discuss some other ideas below. + +Any type can be stored in the context. To enforce a given type, make the key +private and wrap Get() and Set() to accept and return values of a specific +type: + + type key int + + const mykey key = 0 + + // GetMyKey returns a value for this package from the request values. + func GetMyKey(r *http.Request) SomeType { + if rv := context.Get(r, mykey); rv != nil { + return rv.(SomeType) + } + return nil + } + + // SetMyKey sets a value for this package in the request values. + func SetMyKey(r *http.Request, val SomeType) { + context.Set(r, mykey, val) + } + +Variables must be cleared at the end of a request, to remove all values +that were stored. This can be done in an http.Handler, after a request was +served. Just call Clear() passing the request: + + context.Clear(r) + +...or use ClearHandler(), which conveniently wraps an http.Handler to clear +variables at the end of a request lifetime. + +The Routers from the packages gorilla/mux and gorilla/pat call Clear() +so if you are using either of them you don't need to clear the context manually. +*/ +package context diff --git a/vendor/github.com/gorilla/mux/LICENSE b/vendor/github.com/gorilla/mux/LICENSE new file mode 100644 index 000000000..0e5fb8728 --- /dev/null +++ b/vendor/github.com/gorilla/mux/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md new file mode 100644 index 000000000..cdab8784d --- /dev/null +++ b/vendor/github.com/gorilla/mux/README.md @@ -0,0 +1,340 @@ +gorilla/mux +=== +[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux) +[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux) +[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge) + +![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png) + +http://www.gorillatoolkit.org/pkg/mux + +Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to +their respective handler. + +The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are: + +* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`. +* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers. +* URL hosts and paths can have variables with an optional regular expression. +* Registered URLs can be built, or "reversed", which helps maintaining references to resources. +* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching. + +--- + +* [Install](#install) +* [Examples](#examples) +* [Matching Routes](#matching-routes) +* [Listing Routes](#listing-routes) +* [Static Files](#static-files) +* [Registered URLs](#registered-urls) +* [Full Example](#full-example) + +--- + +## Install + +With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain: + +```sh +go get -u github.com/gorilla/mux +``` + +## Examples + +Let's start registering a couple of URL paths and handlers: + +```go +func main() { + r := mux.NewRouter() + r.HandleFunc("/", HomeHandler) + r.HandleFunc("/products", ProductsHandler) + r.HandleFunc("/articles", ArticlesHandler) + http.Handle("/", r) +} +``` + +Here we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters. + +Paths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example: + +```go +r := mux.NewRouter() +r.HandleFunc("/products/{key}", ProductHandler) +r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler) +r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) +``` + +The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`: + +```go +func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, "Category: %v\n", vars["category"]) +} +``` + +And this is all you need to know about the basic usage. More advanced options are explained below. + +### Matching Routes + +Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables: + +```go +r := mux.NewRouter() +// Only matches if domain is "www.example.com". +r.Host("www.example.com") +// Matches a dynamic subdomain. +r.Host("{subdomain:[a-z]+}.domain.com") +``` + +There are several other matchers that can be added. To match path prefixes: + +```go +r.PathPrefix("/products/") +``` + +...or HTTP methods: + +```go +r.Methods("GET", "POST") +``` + +...or URL schemes: + +```go +r.Schemes("https") +``` + +...or header values: + +```go +r.Headers("X-Requested-With", "XMLHttpRequest") +``` + +...or query values: + +```go +r.Queries("key", "value") +``` + +...or to use a custom matcher function: + +```go +r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { + return r.ProtoMajor == 0 +}) +``` + +...and finally, it is possible to combine several matchers in a single route: + +```go +r.HandleFunc("/products", ProductsHandler). + Host("www.example.com"). + Methods("GET"). + Schemes("http") +``` + +Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting". + +For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it: + +```go +r := mux.NewRouter() +s := r.Host("www.example.com").Subrouter() +``` + +Then register routes in the subrouter: + +```go +s.HandleFunc("/products/", ProductsHandler) +s.HandleFunc("/products/{key}", ProductHandler) +s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) +``` + +The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route. + +Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter. + +There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths: + +```go +r := mux.NewRouter() +s := r.PathPrefix("/products").Subrouter() +// "/products/" +s.HandleFunc("/", ProductsHandler) +// "/products/{key}/" +s.HandleFunc("/{key}/", ProductHandler) +// "/products/{key}/details" +s.HandleFunc("/{key}/details", ProductDetailsHandler) +``` + +### Listing Routes + +Routes on a mux can be listed using the Router.Walk method—useful for generating documentation: + +```go +package main + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" +) + +func handler(w http.ResponseWriter, r *http.Request) { + return +} + +func main() { + r := mux.NewRouter() + r.HandleFunc("/", handler) + r.HandleFunc("/products", handler) + r.HandleFunc("/articles", handler) + r.HandleFunc("/articles/{id}", handler) + r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { + t, err := route.GetPathTemplate() + if err != nil { + return err + } + fmt.Println(t) + return nil + }) + http.Handle("/", r) +} +``` + +### Static Files + +Note that the path provided to `PathPrefix()` represents a "wildcard": calling +`PathPrefix("/static/").Handler(...)` means that the handler will be passed any +request that matches "/static/*". This makes it easy to serve static files with mux: + +```go +func main() { + var dir string + + flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") + flag.Parse() + r := mux.NewRouter() + + // This will serve files under http://localhost:8000/static/ + r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) + + srv := &http.Server{ + Handler: r, + Addr: "127.0.0.1:8000", + // Good practice: enforce timeouts for servers you create! + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + + log.Fatal(srv.ListenAndServe()) +} +``` + +### Registered URLs + +Now let's see how to build registered URLs. + +Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example: + +```go +r := mux.NewRouter() +r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). + Name("article") +``` + +To build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do: + +```go +url, err := r.Get("article").URL("category", "technology", "id", "42") +``` + +...and the result will be a `url.URL` with the following path: + +``` +"/articles/technology/42" +``` + +This also works for host variables: + +```go +r := mux.NewRouter() +r.Host("{subdomain}.domain.com"). + Path("/articles/{category}/{id:[0-9]+}"). + HandlerFunc(ArticleHandler). + Name("article") + +// url.String() will be "http://news.domain.com/articles/technology/42" +url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42") +``` + +All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match. + +Regex support also exists for matching Headers within a route. For example, we could do: + +```go +r.HeadersRegexp("Content-Type", "application/(text|json)") +``` + +...and the route will match both requests with a Content-Type of `application/json` as well as `application/text` + +There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do: + +```go +// "http://news.domain.com/" +host, err := r.Get("article").URLHost("subdomain", "news") + +// "/articles/technology/42" +path, err := r.Get("article").URLPath("category", "technology", "id", "42") +``` + +And if you use subrouters, host and path defined separately can be built as well: + +```go +r := mux.NewRouter() +s := r.Host("{subdomain}.domain.com").Subrouter() +s.Path("/articles/{category}/{id:[0-9]+}"). + HandlerFunc(ArticleHandler). + Name("article") + +// "http://news.domain.com/articles/technology/42" +url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42") +``` + +## Full Example + +Here's a complete, runnable example of a small `mux` based server: + +```go +package main + +import ( + "net/http" + "log" + "github.com/gorilla/mux" +) + +func YourHandler(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("Gorilla!\n")) +} + +func main() { + r := mux.NewRouter() + // Routes consist of a path and a handler function. + r.HandleFunc("/", YourHandler) + + // Bind to a port and pass our router in + log.Fatal(http.ListenAndServe(":8000", r)) +} +``` + +## License + +BSD licensed. See the LICENSE file for details. diff --git a/vendor/github.com/gorilla/mux/context_gorilla.go b/vendor/github.com/gorilla/mux/context_gorilla.go new file mode 100644 index 000000000..d7adaa8fa --- /dev/null +++ b/vendor/github.com/gorilla/mux/context_gorilla.go @@ -0,0 +1,26 @@ +// +build !go1.7 + +package mux + +import ( + "net/http" + + "github.com/gorilla/context" +) + +func contextGet(r *http.Request, key interface{}) interface{} { + return context.Get(r, key) +} + +func contextSet(r *http.Request, key, val interface{}) *http.Request { + if val == nil { + return r + } + + context.Set(r, key, val) + return r +} + +func contextClear(r *http.Request) { + context.Clear(r) +} diff --git a/vendor/github.com/gorilla/mux/context_native.go b/vendor/github.com/gorilla/mux/context_native.go new file mode 100644 index 000000000..209cbea7d --- /dev/null +++ b/vendor/github.com/gorilla/mux/context_native.go @@ -0,0 +1,24 @@ +// +build go1.7 + +package mux + +import ( + "context" + "net/http" +) + +func contextGet(r *http.Request, key interface{}) interface{} { + return r.Context().Value(key) +} + +func contextSet(r *http.Request, key, val interface{}) *http.Request { + if val == nil { + return r + } + + return r.WithContext(context.WithValue(r.Context(), key, val)) +} + +func contextClear(r *http.Request) { + return +} diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go new file mode 100644 index 000000000..00daf4a72 --- /dev/null +++ b/vendor/github.com/gorilla/mux/doc.go @@ -0,0 +1,240 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package mux implements a request router and dispatcher. + +The name mux stands for "HTTP request multiplexer". Like the standard +http.ServeMux, mux.Router matches incoming requests against a list of +registered routes and calls a handler for the route that matches the URL +or other conditions. The main features are: + + * Requests can be matched based on URL host, path, path prefix, schemes, + header and query values, HTTP methods or using custom matchers. + * URL hosts and paths can have variables with an optional regular + expression. + * Registered URLs can be built, or "reversed", which helps maintaining + references to resources. + * Routes can be used as subrouters: nested routes are only tested if the + parent route matches. This is useful to define groups of routes that + share common conditions like a host, a path prefix or other repeated + attributes. As a bonus, this optimizes request matching. + * It implements the http.Handler interface so it is compatible with the + standard http.ServeMux. + +Let's start registering a couple of URL paths and handlers: + + func main() { + r := mux.NewRouter() + r.HandleFunc("/", HomeHandler) + r.HandleFunc("/products", ProductsHandler) + r.HandleFunc("/articles", ArticlesHandler) + http.Handle("/", r) + } + +Here we register three routes mapping URL paths to handlers. This is +equivalent to how http.HandleFunc() works: if an incoming request URL matches +one of the paths, the corresponding handler is called passing +(http.ResponseWriter, *http.Request) as parameters. + +Paths can have variables. They are defined using the format {name} or +{name:pattern}. If a regular expression pattern is not defined, the matched +variable will be anything until the next slash. For example: + + r := mux.NewRouter() + r.HandleFunc("/products/{key}", ProductHandler) + r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler) + r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) + +Groups can be used inside patterns, as long as they are non-capturing (?:re). For example: + + r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler) + +The names are used to create a map of route variables which can be retrieved +calling mux.Vars(): + + vars := mux.Vars(request) + category := vars["category"] + +Note that if any capturing groups are present, mux will panic() during parsing. To prevent +this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to +"/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably +when capturing groups were present. + +And this is all you need to know about the basic usage. More advanced options +are explained below. + +Routes can also be restricted to a domain or subdomain. Just define a host +pattern to be matched. They can also have variables: + + r := mux.NewRouter() + // Only matches if domain is "www.example.com". + r.Host("www.example.com") + // Matches a dynamic subdomain. + r.Host("{subdomain:[a-z]+}.domain.com") + +There are several other matchers that can be added. To match path prefixes: + + r.PathPrefix("/products/") + +...or HTTP methods: + + r.Methods("GET", "POST") + +...or URL schemes: + + r.Schemes("https") + +...or header values: + + r.Headers("X-Requested-With", "XMLHttpRequest") + +...or query values: + + r.Queries("key", "value") + +...or to use a custom matcher function: + + r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { + return r.ProtoMajor == 0 + }) + +...and finally, it is possible to combine several matchers in a single route: + + r.HandleFunc("/products", ProductsHandler). + Host("www.example.com"). + Methods("GET"). + Schemes("http") + +Setting the same matching conditions again and again can be boring, so we have +a way to group several routes that share the same requirements. +We call it "subrouting". + +For example, let's say we have several URLs that should only match when the +host is "www.example.com". Create a route for that host and get a "subrouter" +from it: + + r := mux.NewRouter() + s := r.Host("www.example.com").Subrouter() + +Then register routes in the subrouter: + + s.HandleFunc("/products/", ProductsHandler) + s.HandleFunc("/products/{key}", ProductHandler) + s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) + +The three URL paths we registered above will only be tested if the domain is +"www.example.com", because the subrouter is tested first. This is not +only convenient, but also optimizes request matching. You can create +subrouters combining any attribute matchers accepted by a route. + +Subrouters can be used to create domain or path "namespaces": you define +subrouters in a central place and then parts of the app can register its +paths relatively to a given subrouter. + +There's one more thing about subroutes. When a subrouter has a path prefix, +the inner routes use it as base for their paths: + + r := mux.NewRouter() + s := r.PathPrefix("/products").Subrouter() + // "/products/" + s.HandleFunc("/", ProductsHandler) + // "/products/{key}/" + s.HandleFunc("/{key}/", ProductHandler) + // "/products/{key}/details" + s.HandleFunc("/{key}/details", ProductDetailsHandler) + +Note that the path provided to PathPrefix() represents a "wildcard": calling +PathPrefix("/static/").Handler(...) means that the handler will be passed any +request that matches "/static/*". This makes it easy to serve static files with mux: + + func main() { + var dir string + + flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") + flag.Parse() + r := mux.NewRouter() + + // This will serve files under http://localhost:8000/static/ + r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) + + srv := &http.Server{ + Handler: r, + Addr: "127.0.0.1:8000", + // Good practice: enforce timeouts for servers you create! + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + + log.Fatal(srv.ListenAndServe()) + } + +Now let's see how to build registered URLs. + +Routes can be named. All routes that define a name can have their URLs built, +or "reversed". We define a name calling Name() on a route. For example: + + r := mux.NewRouter() + r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). + Name("article") + +To build a URL, get the route and call the URL() method, passing a sequence of +key/value pairs for the route variables. For the previous route, we would do: + + url, err := r.Get("article").URL("category", "technology", "id", "42") + +...and the result will be a url.URL with the following path: + + "/articles/technology/42" + +This also works for host variables: + + r := mux.NewRouter() + r.Host("{subdomain}.domain.com"). + Path("/articles/{category}/{id:[0-9]+}"). + HandlerFunc(ArticleHandler). + Name("article") + + // url.String() will be "http://news.domain.com/articles/technology/42" + url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42") + +All variables defined in the route are required, and their values must +conform to the corresponding patterns. These requirements guarantee that a +generated URL will always match a registered route -- the only exception is +for explicitly defined "build-only" routes which never match. + +Regex support also exists for matching Headers within a route. For example, we could do: + + r.HeadersRegexp("Content-Type", "application/(text|json)") + +...and the route will match both requests with a Content-Type of `application/json` as well as +`application/text` + +There's also a way to build only the URL host or path for a route: +use the methods URLHost() or URLPath() instead. For the previous route, +we would do: + + // "http://news.domain.com/" + host, err := r.Get("article").URLHost("subdomain", "news") + + // "/articles/technology/42" + path, err := r.Get("article").URLPath("category", "technology", "id", "42") + +And if you use subrouters, host and path defined separately can be built +as well: + + r := mux.NewRouter() + s := r.Host("{subdomain}.domain.com").Subrouter() + s.Path("/articles/{category}/{id:[0-9]+}"). + HandlerFunc(ArticleHandler). + Name("article") + + // "http://news.domain.com/articles/technology/42" + url, err := r.Get("article").URL("subdomain", "news", + "category", "technology", + "id", "42") +*/ +package mux diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go new file mode 100644 index 000000000..d66ec3841 --- /dev/null +++ b/vendor/github.com/gorilla/mux/mux.go @@ -0,0 +1,542 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mux + +import ( + "errors" + "fmt" + "net/http" + "path" + "regexp" + "strings" +) + +// NewRouter returns a new router instance. +func NewRouter() *Router { + return &Router{namedRoutes: make(map[string]*Route), KeepContext: false} +} + +// Router registers routes to be matched and dispatches a handler. +// +// It implements the http.Handler interface, so it can be registered to serve +// requests: +// +// var router = mux.NewRouter() +// +// func main() { +// http.Handle("/", router) +// } +// +// Or, for Google App Engine, register it in a init() function: +// +// func init() { +// http.Handle("/", router) +// } +// +// This will send all incoming requests to the router. +type Router struct { + // Configurable Handler to be used when no route matches. + NotFoundHandler http.Handler + // Parent route, if this is a subrouter. + parent parentRoute + // Routes to be matched, in order. + routes []*Route + // Routes by name for URL building. + namedRoutes map[string]*Route + // See Router.StrictSlash(). This defines the flag for new routes. + strictSlash bool + // See Router.SkipClean(). This defines the flag for new routes. + skipClean bool + // If true, do not clear the request context after handling the request. + // This has no effect when go1.7+ is used, since the context is stored + // on the request itself. + KeepContext bool + // see Router.UseEncodedPath(). This defines a flag for all routes. + useEncodedPath bool +} + +// Match matches registered routes against the request. +func (r *Router) Match(req *http.Request, match *RouteMatch) bool { + for _, route := range r.routes { + if route.Match(req, match) { + return true + } + } + + // Closest match for a router (includes sub-routers) + if r.NotFoundHandler != nil { + match.Handler = r.NotFoundHandler + return true + } + return false +} + +// ServeHTTP dispatches the handler registered in the matched route. +// +// When there is a match, the route variables can be retrieved calling +// mux.Vars(request). +func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { + if !r.skipClean { + path := req.URL.Path + if r.useEncodedPath { + path = getPath(req) + } + // Clean path to canonical form and redirect. + if p := cleanPath(path); p != path { + + // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query. + // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue: + // http://code.google.com/p/go/issues/detail?id=5252 + url := *req.URL + url.Path = p + p = url.String() + + w.Header().Set("Location", p) + w.WriteHeader(http.StatusMovedPermanently) + return + } + } + var match RouteMatch + var handler http.Handler + if r.Match(req, &match) { + handler = match.Handler + req = setVars(req, match.Vars) + req = setCurrentRoute(req, match.Route) + } + if handler == nil { + handler = http.NotFoundHandler() + } + if !r.KeepContext { + defer contextClear(req) + } + handler.ServeHTTP(w, req) +} + +// Get returns a route registered with the given name. +func (r *Router) Get(name string) *Route { + return r.getNamedRoutes()[name] +} + +// GetRoute returns a route registered with the given name. This method +// was renamed to Get() and remains here for backwards compatibility. +func (r *Router) GetRoute(name string) *Route { + return r.getNamedRoutes()[name] +} + +// StrictSlash defines the trailing slash behavior for new routes. The initial +// value is false. +// +// When true, if the route path is "/path/", accessing "/path" will redirect +// to the former and vice versa. In other words, your application will always +// see the path as specified in the route. +// +// When false, if the route path is "/path", accessing "/path/" will not match +// this route and vice versa. +// +// Special case: when a route sets a path prefix using the PathPrefix() method, +// strict slash is ignored for that route because the redirect behavior can't +// be determined from a prefix alone. However, any subrouters created from that +// route inherit the original StrictSlash setting. +func (r *Router) StrictSlash(value bool) *Router { + r.strictSlash = value + return r +} + +// SkipClean defines the path cleaning behaviour for new routes. The initial +// value is false. Users should be careful about which routes are not cleaned +// +// When true, if the route path is "/path//to", it will remain with the double +// slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/ +// +// When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will +// become /fetch/http/xkcd.com/534 +func (r *Router) SkipClean(value bool) *Router { + r.skipClean = value + return r +} + +// UseEncodedPath tells the router to match the encoded original path +// to the routes. +// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to". +// This behavior has the drawback of needing to match routes against +// r.RequestURI instead of r.URL.Path. Any modifications (such as http.StripPrefix) +// to r.URL.Path will not affect routing when this flag is on and thus may +// induce unintended behavior. +// +// If not called, the router will match the unencoded path to the routes. +// For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to" +func (r *Router) UseEncodedPath() *Router { + r.useEncodedPath = true + return r +} + +// ---------------------------------------------------------------------------- +// parentRoute +// ---------------------------------------------------------------------------- + +// getNamedRoutes returns the map where named routes are registered. +func (r *Router) getNamedRoutes() map[string]*Route { + if r.namedRoutes == nil { + if r.parent != nil { + r.namedRoutes = r.parent.getNamedRoutes() + } else { + r.namedRoutes = make(map[string]*Route) + } + } + return r.namedRoutes +} + +// getRegexpGroup returns regexp definitions from the parent route, if any. +func (r *Router) getRegexpGroup() *routeRegexpGroup { + if r.parent != nil { + return r.parent.getRegexpGroup() + } + return nil +} + +func (r *Router) buildVars(m map[string]string) map[string]string { + if r.parent != nil { + m = r.parent.buildVars(m) + } + return m +} + +// ---------------------------------------------------------------------------- +// Route factories +// ---------------------------------------------------------------------------- + +// NewRoute registers an empty route. +func (r *Router) NewRoute() *Route { + route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath} + r.routes = append(r.routes, route) + return route +} + +// Handle registers a new route with a matcher for the URL path. +// See Route.Path() and Route.Handler(). +func (r *Router) Handle(path string, handler http.Handler) *Route { + return r.NewRoute().Path(path).Handler(handler) +} + +// HandleFunc registers a new route with a matcher for the URL path. +// See Route.Path() and Route.HandlerFunc(). +func (r *Router) HandleFunc(path string, f func(http.ResponseWriter, + *http.Request)) *Route { + return r.NewRoute().Path(path).HandlerFunc(f) +} + +// Headers registers a new route with a matcher for request header values. +// See Route.Headers(). +func (r *Router) Headers(pairs ...string) *Route { + return r.NewRoute().Headers(pairs...) +} + +// Host registers a new route with a matcher for the URL host. +// See Route.Host(). +func (r *Router) Host(tpl string) *Route { + return r.NewRoute().Host(tpl) +} + +// MatcherFunc registers a new route with a custom matcher function. +// See Route.MatcherFunc(). +func (r *Router) MatcherFunc(f MatcherFunc) *Route { + return r.NewRoute().MatcherFunc(f) +} + +// Methods registers a new route with a matcher for HTTP methods. +// See Route.Methods(). +func (r *Router) Methods(methods ...string) *Route { + return r.NewRoute().Methods(methods...) +} + +// Path registers a new route with a matcher for the URL path. +// See Route.Path(). +func (r *Router) Path(tpl string) *Route { + return r.NewRoute().Path(tpl) +} + +// PathPrefix registers a new route with a matcher for the URL path prefix. +// See Route.PathPrefix(). +func (r *Router) PathPrefix(tpl string) *Route { + return r.NewRoute().PathPrefix(tpl) +} + +// Queries registers a new route with a matcher for URL query values. +// See Route.Queries(). +func (r *Router) Queries(pairs ...string) *Route { + return r.NewRoute().Queries(pairs...) +} + +// Schemes registers a new route with a matcher for URL schemes. +// See Route.Schemes(). +func (r *Router) Schemes(schemes ...string) *Route { + return r.NewRoute().Schemes(schemes...) +} + +// BuildVarsFunc registers a new route with a custom function for modifying +// route variables before building a URL. +func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route { + return r.NewRoute().BuildVarsFunc(f) +} + +// Walk walks the router and all its sub-routers, calling walkFn for each route +// in the tree. The routes are walked in the order they were added. Sub-routers +// are explored depth-first. +func (r *Router) Walk(walkFn WalkFunc) error { + return r.walk(walkFn, []*Route{}) +} + +// SkipRouter is used as a return value from WalkFuncs to indicate that the +// router that walk is about to descend down to should be skipped. +var SkipRouter = errors.New("skip this router") + +// WalkFunc is the type of the function called for each route visited by Walk. +// At every invocation, it is given the current route, and the current router, +// and a list of ancestor routes that lead to the current route. +type WalkFunc func(route *Route, router *Router, ancestors []*Route) error + +func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error { + for _, t := range r.routes { + if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" { + continue + } + + err := walkFn(t, r, ancestors) + if err == SkipRouter { + continue + } + if err != nil { + return err + } + for _, sr := range t.matchers { + if h, ok := sr.(*Router); ok { + err := h.walk(walkFn, ancestors) + if err != nil { + return err + } + } + } + if h, ok := t.handler.(*Router); ok { + ancestors = append(ancestors, t) + err := h.walk(walkFn, ancestors) + if err != nil { + return err + } + ancestors = ancestors[:len(ancestors)-1] + } + } + return nil +} + +// ---------------------------------------------------------------------------- +// Context +// ---------------------------------------------------------------------------- + +// RouteMatch stores information about a matched route. +type RouteMatch struct { + Route *Route + Handler http.Handler + Vars map[string]string +} + +type contextKey int + +const ( + varsKey contextKey = iota + routeKey +) + +// Vars returns the route variables for the current request, if any. +func Vars(r *http.Request) map[string]string { + if rv := contextGet(r, varsKey); rv != nil { + return rv.(map[string]string) + } + return nil +} + +// CurrentRoute returns the matched route for the current request, if any. +// This only works when called inside the handler of the matched route +// because the matched route is stored in the request context which is cleared +// after the handler returns, unless the KeepContext option is set on the +// Router. +func CurrentRoute(r *http.Request) *Route { + if rv := contextGet(r, routeKey); rv != nil { + return rv.(*Route) + } + return nil +} + +func setVars(r *http.Request, val interface{}) *http.Request { + return contextSet(r, varsKey, val) +} + +func setCurrentRoute(r *http.Request, val interface{}) *http.Request { + return contextSet(r, routeKey, val) +} + +// ---------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------- + +// getPath returns the escaped path if possible; doing what URL.EscapedPath() +// which was added in go1.5 does +func getPath(req *http.Request) string { + if req.RequestURI != "" { + // Extract the path from RequestURI (which is escaped unlike URL.Path) + // as detailed here as detailed in https://golang.org/pkg/net/url/#URL + // for < 1.5 server side workaround + // http://localhost/path/here?v=1 -> /path/here + path := req.RequestURI + path = strings.TrimPrefix(path, req.URL.Scheme+`://`) + path = strings.TrimPrefix(path, req.URL.Host) + if i := strings.LastIndex(path, "?"); i > -1 { + path = path[:i] + } + if i := strings.LastIndex(path, "#"); i > -1 { + path = path[:i] + } + return path + } + return req.URL.Path +} + +// cleanPath returns the canonical path for p, eliminating . and .. elements. +// Borrowed from the net/http package. +func cleanPath(p string) string { + if p == "" { + return "/" + } + if p[0] != '/' { + p = "/" + p + } + np := path.Clean(p) + // path.Clean removes trailing slash except for root; + // put the trailing slash back if necessary. + if p[len(p)-1] == '/' && np != "/" { + np += "/" + } + + return np +} + +// uniqueVars returns an error if two slices contain duplicated strings. +func uniqueVars(s1, s2 []string) error { + for _, v1 := range s1 { + for _, v2 := range s2 { + if v1 == v2 { + return fmt.Errorf("mux: duplicated route variable %q", v2) + } + } + } + return nil +} + +// checkPairs returns the count of strings passed in, and an error if +// the count is not an even number. +func checkPairs(pairs ...string) (int, error) { + length := len(pairs) + if length%2 != 0 { + return length, fmt.Errorf( + "mux: number of parameters must be multiple of 2, got %v", pairs) + } + return length, nil +} + +// mapFromPairsToString converts variadic string parameters to a +// string to string map. +func mapFromPairsToString(pairs ...string) (map[string]string, error) { + length, err := checkPairs(pairs...) + if err != nil { + return nil, err + } + m := make(map[string]string, length/2) + for i := 0; i < length; i += 2 { + m[pairs[i]] = pairs[i+1] + } + return m, nil +} + +// mapFromPairsToRegex converts variadic string paramers to a +// string to regex map. +func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) { + length, err := checkPairs(pairs...) + if err != nil { + return nil, err + } + m := make(map[string]*regexp.Regexp, length/2) + for i := 0; i < length; i += 2 { + regex, err := regexp.Compile(pairs[i+1]) + if err != nil { + return nil, err + } + m[pairs[i]] = regex + } + return m, nil +} + +// matchInArray returns true if the given string value is in the array. +func matchInArray(arr []string, value string) bool { + for _, v := range arr { + if v == value { + return true + } + } + return false +} + +// matchMapWithString returns true if the given key/value pairs exist in a given map. +func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool { + for k, v := range toCheck { + // Check if key exists. + if canonicalKey { + k = http.CanonicalHeaderKey(k) + } + if values := toMatch[k]; values == nil { + return false + } else if v != "" { + // If value was defined as an empty string we only check that the + // key exists. Otherwise we also check for equality. + valueExists := false + for _, value := range values { + if v == value { + valueExists = true + break + } + } + if !valueExists { + return false + } + } + } + return true +} + +// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against +// the given regex +func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool { + for k, v := range toCheck { + // Check if key exists. + if canonicalKey { + k = http.CanonicalHeaderKey(k) + } + if values := toMatch[k]; values == nil { + return false + } else if v != nil { + // If value was defined as an empty string we only check that the + // key exists. Otherwise we also check for equality. + valueExists := false + for _, value := range values { + if v.MatchString(value) { + valueExists = true + break + } + } + if !valueExists { + return false + } + } + } + return true +} diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go new file mode 100644 index 000000000..0189ad346 --- /dev/null +++ b/vendor/github.com/gorilla/mux/regexp.go @@ -0,0 +1,323 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mux + +import ( + "bytes" + "fmt" + "net/http" + "net/url" + "regexp" + "strconv" + "strings" +) + +// newRouteRegexp parses a route template and returns a routeRegexp, +// used to match a host, a path or a query string. +// +// It will extract named variables, assemble a regexp to be matched, create +// a "reverse" template to build URLs and compile regexps to validate variable +// values used in URL building. +// +// Previously we accepted only Python-like identifiers for variable +// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that +// name and pattern can't be empty, and names can't contain a colon. +func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, useEncodedPath bool) (*routeRegexp, error) { + // Check if it is well-formed. + idxs, errBraces := braceIndices(tpl) + if errBraces != nil { + return nil, errBraces + } + // Backup the original. + template := tpl + // Now let's parse it. + defaultPattern := "[^/]+" + if matchQuery { + defaultPattern = "[^?&]*" + } else if matchHost { + defaultPattern = "[^.]+" + matchPrefix = false + } + // Only match strict slash if not matching + if matchPrefix || matchHost || matchQuery { + strictSlash = false + } + // Set a flag for strictSlash. + endSlash := false + if strictSlash && strings.HasSuffix(tpl, "/") { + tpl = tpl[:len(tpl)-1] + endSlash = true + } + varsN := make([]string, len(idxs)/2) + varsR := make([]*regexp.Regexp, len(idxs)/2) + pattern := bytes.NewBufferString("") + pattern.WriteByte('^') + reverse := bytes.NewBufferString("") + var end int + var err error + for i := 0; i < len(idxs); i += 2 { + // Set all values we are interested in. + raw := tpl[end:idxs[i]] + end = idxs[i+1] + parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2) + name := parts[0] + patt := defaultPattern + if len(parts) == 2 { + patt = parts[1] + } + // Name or pattern can't be empty. + if name == "" || patt == "" { + return nil, fmt.Errorf("mux: missing name or pattern in %q", + tpl[idxs[i]:end]) + } + // Build the regexp pattern. + fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt) + + // Build the reverse template. + fmt.Fprintf(reverse, "%s%%s", raw) + + // Append variable name and compiled pattern. + varsN[i/2] = name + varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt)) + if err != nil { + return nil, err + } + } + // Add the remaining. + raw := tpl[end:] + pattern.WriteString(regexp.QuoteMeta(raw)) + if strictSlash { + pattern.WriteString("[/]?") + } + if matchQuery { + // Add the default pattern if the query value is empty + if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" { + pattern.WriteString(defaultPattern) + } + } + if !matchPrefix { + pattern.WriteByte('$') + } + reverse.WriteString(raw) + if endSlash { + reverse.WriteByte('/') + } + // Compile full regexp. + reg, errCompile := regexp.Compile(pattern.String()) + if errCompile != nil { + return nil, errCompile + } + + // Check for capturing groups which used to work in older versions + if reg.NumSubexp() != len(idxs)/2 { + panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) + + "Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)") + } + + // Done! + return &routeRegexp{ + template: template, + matchHost: matchHost, + matchQuery: matchQuery, + strictSlash: strictSlash, + useEncodedPath: useEncodedPath, + regexp: reg, + reverse: reverse.String(), + varsN: varsN, + varsR: varsR, + }, nil +} + +// routeRegexp stores a regexp to match a host or path and information to +// collect and validate route variables. +type routeRegexp struct { + // The unmodified template. + template string + // True for host match, false for path or query string match. + matchHost bool + // True for query string match, false for path and host match. + matchQuery bool + // The strictSlash value defined on the route, but disabled if PathPrefix was used. + strictSlash bool + // Determines whether to use encoded path from getPath function or unencoded + // req.URL.Path for path matching + useEncodedPath bool + // Expanded regexp. + regexp *regexp.Regexp + // Reverse template. + reverse string + // Variable names. + varsN []string + // Variable regexps (validators). + varsR []*regexp.Regexp +} + +// Match matches the regexp against the URL host or path. +func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { + if !r.matchHost { + if r.matchQuery { + return r.matchQueryString(req) + } + path := req.URL.Path + if r.useEncodedPath { + path = getPath(req) + } + return r.regexp.MatchString(path) + } + + return r.regexp.MatchString(getHost(req)) +} + +// url builds a URL part using the given values. +func (r *routeRegexp) url(values map[string]string) (string, error) { + urlValues := make([]interface{}, len(r.varsN)) + for k, v := range r.varsN { + value, ok := values[v] + if !ok { + return "", fmt.Errorf("mux: missing route variable %q", v) + } + urlValues[k] = value + } + rv := fmt.Sprintf(r.reverse, urlValues...) + if !r.regexp.MatchString(rv) { + // The URL is checked against the full regexp, instead of checking + // individual variables. This is faster but to provide a good error + // message, we check individual regexps if the URL doesn't match. + for k, v := range r.varsN { + if !r.varsR[k].MatchString(values[v]) { + return "", fmt.Errorf( + "mux: variable %q doesn't match, expected %q", values[v], + r.varsR[k].String()) + } + } + } + return rv, nil +} + +// getURLQuery returns a single query parameter from a request URL. +// For a URL with foo=bar&baz=ding, we return only the relevant key +// value pair for the routeRegexp. +func (r *routeRegexp) getURLQuery(req *http.Request) string { + if !r.matchQuery { + return "" + } + templateKey := strings.SplitN(r.template, "=", 2)[0] + for key, vals := range req.URL.Query() { + if key == templateKey && len(vals) > 0 { + return key + "=" + vals[0] + } + } + return "" +} + +func (r *routeRegexp) matchQueryString(req *http.Request) bool { + return r.regexp.MatchString(r.getURLQuery(req)) +} + +// braceIndices returns the first level curly brace indices from a string. +// It returns an error in case of unbalanced braces. +func braceIndices(s string) ([]int, error) { + var level, idx int + var idxs []int + for i := 0; i < len(s); i++ { + switch s[i] { + case '{': + if level++; level == 1 { + idx = i + } + case '}': + if level--; level == 0 { + idxs = append(idxs, idx, i+1) + } else if level < 0 { + return nil, fmt.Errorf("mux: unbalanced braces in %q", s) + } + } + } + if level != 0 { + return nil, fmt.Errorf("mux: unbalanced braces in %q", s) + } + return idxs, nil +} + +// varGroupName builds a capturing group name for the indexed variable. +func varGroupName(idx int) string { + return "v" + strconv.Itoa(idx) +} + +// ---------------------------------------------------------------------------- +// routeRegexpGroup +// ---------------------------------------------------------------------------- + +// routeRegexpGroup groups the route matchers that carry variables. +type routeRegexpGroup struct { + host *routeRegexp + path *routeRegexp + queries []*routeRegexp +} + +// setMatch extracts the variables from the URL once a route matches. +func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) { + // Store host variables. + if v.host != nil { + host := getHost(req) + matches := v.host.regexp.FindStringSubmatchIndex(host) + if len(matches) > 0 { + extractVars(host, matches, v.host.varsN, m.Vars) + } + } + path := req.URL.Path + if r.useEncodedPath { + path = getPath(req) + } + // Store path variables. + if v.path != nil { + matches := v.path.regexp.FindStringSubmatchIndex(path) + if len(matches) > 0 { + extractVars(path, matches, v.path.varsN, m.Vars) + // Check if we should redirect. + if v.path.strictSlash { + p1 := strings.HasSuffix(path, "/") + p2 := strings.HasSuffix(v.path.template, "/") + if p1 != p2 { + u, _ := url.Parse(req.URL.String()) + if p1 { + u.Path = u.Path[:len(u.Path)-1] + } else { + u.Path += "/" + } + m.Handler = http.RedirectHandler(u.String(), 301) + } + } + } + } + // Store query string variables. + for _, q := range v.queries { + queryURL := q.getURLQuery(req) + matches := q.regexp.FindStringSubmatchIndex(queryURL) + if len(matches) > 0 { + extractVars(queryURL, matches, q.varsN, m.Vars) + } + } +} + +// getHost tries its best to return the request host. +func getHost(r *http.Request) string { + if r.URL.IsAbs() { + return r.URL.Host + } + host := r.Host + // Slice off any port information. + if i := strings.Index(host, ":"); i != -1 { + host = host[:i] + } + return host + +} + +func extractVars(input string, matches []int, names []string, output map[string]string) { + for i, name := range names { + output[name] = input[matches[2*i+2]:matches[2*i+3]] + } +} diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go new file mode 100644 index 000000000..5544c1fd6 --- /dev/null +++ b/vendor/github.com/gorilla/mux/route.go @@ -0,0 +1,636 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mux + +import ( + "errors" + "fmt" + "net/http" + "net/url" + "regexp" + "strings" +) + +// Route stores information to match a request and build URLs. +type Route struct { + // Parent where the route was registered (a Router). + parent parentRoute + // Request handler for the route. + handler http.Handler + // List of matchers. + matchers []matcher + // Manager for the variables from host and path. + regexp *routeRegexpGroup + // If true, when the path pattern is "/path/", accessing "/path" will + // redirect to the former and vice versa. + strictSlash bool + // If true, when the path pattern is "/path//to", accessing "/path//to" + // will not redirect + skipClean bool + // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to" + useEncodedPath bool + // If true, this route never matches: it is only used to build URLs. + buildOnly bool + // The name used to build URLs. + name string + // Error resulted from building a route. + err error + + buildVarsFunc BuildVarsFunc +} + +func (r *Route) SkipClean() bool { + return r.skipClean +} + +// Match matches the route against the request. +func (r *Route) Match(req *http.Request, match *RouteMatch) bool { + if r.buildOnly || r.err != nil { + return false + } + // Match everything. + for _, m := range r.matchers { + if matched := m.Match(req, match); !matched { + return false + } + } + // Yay, we have a match. Let's collect some info about it. + if match.Route == nil { + match.Route = r + } + if match.Handler == nil { + match.Handler = r.handler + } + if match.Vars == nil { + match.Vars = make(map[string]string) + } + // Set variables. + if r.regexp != nil { + r.regexp.setMatch(req, match, r) + } + return true +} + +// ---------------------------------------------------------------------------- +// Route attributes +// ---------------------------------------------------------------------------- + +// GetError returns an error resulted from building the route, if any. +func (r *Route) GetError() error { + return r.err +} + +// BuildOnly sets the route to never match: it is only used to build URLs. +func (r *Route) BuildOnly() *Route { + r.buildOnly = true + return r +} + +// Handler -------------------------------------------------------------------- + +// Handler sets a handler for the route. +func (r *Route) Handler(handler http.Handler) *Route { + if r.err == nil { + r.handler = handler + } + return r +} + +// HandlerFunc sets a handler function for the route. +func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route { + return r.Handler(http.HandlerFunc(f)) +} + +// GetHandler returns the handler for the route, if any. +func (r *Route) GetHandler() http.Handler { + return r.handler +} + +// Name ----------------------------------------------------------------------- + +// Name sets the name for the route, used to build URLs. +// If the name was registered already it will be overwritten. +func (r *Route) Name(name string) *Route { + if r.name != "" { + r.err = fmt.Errorf("mux: route already has name %q, can't set %q", + r.name, name) + } + if r.err == nil { + r.name = name + r.getNamedRoutes()[name] = r + } + return r +} + +// GetName returns the name for the route, if any. +func (r *Route) GetName() string { + return r.name +} + +// ---------------------------------------------------------------------------- +// Matchers +// ---------------------------------------------------------------------------- + +// matcher types try to match a request. +type matcher interface { + Match(*http.Request, *RouteMatch) bool +} + +// addMatcher adds a matcher to the route. +func (r *Route) addMatcher(m matcher) *Route { + if r.err == nil { + r.matchers = append(r.matchers, m) + } + return r +} + +// addRegexpMatcher adds a host or path matcher and builder to a route. +func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery bool) error { + if r.err != nil { + return r.err + } + r.regexp = r.getRegexpGroup() + if !matchHost && !matchQuery { + if len(tpl) > 0 && tpl[0] != '/' { + return fmt.Errorf("mux: path must start with a slash, got %q", tpl) + } + if r.regexp.path != nil { + tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl + } + } + rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash, r.useEncodedPath) + if err != nil { + return err + } + for _, q := range r.regexp.queries { + if err = uniqueVars(rr.varsN, q.varsN); err != nil { + return err + } + } + if matchHost { + if r.regexp.path != nil { + if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil { + return err + } + } + r.regexp.host = rr + } else { + if r.regexp.host != nil { + if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil { + return err + } + } + if matchQuery { + r.regexp.queries = append(r.regexp.queries, rr) + } else { + r.regexp.path = rr + } + } + r.addMatcher(rr) + return nil +} + +// Headers -------------------------------------------------------------------- + +// headerMatcher matches the request against header values. +type headerMatcher map[string]string + +func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchMapWithString(m, r.Header, true) +} + +// Headers adds a matcher for request header values. +// It accepts a sequence of key/value pairs to be matched. For example: +// +// r := mux.NewRouter() +// r.Headers("Content-Type", "application/json", +// "X-Requested-With", "XMLHttpRequest") +// +// The above route will only match if both request header values match. +// If the value is an empty string, it will match any value if the key is set. +func (r *Route) Headers(pairs ...string) *Route { + if r.err == nil { + var headers map[string]string + headers, r.err = mapFromPairsToString(pairs...) + return r.addMatcher(headerMatcher(headers)) + } + return r +} + +// headerRegexMatcher matches the request against the route given a regex for the header +type headerRegexMatcher map[string]*regexp.Regexp + +func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchMapWithRegex(m, r.Header, true) +} + +// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex +// support. For example: +// +// r := mux.NewRouter() +// r.HeadersRegexp("Content-Type", "application/(text|json)", +// "X-Requested-With", "XMLHttpRequest") +// +// The above route will only match if both the request header matches both regular expressions. +// It the value is an empty string, it will match any value if the key is set. +func (r *Route) HeadersRegexp(pairs ...string) *Route { + if r.err == nil { + var headers map[string]*regexp.Regexp + headers, r.err = mapFromPairsToRegex(pairs...) + return r.addMatcher(headerRegexMatcher(headers)) + } + return r +} + +// Host ----------------------------------------------------------------------- + +// Host adds a matcher for the URL host. +// It accepts a template with zero or more URL variables enclosed by {}. +// Variables can define an optional regexp pattern to be matched: +// +// - {name} matches anything until the next dot. +// +// - {name:pattern} matches the given regexp pattern. +// +// For example: +// +// r := mux.NewRouter() +// r.Host("www.example.com") +// r.Host("{subdomain}.domain.com") +// r.Host("{subdomain:[a-z]+}.domain.com") +// +// Variable names must be unique in a given route. They can be retrieved +// calling mux.Vars(request). +func (r *Route) Host(tpl string) *Route { + r.err = r.addRegexpMatcher(tpl, true, false, false) + return r +} + +// MatcherFunc ---------------------------------------------------------------- + +// MatcherFunc is the function signature used by custom matchers. +type MatcherFunc func(*http.Request, *RouteMatch) bool + +// Match returns the match for a given request. +func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool { + return m(r, match) +} + +// MatcherFunc adds a custom function to be used as request matcher. +func (r *Route) MatcherFunc(f MatcherFunc) *Route { + return r.addMatcher(f) +} + +// Methods -------------------------------------------------------------------- + +// methodMatcher matches the request against HTTP methods. +type methodMatcher []string + +func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchInArray(m, r.Method) +} + +// Methods adds a matcher for HTTP methods. +// It accepts a sequence of one or more methods to be matched, e.g.: +// "GET", "POST", "PUT". +func (r *Route) Methods(methods ...string) *Route { + for k, v := range methods { + methods[k] = strings.ToUpper(v) + } + return r.addMatcher(methodMatcher(methods)) +} + +// Path ----------------------------------------------------------------------- + +// Path adds a matcher for the URL path. +// It accepts a template with zero or more URL variables enclosed by {}. The +// template must start with a "/". +// Variables can define an optional regexp pattern to be matched: +// +// - {name} matches anything until the next slash. +// +// - {name:pattern} matches the given regexp pattern. +// +// For example: +// +// r := mux.NewRouter() +// r.Path("/products/").Handler(ProductsHandler) +// r.Path("/products/{key}").Handler(ProductsHandler) +// r.Path("/articles/{category}/{id:[0-9]+}"). +// Handler(ArticleHandler) +// +// Variable names must be unique in a given route. They can be retrieved +// calling mux.Vars(request). +func (r *Route) Path(tpl string) *Route { + r.err = r.addRegexpMatcher(tpl, false, false, false) + return r +} + +// PathPrefix ----------------------------------------------------------------- + +// PathPrefix adds a matcher for the URL path prefix. This matches if the given +// template is a prefix of the full URL path. See Route.Path() for details on +// the tpl argument. +// +// Note that it does not treat slashes specially ("/foobar/" will be matched by +// the prefix "/foo") so you may want to use a trailing slash here. +// +// Also note that the setting of Router.StrictSlash() has no effect on routes +// with a PathPrefix matcher. +func (r *Route) PathPrefix(tpl string) *Route { + r.err = r.addRegexpMatcher(tpl, false, true, false) + return r +} + +// Query ---------------------------------------------------------------------- + +// Queries adds a matcher for URL query values. +// It accepts a sequence of key/value pairs. Values may define variables. +// For example: +// +// r := mux.NewRouter() +// r.Queries("foo", "bar", "id", "{id:[0-9]+}") +// +// The above route will only match if the URL contains the defined queries +// values, e.g.: ?foo=bar&id=42. +// +// It the value is an empty string, it will match any value if the key is set. +// +// Variables can define an optional regexp pattern to be matched: +// +// - {name} matches anything until the next slash. +// +// - {name:pattern} matches the given regexp pattern. +func (r *Route) Queries(pairs ...string) *Route { + length := len(pairs) + if length%2 != 0 { + r.err = fmt.Errorf( + "mux: number of parameters must be multiple of 2, got %v", pairs) + return nil + } + for i := 0; i < length; i += 2 { + if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, false, true); r.err != nil { + return r + } + } + + return r +} + +// Schemes -------------------------------------------------------------------- + +// schemeMatcher matches the request against URL schemes. +type schemeMatcher []string + +func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool { + return matchInArray(m, r.URL.Scheme) +} + +// Schemes adds a matcher for URL schemes. +// It accepts a sequence of schemes to be matched, e.g.: "http", "https". +func (r *Route) Schemes(schemes ...string) *Route { + for k, v := range schemes { + schemes[k] = strings.ToLower(v) + } + return r.addMatcher(schemeMatcher(schemes)) +} + +// BuildVarsFunc -------------------------------------------------------------- + +// BuildVarsFunc is the function signature used by custom build variable +// functions (which can modify route variables before a route's URL is built). +type BuildVarsFunc func(map[string]string) map[string]string + +// BuildVarsFunc adds a custom function to be used to modify build variables +// before a route's URL is built. +func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route { + r.buildVarsFunc = f + return r +} + +// Subrouter ------------------------------------------------------------------ + +// Subrouter creates a subrouter for the route. +// +// It will test the inner routes only if the parent route matched. For example: +// +// r := mux.NewRouter() +// s := r.Host("www.example.com").Subrouter() +// s.HandleFunc("/products/", ProductsHandler) +// s.HandleFunc("/products/{key}", ProductHandler) +// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) +// +// Here, the routes registered in the subrouter won't be tested if the host +// doesn't match. +func (r *Route) Subrouter() *Router { + router := &Router{parent: r, strictSlash: r.strictSlash} + r.addMatcher(router) + return router +} + +// ---------------------------------------------------------------------------- +// URL building +// ---------------------------------------------------------------------------- + +// URL builds a URL for the route. +// +// It accepts a sequence of key/value pairs for the route variables. For +// example, given this route: +// +// r := mux.NewRouter() +// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). +// Name("article") +// +// ...a URL for it can be built using: +// +// url, err := r.Get("article").URL("category", "technology", "id", "42") +// +// ...which will return an url.URL with the following path: +// +// "/articles/technology/42" +// +// This also works for host variables: +// +// r := mux.NewRouter() +// r.Host("{subdomain}.domain.com"). +// HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). +// Name("article") +// +// // url.String() will be "http://news.domain.com/articles/technology/42" +// url, err := r.Get("article").URL("subdomain", "news", +// "category", "technology", +// "id", "42") +// +// All variables defined in the route are required, and their values must +// conform to the corresponding patterns. +func (r *Route) URL(pairs ...string) (*url.URL, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil { + return nil, errors.New("mux: route doesn't have a host or path") + } + values, err := r.prepareVars(pairs...) + if err != nil { + return nil, err + } + var scheme, host, path string + if r.regexp.host != nil { + // Set a default scheme. + scheme = "http" + if host, err = r.regexp.host.url(values); err != nil { + return nil, err + } + } + if r.regexp.path != nil { + if path, err = r.regexp.path.url(values); err != nil { + return nil, err + } + } + return &url.URL{ + Scheme: scheme, + Host: host, + Path: path, + }, nil +} + +// URLHost builds the host part of the URL for a route. See Route.URL(). +// +// The route must have a host defined. +func (r *Route) URLHost(pairs ...string) (*url.URL, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil || r.regexp.host == nil { + return nil, errors.New("mux: route doesn't have a host") + } + values, err := r.prepareVars(pairs...) + if err != nil { + return nil, err + } + host, err := r.regexp.host.url(values) + if err != nil { + return nil, err + } + return &url.URL{ + Scheme: "http", + Host: host, + }, nil +} + +// URLPath builds the path part of the URL for a route. See Route.URL(). +// +// The route must have a path defined. +func (r *Route) URLPath(pairs ...string) (*url.URL, error) { + if r.err != nil { + return nil, r.err + } + if r.regexp == nil || r.regexp.path == nil { + return nil, errors.New("mux: route doesn't have a path") + } + values, err := r.prepareVars(pairs...) + if err != nil { + return nil, err + } + path, err := r.regexp.path.url(values) + if err != nil { + return nil, err + } + return &url.URL{ + Path: path, + }, nil +} + +// GetPathTemplate returns the template used to build the +// route match. +// This is useful for building simple REST API documentation and for instrumentation +// against third-party services. +// An error will be returned if the route does not define a path. +func (r *Route) GetPathTemplate() (string, error) { + if r.err != nil { + return "", r.err + } + if r.regexp == nil || r.regexp.path == nil { + return "", errors.New("mux: route doesn't have a path") + } + return r.regexp.path.template, nil +} + +// GetHostTemplate returns the template used to build the +// route match. +// This is useful for building simple REST API documentation and for instrumentation +// against third-party services. +// An error will be returned if the route does not define a host. +func (r *Route) GetHostTemplate() (string, error) { + if r.err != nil { + return "", r.err + } + if r.regexp == nil || r.regexp.host == nil { + return "", errors.New("mux: route doesn't have a host") + } + return r.regexp.host.template, nil +} + +// prepareVars converts the route variable pairs into a map. If the route has a +// BuildVarsFunc, it is invoked. +func (r *Route) prepareVars(pairs ...string) (map[string]string, error) { + m, err := mapFromPairsToString(pairs...) + if err != nil { + return nil, err + } + return r.buildVars(m), nil +} + +func (r *Route) buildVars(m map[string]string) map[string]string { + if r.parent != nil { + m = r.parent.buildVars(m) + } + if r.buildVarsFunc != nil { + m = r.buildVarsFunc(m) + } + return m +} + +// ---------------------------------------------------------------------------- +// parentRoute +// ---------------------------------------------------------------------------- + +// parentRoute allows routes to know about parent host and path definitions. +type parentRoute interface { + getNamedRoutes() map[string]*Route + getRegexpGroup() *routeRegexpGroup + buildVars(map[string]string) map[string]string +} + +// getNamedRoutes returns the map where named routes are registered. +func (r *Route) getNamedRoutes() map[string]*Route { + if r.parent == nil { + // During tests router is not always set. + r.parent = NewRouter() + } + return r.parent.getNamedRoutes() +} + +// getRegexpGroup returns regexp definitions from this route. +func (r *Route) getRegexpGroup() *routeRegexpGroup { + if r.regexp == nil { + if r.parent == nil { + // During tests router is not always set. + r.parent = NewRouter() + } + regexp := r.parent.getRegexpGroup() + if regexp == nil { + r.regexp = new(routeRegexpGroup) + } else { + // Copy. + r.regexp = &routeRegexpGroup{ + host: regexp.host, + path: regexp.path, + queries: regexp.queries, + } + } + } + return r.regexp +} diff --git a/vendor/github.com/gorilla/rpc/LICENSE b/vendor/github.com/gorilla/rpc/LICENSE new file mode 100644 index 000000000..0e5fb8728 --- /dev/null +++ b/vendor/github.com/gorilla/rpc/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/rpc/README.md b/vendor/github.com/gorilla/rpc/README.md new file mode 100644 index 000000000..75c26eaa8 --- /dev/null +++ b/vendor/github.com/gorilla/rpc/README.md @@ -0,0 +1,7 @@ +rpc +=== +[![Build Status](https://travis-ci.org/gorilla/rpc.png?branch=master)](https://travis-ci.org/gorilla/rpc) + +gorilla/rpc is a foundation for RPC over HTTP services, providing access to the exported methods of an object through HTTP requests. + +Read the full documentation here: http://www.gorillatoolkit.org/pkg/rpc diff --git a/vendor/github.com/gorilla/rpc/v2/LICENSE b/vendor/github.com/gorilla/rpc/v2/LICENSE new file mode 100644 index 000000000..0e5fb8728 --- /dev/null +++ b/vendor/github.com/gorilla/rpc/v2/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/rpc/v2/README.md b/vendor/github.com/gorilla/rpc/v2/README.md new file mode 100644 index 000000000..8f9af9a8d --- /dev/null +++ b/vendor/github.com/gorilla/rpc/v2/README.md @@ -0,0 +1,6 @@ +rpc +=== + +gorilla/rpc is a foundation for RPC over HTTP services, providing access to the exported methods of an object through HTTP requests. + +Read the full documentation here: http://www.gorillatoolkit.org/pkg/rpc diff --git a/vendor/github.com/gorilla/rpc/v2/compression_selector.go b/vendor/github.com/gorilla/rpc/v2/compression_selector.go new file mode 100644 index 000000000..bbf3fd1ef --- /dev/null +++ b/vendor/github.com/gorilla/rpc/v2/compression_selector.go @@ -0,0 +1,90 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rpc + +import ( + "compress/flate" + "compress/gzip" + "io" + "net/http" + "strings" + "unicode" +) + +// gzipWriter writes and closes the gzip writer. +type gzipWriter struct { + w *gzip.Writer +} + +func (gw *gzipWriter) Write(p []byte) (n int, err error) { + defer gw.w.Close() + return gw.w.Write(p) +} + +// gzipEncoder implements the gzip compressed http encoder. +type gzipEncoder struct { +} + +func (enc *gzipEncoder) Encode(w http.ResponseWriter) io.Writer { + w.Header().Set("Content-Encoding", "gzip") + return &gzipWriter{gzip.NewWriter(w)} +} + +// flateWriter writes and closes the flate writer. +type flateWriter struct { + w *flate.Writer +} + +func (fw *flateWriter) Write(p []byte) (n int, err error) { + defer fw.w.Close() + return fw.w.Write(p) +} + +// flateEncoder implements the flate compressed http encoder. +type flateEncoder struct { +} + +func (enc *flateEncoder) Encode(w http.ResponseWriter) io.Writer { + fw, err := flate.NewWriter(w, flate.DefaultCompression) + if err != nil { + return w + } + w.Header().Set("Content-Encoding", "deflate") + return &flateWriter{fw} +} + +// CompressionSelector generates the compressed http encoder. +type CompressionSelector struct { +} + +// acceptedEnc returns the first compression type in "Accept-Encoding" header +// field of the request. +func acceptedEnc(req *http.Request) string { + encHeader := req.Header.Get("Accept-Encoding") + if encHeader == "" { + return "" + } + encTypes := strings.FieldsFunc(encHeader, func(r rune) bool { + return unicode.IsSpace(r) || r == ',' + }) + for _, enc := range encTypes { + if enc == "gzip" || enc == "deflate" { + return enc + } + } + return "" +} + +// Select method selects the correct compression encoder based on http HEADER. +func (_ *CompressionSelector) Select(r *http.Request) Encoder { + switch acceptedEnc(r) { + case "gzip": + return &gzipEncoder{} + case "flate": + return &flateEncoder{} + } + return DefaultEncoder +} diff --git a/vendor/github.com/gorilla/rpc/v2/doc.go b/vendor/github.com/gorilla/rpc/v2/doc.go new file mode 100644 index 000000000..301d5dc06 --- /dev/null +++ b/vendor/github.com/gorilla/rpc/v2/doc.go @@ -0,0 +1,81 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package gorilla/rpc is a foundation for RPC over HTTP services, providing +access to the exported methods of an object through HTTP requests. + +This package derives from the standard net/rpc package but uses a single HTTP +request per call instead of persistent connections. Other differences +compared to net/rpc: + + - Multiple codecs can be registered in the same server. + - A codec is chosen based on the "Content-Type" header from the request. + - Service methods also receive http.Request as parameter. + - This package can be used on Google App Engine. + +Let's setup a server and register a codec and service: + + import ( + "http" + "github.com/gorilla/rpc/v2" + "github.com/gorilla/rpc/v2/json" + ) + + func init() { + s := rpc.NewServer() + s.RegisterCodec(json.NewCodec(), "application/json") + s.RegisterService(new(HelloService), "") + http.Handle("/rpc", s) + } + +This server handles requests to the "/rpc" path using a JSON codec. +A codec is tied to a content type. In the example above, the JSON codec is +registered to serve requests with "application/json" as the value for the +"Content-Type" header. If the header includes a charset definition, it is +ignored; only the media-type part is taken into account. + +A service can be registered using a name. If the name is empty, like in the +example above, it will be inferred from the service type. + +That's all about the server setup. Now let's define a simple service: + + type HelloArgs struct { + Who string + } + + type HelloReply struct { + Message string + } + + type HelloService struct {} + + func (h *HelloService) Say(r *http.Request, args *HelloArgs, reply *HelloReply) error { + reply.Message = "Hello, " + args.Who + "!" + return nil + } + +The example above defines a service with a method "HelloService.Say" and +the arguments and reply related to that method. + +The service must be exported (begin with an upper case letter) or local +(defined in the package registering the service). + +When a service is registered, the server inspects the service methods +and make available the ones that follow these rules: + + - The method name is exported. + - The method has three arguments: *http.Request, *args, *reply. + - All three arguments are pointers. + - The second and third arguments are exported or local. + - The method has return type error. + +All other methods are ignored. + +Gorilla has packages with common RPC codecs. Check out their documentation: + + JSON: http://gorilla-web.appspot.com/pkg/rpc/json +*/ +package rpc diff --git a/vendor/github.com/gorilla/rpc/v2/encoder_selector.go b/vendor/github.com/gorilla/rpc/v2/encoder_selector.go new file mode 100644 index 000000000..333361f3a --- /dev/null +++ b/vendor/github.com/gorilla/rpc/v2/encoder_selector.go @@ -0,0 +1,43 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rpc + +import ( + "io" + "net/http" +) + +// Encoder interface contains the encoder for http response. +// Eg. gzip, flate compressions. +type Encoder interface { + Encode(w http.ResponseWriter) io.Writer +} + +type encoder struct { +} + +func (_ *encoder) Encode(w http.ResponseWriter) io.Writer { + return w +} + +var DefaultEncoder = &encoder{} + +// EncoderSelector interface provides a way to select encoder using the http +// request. Typically people can use this to check HEADER of the request and +// figure out client capabilities. +// Eg. "Accept-Encoding" tells about supported compressions. +type EncoderSelector interface { + Select(r *http.Request) Encoder +} + +type encoderSelector struct { +} + +func (_ *encoderSelector) Select(_ *http.Request) Encoder { + return DefaultEncoder +} + +var DefaultEncoderSelector = &encoderSelector{} diff --git a/vendor/github.com/gorilla/rpc/v2/json2/client.go b/vendor/github.com/gorilla/rpc/v2/json2/client.go new file mode 100644 index 000000000..8f4c1f5ee --- /dev/null +++ b/vendor/github.com/gorilla/rpc/v2/json2/client.go @@ -0,0 +1,75 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json2 + +import ( + "encoding/json" + "io" + "math/rand" +) + +// ---------------------------------------------------------------------------- +// Request and Response +// ---------------------------------------------------------------------------- + +// clientRequest represents a JSON-RPC request sent by a client. +type clientRequest struct { + // JSON-RPC protocol. + Version string `json:"jsonrpc"` + + // A String containing the name of the method to be invoked. + Method string `json:"method"` + + // Object to pass as request parameter to the method. + Params interface{} `json:"params"` + + // The request id. This can be of any type. It is used to match the + // response with the request that it is replying to. + Id uint64 `json:"id"` +} + +// clientResponse represents a JSON-RPC response returned to a client. +type clientResponse struct { + Version string `json:"jsonrpc"` + Result *json.RawMessage `json:"result"` + Error *json.RawMessage `json:"error"` +} + +// EncodeClientRequest encodes parameters for a JSON-RPC client request. +func EncodeClientRequest(method string, args interface{}) ([]byte, error) { + c := &clientRequest{ + Version: "2.0", + Method: method, + Params: args, + Id: uint64(rand.Int63()), + } + return json.Marshal(c) +} + +// DecodeClientResponse decodes the response body of a client request into +// the interface reply. +func DecodeClientResponse(r io.Reader, reply interface{}) error { + var c clientResponse + if err := json.NewDecoder(r).Decode(&c); err != nil { + return err + } + if c.Error != nil { + jsonErr := &Error{} + if err := json.Unmarshal(*c.Error, jsonErr); err != nil { + return &Error{ + Code: E_SERVER, + Message: string(*c.Error), + } + } + return jsonErr + } + + if c.Result == nil { + return ErrNullResult + } + + return json.Unmarshal(*c.Result, reply) +} diff --git a/vendor/github.com/gorilla/rpc/v2/json2/error.go b/vendor/github.com/gorilla/rpc/v2/json2/error.go new file mode 100644 index 000000000..9d2cbd9ee --- /dev/null +++ b/vendor/github.com/gorilla/rpc/v2/json2/error.go @@ -0,0 +1,39 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json2 + +import ( + "errors" +) + +type ErrorCode int + +const ( + E_PARSE ErrorCode = -32700 + E_INVALID_REQ ErrorCode = -32600 + E_NO_METHOD ErrorCode = -32601 + E_BAD_PARAMS ErrorCode = -32602 + E_INTERNAL ErrorCode = -32603 + E_SERVER ErrorCode = -32000 +) + +var ErrNullResult = errors.New("result is null") + +type Error struct { + // A Number that indicates the error type that occurred. + Code ErrorCode `json:"code"` /* required */ + + // A String providing a short description of the error. + // The message SHOULD be limited to a concise single sentence. + Message string `json:"message"` /* required */ + + // A Primitive or Structured value that contains additional information about the error. + Data interface{} `json:"data"` /* optional */ +} + +func (e *Error) Error() string { + return e.Message +} diff --git a/vendor/github.com/gorilla/rpc/v2/json2/server.go b/vendor/github.com/gorilla/rpc/v2/json2/server.go new file mode 100644 index 000000000..158e996e8 --- /dev/null +++ b/vendor/github.com/gorilla/rpc/v2/json2/server.go @@ -0,0 +1,202 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json2 + +import ( + "encoding/json" + "net/http" + + "github.com/gorilla/rpc/v2" +) + +var null = json.RawMessage([]byte("null")) +var Version = "2.0" + +// ---------------------------------------------------------------------------- +// Request and Response +// ---------------------------------------------------------------------------- + +// serverRequest represents a JSON-RPC request received by the server. +type serverRequest struct { + // JSON-RPC protocol. + Version string `json:"jsonrpc"` + + // A String containing the name of the method to be invoked. + Method string `json:"method"` + + // A Structured value to pass as arguments to the method. + Params *json.RawMessage `json:"params"` + + // The request id. MUST be a string, number or null. + // Our implementation will not do type checking for id. + // It will be copied as it is. + Id *json.RawMessage `json:"id"` +} + +// serverResponse represents a JSON-RPC response returned by the server. +type serverResponse struct { + // JSON-RPC protocol. + Version string `json:"jsonrpc"` + + // The Object that was returned by the invoked method. This must be null + // in case there was an error invoking the method. + // As per spec the member will be omitted if there was an error. + Result interface{} `json:"result,omitempty"` + + // An Error object if there was an error invoking the method. It must be + // null if there was no error. + // As per spec the member will be omitted if there was no error. + Error *Error `json:"error,omitempty"` + + // This must be the same id as the request it is responding to. + Id *json.RawMessage `json:"id"` +} + +// ---------------------------------------------------------------------------- +// Codec +// ---------------------------------------------------------------------------- + +// NewcustomCodec returns a new JSON Codec based on passed encoder selector. +func NewCustomCodec(encSel rpc.EncoderSelector) *Codec { + return &Codec{encSel: encSel} +} + +// NewCodec returns a new JSON Codec. +func NewCodec() *Codec { + return NewCustomCodec(rpc.DefaultEncoderSelector) +} + +// Codec creates a CodecRequest to process each request. +type Codec struct { + encSel rpc.EncoderSelector +} + +// NewRequest returns a CodecRequest. +func (c *Codec) NewRequest(r *http.Request) rpc.CodecRequest { + return newCodecRequest(r, c.encSel.Select(r)) +} + +// ---------------------------------------------------------------------------- +// CodecRequest +// ---------------------------------------------------------------------------- + +// newCodecRequest returns a new CodecRequest. +func newCodecRequest(r *http.Request, encoder rpc.Encoder) rpc.CodecRequest { + // Decode the request body and check if RPC method is valid. + req := new(serverRequest) + err := json.NewDecoder(r.Body).Decode(req) + if err != nil { + err = &Error{ + Code: E_PARSE, + Message: err.Error(), + Data: req, + } + } + if req.Version != Version { + err = &Error{ + Code: E_INVALID_REQ, + Message: "jsonrpc must be " + Version, + Data: req, + } + } + r.Body.Close() + return &CodecRequest{request: req, err: err, encoder: encoder} +} + +// CodecRequest decodes and encodes a single request. +type CodecRequest struct { + request *serverRequest + err error + encoder rpc.Encoder +} + +// Method returns the RPC method for the current request. +// +// The method uses a dotted notation as in "Service.Method". +func (c *CodecRequest) Method() (string, error) { + if c.err == nil { + return c.request.Method, nil + } + return "", c.err +} + +// ReadRequest fills the request object for the RPC method. +// +// ReadRequest parses request parameters in two supported forms in +// accordance with http://www.jsonrpc.org/specification#parameter_structures +// +// by-position: params MUST be an Array, containing the +// values in the Server expected order. +// +// by-name: params MUST be an Object, with member names +// that match the Server expected parameter names. The +// absence of expected names MAY result in an error being +// generated. The names MUST match exactly, including +// case, to the method's expected parameters. +func (c *CodecRequest) ReadRequest(args interface{}) error { + if c.err == nil && c.request.Params != nil { + // Note: if c.request.Params is nil it's not an error, it's an optional member. + // JSON params structured object. Unmarshal to the args object. + if err := json.Unmarshal(*c.request.Params, args); err != nil { + // Clearly JSON params is not a structured object, + // fallback and attempt an unmarshal with JSON params as + // array value and RPC params is struct. Unmarshal into + // array containing the request struct. + params := [1]interface{}{args} + if err = json.Unmarshal(*c.request.Params, ¶ms); err != nil { + c.err = &Error{ + Code: E_INVALID_REQ, + Message: err.Error(), + Data: c.request.Params, + } + } + } + } + return c.err +} + +// WriteResponse encodes the response and writes it to the ResponseWriter. +func (c *CodecRequest) WriteResponse(w http.ResponseWriter, reply interface{}) { + res := &serverResponse{ + Version: Version, + Result: reply, + Id: c.request.Id, + } + c.writeServerResponse(w, res) +} + +func (c *CodecRequest) WriteError(w http.ResponseWriter, status int, err error) { + jsonErr, ok := err.(*Error) + if !ok { + jsonErr = &Error{ + Code: E_SERVER, + Message: err.Error(), + } + } + res := &serverResponse{ + Version: Version, + Error: jsonErr, + Id: c.request.Id, + } + c.writeServerResponse(w, res) +} + +func (c *CodecRequest) writeServerResponse(w http.ResponseWriter, res *serverResponse) { + // Id is null for notifications and they don't have a response. + if c.request.Id != nil { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + encoder := json.NewEncoder(c.encoder.Encode(w)) + err := encoder.Encode(res) + + // Not sure in which case will this happen. But seems harmless. + if err != nil { + rpc.WriteError(w, 400, err.Error()) + } + } +} + +type EmptyResponse struct { +} diff --git a/vendor/github.com/gorilla/rpc/v2/map.go b/vendor/github.com/gorilla/rpc/v2/map.go new file mode 100644 index 000000000..dda42161c --- /dev/null +++ b/vendor/github.com/gorilla/rpc/v2/map.go @@ -0,0 +1,164 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rpc + +import ( + "fmt" + "net/http" + "reflect" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +var ( + // Precompute the reflect.Type of error and http.Request + typeOfError = reflect.TypeOf((*error)(nil)).Elem() + typeOfRequest = reflect.TypeOf((*http.Request)(nil)).Elem() +) + +// ---------------------------------------------------------------------------- +// service +// ---------------------------------------------------------------------------- + +type service struct { + name string // name of service + rcvr reflect.Value // receiver of methods for the service + rcvrType reflect.Type // type of the receiver + methods map[string]*serviceMethod // registered methods +} + +type serviceMethod struct { + method reflect.Method // receiver method + argsType reflect.Type // type of the request argument + replyType reflect.Type // type of the response argument +} + +// ---------------------------------------------------------------------------- +// serviceMap +// ---------------------------------------------------------------------------- + +// serviceMap is a registry for services. +type serviceMap struct { + mutex sync.Mutex + services map[string]*service +} + +// register adds a new service using reflection to extract its methods. +func (m *serviceMap) register(rcvr interface{}, name string) error { + // Setup service. + s := &service{ + name: name, + rcvr: reflect.ValueOf(rcvr), + rcvrType: reflect.TypeOf(rcvr), + methods: make(map[string]*serviceMethod), + } + if name == "" { + s.name = reflect.Indirect(s.rcvr).Type().Name() + if !isExported(s.name) { + return fmt.Errorf("rpc: type %q is not exported", s.name) + } + } + if s.name == "" { + return fmt.Errorf("rpc: no service name for type %q", + s.rcvrType.String()) + } + // Setup methods. + for i := 0; i < s.rcvrType.NumMethod(); i++ { + method := s.rcvrType.Method(i) + mtype := method.Type + // Method must be exported. + if method.PkgPath != "" { + continue + } + // Method needs four ins: receiver, *http.Request, *args, *reply. + if mtype.NumIn() != 4 { + continue + } + // First argument must be a pointer and must be http.Request. + reqType := mtype.In(1) + if reqType.Kind() != reflect.Ptr || reqType.Elem() != typeOfRequest { + continue + } + // Second argument must be a pointer and must be exported. + args := mtype.In(2) + if args.Kind() != reflect.Ptr || !isExportedOrBuiltin(args) { + continue + } + // Third argument must be a pointer and must be exported. + reply := mtype.In(3) + if reply.Kind() != reflect.Ptr || !isExportedOrBuiltin(reply) { + continue + } + // Method needs one out: error. + if mtype.NumOut() != 1 { + continue + } + if returnType := mtype.Out(0); returnType != typeOfError { + continue + } + s.methods[method.Name] = &serviceMethod{ + method: method, + argsType: args.Elem(), + replyType: reply.Elem(), + } + } + if len(s.methods) == 0 { + return fmt.Errorf("rpc: %q has no exported methods of suitable type", + s.name) + } + // Add to the map. + m.mutex.Lock() + defer m.mutex.Unlock() + if m.services == nil { + m.services = make(map[string]*service) + } else if _, ok := m.services[s.name]; ok { + return fmt.Errorf("rpc: service already defined: %q", s.name) + } + m.services[s.name] = s + return nil +} + +// get returns a registered service given a method name. +// +// The method name uses a dotted notation as in "Service.Method". +func (m *serviceMap) get(method string) (*service, *serviceMethod, error) { + parts := strings.Split(method, ".") + if len(parts) != 2 { + err := fmt.Errorf("rpc: service/method request ill-formed: %q", method) + return nil, nil, err + } + m.mutex.Lock() + service := m.services[parts[0]] + m.mutex.Unlock() + if service == nil { + err := fmt.Errorf("rpc: can't find service %q", method) + return nil, nil, err + } + serviceMethod := service.methods[parts[1]] + if serviceMethod == nil { + err := fmt.Errorf("rpc: can't find method %q", method) + return nil, nil, err + } + return service, serviceMethod, nil +} + +// isExported returns true of a string is an exported (upper case) name. +func isExported(name string) bool { + rune, _ := utf8.DecodeRuneInString(name) + return unicode.IsUpper(rune) +} + +// isExportedOrBuiltin returns true if a type is exported or a builtin. +func isExportedOrBuiltin(t reflect.Type) bool { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + // PkgPath will be non-empty even for an exported type, + // so we need to check the type name as well. + return isExported(t.Name()) || t.PkgPath() == "" +} diff --git a/vendor/github.com/gorilla/rpc/v2/server.go b/vendor/github.com/gorilla/rpc/v2/server.go new file mode 100644 index 000000000..bd0a42db4 --- /dev/null +++ b/vendor/github.com/gorilla/rpc/v2/server.go @@ -0,0 +1,164 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rpc + +import ( + "fmt" + "net/http" + "reflect" + "strings" +) + +// ---------------------------------------------------------------------------- +// Codec +// ---------------------------------------------------------------------------- + +// Codec creates a CodecRequest to process each request. +type Codec interface { + NewRequest(*http.Request) CodecRequest +} + +// CodecRequest decodes a request and encodes a response using a specific +// serialization scheme. +type CodecRequest interface { + // Reads the request and returns the RPC method name. + Method() (string, error) + // Reads the request filling the RPC method args. + ReadRequest(interface{}) error + // Writes the response using the RPC method reply. + WriteResponse(http.ResponseWriter, interface{}) + // Writes an error produced by the server. + WriteError(w http.ResponseWriter, status int, err error) +} + +// ---------------------------------------------------------------------------- +// Server +// ---------------------------------------------------------------------------- + +// NewServer returns a new RPC server. +func NewServer() *Server { + return &Server{ + codecs: make(map[string]Codec), + services: new(serviceMap), + } +} + +// Server serves registered RPC services using registered codecs. +type Server struct { + codecs map[string]Codec + services *serviceMap +} + +// RegisterCodec adds a new codec to the server. +// +// Codecs are defined to process a given serialization scheme, e.g., JSON or +// XML. A codec is chosen based on the "Content-Type" header from the request, +// excluding the charset definition. +func (s *Server) RegisterCodec(codec Codec, contentType string) { + s.codecs[strings.ToLower(contentType)] = codec +} + +// RegisterService adds a new service to the server. +// +// The name parameter is optional: if empty it will be inferred from +// the receiver type name. +// +// Methods from the receiver will be extracted if these rules are satisfied: +// +// - The receiver is exported (begins with an upper case letter) or local +// (defined in the package registering the service). +// - The method name is exported. +// - The method has three arguments: *http.Request, *args, *reply. +// - All three arguments are pointers. +// - The second and third arguments are exported or local. +// - The method has return type error. +// +// All other methods are ignored. +func (s *Server) RegisterService(receiver interface{}, name string) error { + return s.services.register(receiver, name) +} + +// HasMethod returns true if the given method is registered. +// +// The method uses a dotted notation as in "Service.Method". +func (s *Server) HasMethod(method string) bool { + if _, _, err := s.services.get(method); err == nil { + return true + } + return false +} + +// ServeHTTP +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + WriteError(w, 405, "rpc: POST method required, received "+r.Method) + return + } + contentType := r.Header.Get("Content-Type") + idx := strings.Index(contentType, ";") + if idx != -1 { + contentType = contentType[:idx] + } + var codec Codec + if contentType == "" && len(s.codecs) == 1 { + // If Content-Type is not set and only one codec has been registered, + // then default to that codec. + for _, c := range s.codecs { + codec = c + } + } else if codec = s.codecs[strings.ToLower(contentType)]; codec == nil { + WriteError(w, 415, "rpc: unrecognized Content-Type: "+contentType) + return + } + // Create a new codec request. + codecReq := codec.NewRequest(r) + // Get service method to be called. + method, errMethod := codecReq.Method() + if errMethod != nil { + codecReq.WriteError(w, 400, errMethod) + return + } + serviceSpec, methodSpec, errGet := s.services.get(method) + if errGet != nil { + codecReq.WriteError(w, 400, errGet) + return + } + // Decode the args. + args := reflect.New(methodSpec.argsType) + if errRead := codecReq.ReadRequest(args.Interface()); errRead != nil { + codecReq.WriteError(w, 400, errRead) + return + } + // Call the service method. + reply := reflect.New(methodSpec.replyType) + errValue := methodSpec.method.Func.Call([]reflect.Value{ + serviceSpec.rcvr, + reflect.ValueOf(r), + args, + reply, + }) + // Cast the result to error if needed. + var errResult error + errInter := errValue[0].Interface() + if errInter != nil { + errResult = errInter.(error) + } + // Prevents Internet Explorer from MIME-sniffing a response away + // from the declared content-type + w.Header().Set("x-content-type-options", "nosniff") + // Encode the response. + if errResult == nil { + codecReq.WriteResponse(w, reply.Interface()) + } else { + codecReq.WriteError(w, 400, errResult) + } +} + +func WriteError(w http.ResponseWriter, status int, msg string) { + w.WriteHeader(status) + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + fmt.Fprint(w, msg) +} diff --git a/vendor/github.com/inconshreveable/mousetrap/LICENSE b/vendor/github.com/inconshreveable/mousetrap/LICENSE new file mode 100644 index 000000000..5f0d1fb6a --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/LICENSE @@ -0,0 +1,13 @@ +Copyright 2014 Alan Shreve + +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. diff --git a/vendor/github.com/inconshreveable/mousetrap/README.md b/vendor/github.com/inconshreveable/mousetrap/README.md new file mode 100644 index 000000000..7a950d177 --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/README.md @@ -0,0 +1,23 @@ +# mousetrap + +mousetrap is a tiny library that answers a single question. + +On a Windows machine, was the process invoked by someone double clicking on +the executable file while browsing in explorer? + +### Motivation + +Windows developers unfamiliar with command line tools will often "double-click" +the executable for a tool. Because most CLI tools print the help and then exit +when invoked without arguments, this is often very frustrating for those users. + +mousetrap provides a way to detect these invocations so that you can provide +more helpful behavior and instructions on how to run the CLI tool. To see what +this looks like, both from an organizational and a technical perspective, see +https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/ + +### The interface + +The library exposes a single interface: + + func StartedByExplorer() (bool) diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_others.go b/vendor/github.com/inconshreveable/mousetrap/trap_others.go new file mode 100644 index 000000000..9d2d8a4ba --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_others.go @@ -0,0 +1,15 @@ +// +build !windows + +package mousetrap + +// StartedByExplorer returns true if the program was invoked by the user +// double-clicking on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +// +// On non-Windows platforms, it always returns false. +func StartedByExplorer() bool { + return false +} diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go new file mode 100644 index 000000000..336142a5e --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go @@ -0,0 +1,98 @@ +// +build windows +// +build !go1.4 + +package mousetrap + +import ( + "fmt" + "os" + "syscall" + "unsafe" +) + +const ( + // defined by the Win32 API + th32cs_snapprocess uintptr = 0x2 +) + +var ( + kernel = syscall.MustLoadDLL("kernel32.dll") + CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") + Process32First = kernel.MustFindProc("Process32FirstW") + Process32Next = kernel.MustFindProc("Process32NextW") +) + +// ProcessEntry32 structure defined by the Win32 API +type processEntry32 struct { + dwSize uint32 + cntUsage uint32 + th32ProcessID uint32 + th32DefaultHeapID int + th32ModuleID uint32 + cntThreads uint32 + th32ParentProcessID uint32 + pcPriClassBase int32 + dwFlags uint32 + szExeFile [syscall.MAX_PATH]uint16 +} + +func getProcessEntry(pid int) (pe *processEntry32, err error) { + snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) + if snapshot == uintptr(syscall.InvalidHandle) { + err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) + return + } + defer syscall.CloseHandle(syscall.Handle(snapshot)) + + var processEntry processEntry32 + processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) + ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) + if ok == 0 { + err = fmt.Errorf("Process32First: %v", e1) + return + } + + for { + if processEntry.th32ProcessID == uint32(pid) { + pe = &processEntry + return + } + + ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) + if ok == 0 { + err = fmt.Errorf("Process32Next: %v", e1) + return + } + } +} + +func getppid() (pid int, err error) { + pe, err := getProcessEntry(os.Getpid()) + if err != nil { + return + } + + pid = int(pe.th32ParentProcessID) + return +} + +// StartedByExplorer returns true if the program was invoked by the user double-clicking +// on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +func StartedByExplorer() bool { + ppid, err := getppid() + if err != nil { + return false + } + + pe, err := getProcessEntry(ppid) + if err != nil { + return false + } + + name := syscall.UTF16ToString(pe.szExeFile[:]) + return name == "explorer.exe" +} diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go new file mode 100644 index 000000000..9a28e57c3 --- /dev/null +++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go @@ -0,0 +1,46 @@ +// +build windows +// +build go1.4 + +package mousetrap + +import ( + "os" + "syscall" + "unsafe" +) + +func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { + snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) + if err != nil { + return nil, err + } + defer syscall.CloseHandle(snapshot) + var procEntry syscall.ProcessEntry32 + procEntry.Size = uint32(unsafe.Sizeof(procEntry)) + if err = syscall.Process32First(snapshot, &procEntry); err != nil { + return nil, err + } + for { + if procEntry.ProcessID == uint32(pid) { + return &procEntry, nil + } + err = syscall.Process32Next(snapshot, &procEntry) + if err != nil { + return nil, err + } + } +} + +// StartedByExplorer returns true if the program was invoked by the user double-clicking +// on the executable from explorer.exe +// +// It is conservative and returns false if any of the internal calls fail. +// It does not guarantee that the program was run from a terminal. It only can tell you +// whether it was launched from explorer.exe +func StartedByExplorer() bool { + pe, err := getProcessEntry(os.Getppid()) + if err != nil { + return false + } + return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) +} diff --git a/vendor/github.com/jmespath/go-jmespath/LICENSE b/vendor/github.com/jmespath/go-jmespath/LICENSE new file mode 100644 index 000000000..b03310a91 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/LICENSE @@ -0,0 +1,13 @@ +Copyright 2015 James Saryerwinnie + +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. diff --git a/vendor/github.com/jmespath/go-jmespath/README.md b/vendor/github.com/jmespath/go-jmespath/README.md new file mode 100644 index 000000000..187ef676d --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/README.md @@ -0,0 +1,7 @@ +# go-jmespath - A JMESPath implementation in Go + +[![Build Status](https://img.shields.io/travis/jmespath/go-jmespath.svg)](https://travis-ci.org/jmespath/go-jmespath) + + + +See http://jmespath.org for more info. diff --git a/vendor/github.com/jmespath/go-jmespath/api.go b/vendor/github.com/jmespath/go-jmespath/api.go new file mode 100644 index 000000000..9cfa988bc --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/api.go @@ -0,0 +1,49 @@ +package jmespath + +import "strconv" + +// JmesPath is the epresentation of a compiled JMES path query. A JmesPath is +// safe for concurrent use by multiple goroutines. +type JMESPath struct { + ast ASTNode + intr *treeInterpreter +} + +// Compile parses a JMESPath expression and returns, if successful, a JMESPath +// object that can be used to match against data. +func Compile(expression string) (*JMESPath, error) { + parser := NewParser() + ast, err := parser.Parse(expression) + if err != nil { + return nil, err + } + jmespath := &JMESPath{ast: ast, intr: newInterpreter()} + return jmespath, nil +} + +// MustCompile is like Compile but panics if the expression cannot be parsed. +// It simplifies safe initialization of global variables holding compiled +// JMESPaths. +func MustCompile(expression string) *JMESPath { + jmespath, err := Compile(expression) + if err != nil { + panic(`jmespath: Compile(` + strconv.Quote(expression) + `): ` + err.Error()) + } + return jmespath +} + +// Search evaluates a JMESPath expression against input data and returns the result. +func (jp *JMESPath) Search(data interface{}) (interface{}, error) { + return jp.intr.Execute(jp.ast, data) +} + +// Search evaluates a JMESPath expression against input data and returns the result. +func Search(expression string, data interface{}) (interface{}, error) { + intr := newInterpreter() + parser := NewParser() + ast, err := parser.Parse(expression) + if err != nil { + return nil, err + } + return intr.Execute(ast, data) +} diff --git a/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go b/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go new file mode 100644 index 000000000..1cd2d239c --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go @@ -0,0 +1,16 @@ +// generated by stringer -type astNodeType; DO NOT EDIT + +package jmespath + +import "fmt" + +const _astNodeType_name = "ASTEmptyASTComparatorASTCurrentNodeASTExpRefASTFunctionExpressionASTFieldASTFilterProjectionASTFlattenASTIdentityASTIndexASTIndexExpressionASTKeyValPairASTLiteralASTMultiSelectHashASTMultiSelectListASTOrExpressionASTAndExpressionASTNotExpressionASTPipeASTProjectionASTSubexpressionASTSliceASTValueProjection" + +var _astNodeType_index = [...]uint16{0, 8, 21, 35, 44, 65, 73, 92, 102, 113, 121, 139, 152, 162, 180, 198, 213, 229, 245, 252, 265, 281, 289, 307} + +func (i astNodeType) String() string { + if i < 0 || i >= astNodeType(len(_astNodeType_index)-1) { + return fmt.Sprintf("astNodeType(%d)", i) + } + return _astNodeType_name[_astNodeType_index[i]:_astNodeType_index[i+1]] +} diff --git a/vendor/github.com/jmespath/go-jmespath/functions.go b/vendor/github.com/jmespath/go-jmespath/functions.go new file mode 100644 index 000000000..9b7cd89b4 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/functions.go @@ -0,0 +1,842 @@ +package jmespath + +import ( + "encoding/json" + "errors" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "unicode/utf8" +) + +type jpFunction func(arguments []interface{}) (interface{}, error) + +type jpType string + +const ( + jpUnknown jpType = "unknown" + jpNumber jpType = "number" + jpString jpType = "string" + jpArray jpType = "array" + jpObject jpType = "object" + jpArrayNumber jpType = "array[number]" + jpArrayString jpType = "array[string]" + jpExpref jpType = "expref" + jpAny jpType = "any" +) + +type functionEntry struct { + name string + arguments []argSpec + handler jpFunction + hasExpRef bool +} + +type argSpec struct { + types []jpType + variadic bool +} + +type byExprString struct { + intr *treeInterpreter + node ASTNode + items []interface{} + hasError bool +} + +func (a *byExprString) Len() int { + return len(a.items) +} +func (a *byExprString) Swap(i, j int) { + a.items[i], a.items[j] = a.items[j], a.items[i] +} +func (a *byExprString) Less(i, j int) bool { + first, err := a.intr.Execute(a.node, a.items[i]) + if err != nil { + a.hasError = true + // Return a dummy value. + return true + } + ith, ok := first.(string) + if !ok { + a.hasError = true + return true + } + second, err := a.intr.Execute(a.node, a.items[j]) + if err != nil { + a.hasError = true + // Return a dummy value. + return true + } + jth, ok := second.(string) + if !ok { + a.hasError = true + return true + } + return ith < jth +} + +type byExprFloat struct { + intr *treeInterpreter + node ASTNode + items []interface{} + hasError bool +} + +func (a *byExprFloat) Len() int { + return len(a.items) +} +func (a *byExprFloat) Swap(i, j int) { + a.items[i], a.items[j] = a.items[j], a.items[i] +} +func (a *byExprFloat) Less(i, j int) bool { + first, err := a.intr.Execute(a.node, a.items[i]) + if err != nil { + a.hasError = true + // Return a dummy value. + return true + } + ith, ok := first.(float64) + if !ok { + a.hasError = true + return true + } + second, err := a.intr.Execute(a.node, a.items[j]) + if err != nil { + a.hasError = true + // Return a dummy value. + return true + } + jth, ok := second.(float64) + if !ok { + a.hasError = true + return true + } + return ith < jth +} + +type functionCaller struct { + functionTable map[string]functionEntry +} + +func newFunctionCaller() *functionCaller { + caller := &functionCaller{} + caller.functionTable = map[string]functionEntry{ + "length": { + name: "length", + arguments: []argSpec{ + {types: []jpType{jpString, jpArray, jpObject}}, + }, + handler: jpfLength, + }, + "starts_with": { + name: "starts_with", + arguments: []argSpec{ + {types: []jpType{jpString}}, + {types: []jpType{jpString}}, + }, + handler: jpfStartsWith, + }, + "abs": { + name: "abs", + arguments: []argSpec{ + {types: []jpType{jpNumber}}, + }, + handler: jpfAbs, + }, + "avg": { + name: "avg", + arguments: []argSpec{ + {types: []jpType{jpArrayNumber}}, + }, + handler: jpfAvg, + }, + "ceil": { + name: "ceil", + arguments: []argSpec{ + {types: []jpType{jpNumber}}, + }, + handler: jpfCeil, + }, + "contains": { + name: "contains", + arguments: []argSpec{ + {types: []jpType{jpArray, jpString}}, + {types: []jpType{jpAny}}, + }, + handler: jpfContains, + }, + "ends_with": { + name: "ends_with", + arguments: []argSpec{ + {types: []jpType{jpString}}, + {types: []jpType{jpString}}, + }, + handler: jpfEndsWith, + }, + "floor": { + name: "floor", + arguments: []argSpec{ + {types: []jpType{jpNumber}}, + }, + handler: jpfFloor, + }, + "map": { + name: "amp", + arguments: []argSpec{ + {types: []jpType{jpExpref}}, + {types: []jpType{jpArray}}, + }, + handler: jpfMap, + hasExpRef: true, + }, + "max": { + name: "max", + arguments: []argSpec{ + {types: []jpType{jpArrayNumber, jpArrayString}}, + }, + handler: jpfMax, + }, + "merge": { + name: "merge", + arguments: []argSpec{ + {types: []jpType{jpObject}, variadic: true}, + }, + handler: jpfMerge, + }, + "max_by": { + name: "max_by", + arguments: []argSpec{ + {types: []jpType{jpArray}}, + {types: []jpType{jpExpref}}, + }, + handler: jpfMaxBy, + hasExpRef: true, + }, + "sum": { + name: "sum", + arguments: []argSpec{ + {types: []jpType{jpArrayNumber}}, + }, + handler: jpfSum, + }, + "min": { + name: "min", + arguments: []argSpec{ + {types: []jpType{jpArrayNumber, jpArrayString}}, + }, + handler: jpfMin, + }, + "min_by": { + name: "min_by", + arguments: []argSpec{ + {types: []jpType{jpArray}}, + {types: []jpType{jpExpref}}, + }, + handler: jpfMinBy, + hasExpRef: true, + }, + "type": { + name: "type", + arguments: []argSpec{ + {types: []jpType{jpAny}}, + }, + handler: jpfType, + }, + "keys": { + name: "keys", + arguments: []argSpec{ + {types: []jpType{jpObject}}, + }, + handler: jpfKeys, + }, + "values": { + name: "values", + arguments: []argSpec{ + {types: []jpType{jpObject}}, + }, + handler: jpfValues, + }, + "sort": { + name: "sort", + arguments: []argSpec{ + {types: []jpType{jpArrayString, jpArrayNumber}}, + }, + handler: jpfSort, + }, + "sort_by": { + name: "sort_by", + arguments: []argSpec{ + {types: []jpType{jpArray}}, + {types: []jpType{jpExpref}}, + }, + handler: jpfSortBy, + hasExpRef: true, + }, + "join": { + name: "join", + arguments: []argSpec{ + {types: []jpType{jpString}}, + {types: []jpType{jpArrayString}}, + }, + handler: jpfJoin, + }, + "reverse": { + name: "reverse", + arguments: []argSpec{ + {types: []jpType{jpArray, jpString}}, + }, + handler: jpfReverse, + }, + "to_array": { + name: "to_array", + arguments: []argSpec{ + {types: []jpType{jpAny}}, + }, + handler: jpfToArray, + }, + "to_string": { + name: "to_string", + arguments: []argSpec{ + {types: []jpType{jpAny}}, + }, + handler: jpfToString, + }, + "to_number": { + name: "to_number", + arguments: []argSpec{ + {types: []jpType{jpAny}}, + }, + handler: jpfToNumber, + }, + "not_null": { + name: "not_null", + arguments: []argSpec{ + {types: []jpType{jpAny}, variadic: true}, + }, + handler: jpfNotNull, + }, + } + return caller +} + +func (e *functionEntry) resolveArgs(arguments []interface{}) ([]interface{}, error) { + if len(e.arguments) == 0 { + return arguments, nil + } + if !e.arguments[len(e.arguments)-1].variadic { + if len(e.arguments) != len(arguments) { + return nil, errors.New("incorrect number of args") + } + for i, spec := range e.arguments { + userArg := arguments[i] + err := spec.typeCheck(userArg) + if err != nil { + return nil, err + } + } + return arguments, nil + } + if len(arguments) < len(e.arguments) { + return nil, errors.New("Invalid arity.") + } + return arguments, nil +} + +func (a *argSpec) typeCheck(arg interface{}) error { + for _, t := range a.types { + switch t { + case jpNumber: + if _, ok := arg.(float64); ok { + return nil + } + case jpString: + if _, ok := arg.(string); ok { + return nil + } + case jpArray: + if isSliceType(arg) { + return nil + } + case jpObject: + if _, ok := arg.(map[string]interface{}); ok { + return nil + } + case jpArrayNumber: + if _, ok := toArrayNum(arg); ok { + return nil + } + case jpArrayString: + if _, ok := toArrayStr(arg); ok { + return nil + } + case jpAny: + return nil + case jpExpref: + if _, ok := arg.(expRef); ok { + return nil + } + } + } + return fmt.Errorf("Invalid type for: %v, expected: %#v", arg, a.types) +} + +func (f *functionCaller) CallFunction(name string, arguments []interface{}, intr *treeInterpreter) (interface{}, error) { + entry, ok := f.functionTable[name] + if !ok { + return nil, errors.New("unknown function: " + name) + } + resolvedArgs, err := entry.resolveArgs(arguments) + if err != nil { + return nil, err + } + if entry.hasExpRef { + var extra []interface{} + extra = append(extra, intr) + resolvedArgs = append(extra, resolvedArgs...) + } + return entry.handler(resolvedArgs) +} + +func jpfAbs(arguments []interface{}) (interface{}, error) { + num := arguments[0].(float64) + return math.Abs(num), nil +} + +func jpfLength(arguments []interface{}) (interface{}, error) { + arg := arguments[0] + if c, ok := arg.(string); ok { + return float64(utf8.RuneCountInString(c)), nil + } else if isSliceType(arg) { + v := reflect.ValueOf(arg) + return float64(v.Len()), nil + } else if c, ok := arg.(map[string]interface{}); ok { + return float64(len(c)), nil + } + return nil, errors.New("could not compute length()") +} + +func jpfStartsWith(arguments []interface{}) (interface{}, error) { + search := arguments[0].(string) + prefix := arguments[1].(string) + return strings.HasPrefix(search, prefix), nil +} + +func jpfAvg(arguments []interface{}) (interface{}, error) { + // We've already type checked the value so we can safely use + // type assertions. + args := arguments[0].([]interface{}) + length := float64(len(args)) + numerator := 0.0 + for _, n := range args { + numerator += n.(float64) + } + return numerator / length, nil +} +func jpfCeil(arguments []interface{}) (interface{}, error) { + val := arguments[0].(float64) + return math.Ceil(val), nil +} +func jpfContains(arguments []interface{}) (interface{}, error) { + search := arguments[0] + el := arguments[1] + if searchStr, ok := search.(string); ok { + if elStr, ok := el.(string); ok { + return strings.Index(searchStr, elStr) != -1, nil + } + return false, nil + } + // Otherwise this is a generic contains for []interface{} + general := search.([]interface{}) + for _, item := range general { + if item == el { + return true, nil + } + } + return false, nil +} +func jpfEndsWith(arguments []interface{}) (interface{}, error) { + search := arguments[0].(string) + suffix := arguments[1].(string) + return strings.HasSuffix(search, suffix), nil +} +func jpfFloor(arguments []interface{}) (interface{}, error) { + val := arguments[0].(float64) + return math.Floor(val), nil +} +func jpfMap(arguments []interface{}) (interface{}, error) { + intr := arguments[0].(*treeInterpreter) + exp := arguments[1].(expRef) + node := exp.ref + arr := arguments[2].([]interface{}) + mapped := make([]interface{}, 0, len(arr)) + for _, value := range arr { + current, err := intr.Execute(node, value) + if err != nil { + return nil, err + } + mapped = append(mapped, current) + } + return mapped, nil +} +func jpfMax(arguments []interface{}) (interface{}, error) { + if items, ok := toArrayNum(arguments[0]); ok { + if len(items) == 0 { + return nil, nil + } + if len(items) == 1 { + return items[0], nil + } + best := items[0] + for _, item := range items[1:] { + if item > best { + best = item + } + } + return best, nil + } + // Otherwise we're dealing with a max() of strings. + items, _ := toArrayStr(arguments[0]) + if len(items) == 0 { + return nil, nil + } + if len(items) == 1 { + return items[0], nil + } + best := items[0] + for _, item := range items[1:] { + if item > best { + best = item + } + } + return best, nil +} +func jpfMerge(arguments []interface{}) (interface{}, error) { + final := make(map[string]interface{}) + for _, m := range arguments { + mapped := m.(map[string]interface{}) + for key, value := range mapped { + final[key] = value + } + } + return final, nil +} +func jpfMaxBy(arguments []interface{}) (interface{}, error) { + intr := arguments[0].(*treeInterpreter) + arr := arguments[1].([]interface{}) + exp := arguments[2].(expRef) + node := exp.ref + if len(arr) == 0 { + return nil, nil + } else if len(arr) == 1 { + return arr[0], nil + } + start, err := intr.Execute(node, arr[0]) + if err != nil { + return nil, err + } + switch t := start.(type) { + case float64: + bestVal := t + bestItem := arr[0] + for _, item := range arr[1:] { + result, err := intr.Execute(node, item) + if err != nil { + return nil, err + } + current, ok := result.(float64) + if !ok { + return nil, errors.New("invalid type, must be number") + } + if current > bestVal { + bestVal = current + bestItem = item + } + } + return bestItem, nil + case string: + bestVal := t + bestItem := arr[0] + for _, item := range arr[1:] { + result, err := intr.Execute(node, item) + if err != nil { + return nil, err + } + current, ok := result.(string) + if !ok { + return nil, errors.New("invalid type, must be string") + } + if current > bestVal { + bestVal = current + bestItem = item + } + } + return bestItem, nil + default: + return nil, errors.New("invalid type, must be number of string") + } +} +func jpfSum(arguments []interface{}) (interface{}, error) { + items, _ := toArrayNum(arguments[0]) + sum := 0.0 + for _, item := range items { + sum += item + } + return sum, nil +} + +func jpfMin(arguments []interface{}) (interface{}, error) { + if items, ok := toArrayNum(arguments[0]); ok { + if len(items) == 0 { + return nil, nil + } + if len(items) == 1 { + return items[0], nil + } + best := items[0] + for _, item := range items[1:] { + if item < best { + best = item + } + } + return best, nil + } + items, _ := toArrayStr(arguments[0]) + if len(items) == 0 { + return nil, nil + } + if len(items) == 1 { + return items[0], nil + } + best := items[0] + for _, item := range items[1:] { + if item < best { + best = item + } + } + return best, nil +} + +func jpfMinBy(arguments []interface{}) (interface{}, error) { + intr := arguments[0].(*treeInterpreter) + arr := arguments[1].([]interface{}) + exp := arguments[2].(expRef) + node := exp.ref + if len(arr) == 0 { + return nil, nil + } else if len(arr) == 1 { + return arr[0], nil + } + start, err := intr.Execute(node, arr[0]) + if err != nil { + return nil, err + } + if t, ok := start.(float64); ok { + bestVal := t + bestItem := arr[0] + for _, item := range arr[1:] { + result, err := intr.Execute(node, item) + if err != nil { + return nil, err + } + current, ok := result.(float64) + if !ok { + return nil, errors.New("invalid type, must be number") + } + if current < bestVal { + bestVal = current + bestItem = item + } + } + return bestItem, nil + } else if t, ok := start.(string); ok { + bestVal := t + bestItem := arr[0] + for _, item := range arr[1:] { + result, err := intr.Execute(node, item) + if err != nil { + return nil, err + } + current, ok := result.(string) + if !ok { + return nil, errors.New("invalid type, must be string") + } + if current < bestVal { + bestVal = current + bestItem = item + } + } + return bestItem, nil + } else { + return nil, errors.New("invalid type, must be number of string") + } +} +func jpfType(arguments []interface{}) (interface{}, error) { + arg := arguments[0] + if _, ok := arg.(float64); ok { + return "number", nil + } + if _, ok := arg.(string); ok { + return "string", nil + } + if _, ok := arg.([]interface{}); ok { + return "array", nil + } + if _, ok := arg.(map[string]interface{}); ok { + return "object", nil + } + if arg == nil { + return "null", nil + } + if arg == true || arg == false { + return "boolean", nil + } + return nil, errors.New("unknown type") +} +func jpfKeys(arguments []interface{}) (interface{}, error) { + arg := arguments[0].(map[string]interface{}) + collected := make([]interface{}, 0, len(arg)) + for key := range arg { + collected = append(collected, key) + } + return collected, nil +} +func jpfValues(arguments []interface{}) (interface{}, error) { + arg := arguments[0].(map[string]interface{}) + collected := make([]interface{}, 0, len(arg)) + for _, value := range arg { + collected = append(collected, value) + } + return collected, nil +} +func jpfSort(arguments []interface{}) (interface{}, error) { + if items, ok := toArrayNum(arguments[0]); ok { + d := sort.Float64Slice(items) + sort.Stable(d) + final := make([]interface{}, len(d)) + for i, val := range d { + final[i] = val + } + return final, nil + } + // Otherwise we're dealing with sort()'ing strings. + items, _ := toArrayStr(arguments[0]) + d := sort.StringSlice(items) + sort.Stable(d) + final := make([]interface{}, len(d)) + for i, val := range d { + final[i] = val + } + return final, nil +} +func jpfSortBy(arguments []interface{}) (interface{}, error) { + intr := arguments[0].(*treeInterpreter) + arr := arguments[1].([]interface{}) + exp := arguments[2].(expRef) + node := exp.ref + if len(arr) == 0 { + return arr, nil + } else if len(arr) == 1 { + return arr, nil + } + start, err := intr.Execute(node, arr[0]) + if err != nil { + return nil, err + } + if _, ok := start.(float64); ok { + sortable := &byExprFloat{intr, node, arr, false} + sort.Stable(sortable) + if sortable.hasError { + return nil, errors.New("error in sort_by comparison") + } + return arr, nil + } else if _, ok := start.(string); ok { + sortable := &byExprString{intr, node, arr, false} + sort.Stable(sortable) + if sortable.hasError { + return nil, errors.New("error in sort_by comparison") + } + return arr, nil + } else { + return nil, errors.New("invalid type, must be number of string") + } +} +func jpfJoin(arguments []interface{}) (interface{}, error) { + sep := arguments[0].(string) + // We can't just do arguments[1].([]string), we have to + // manually convert each item to a string. + arrayStr := []string{} + for _, item := range arguments[1].([]interface{}) { + arrayStr = append(arrayStr, item.(string)) + } + return strings.Join(arrayStr, sep), nil +} +func jpfReverse(arguments []interface{}) (interface{}, error) { + if s, ok := arguments[0].(string); ok { + r := []rune(s) + for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { + r[i], r[j] = r[j], r[i] + } + return string(r), nil + } + items := arguments[0].([]interface{}) + length := len(items) + reversed := make([]interface{}, length) + for i, item := range items { + reversed[length-(i+1)] = item + } + return reversed, nil +} +func jpfToArray(arguments []interface{}) (interface{}, error) { + if _, ok := arguments[0].([]interface{}); ok { + return arguments[0], nil + } + return arguments[:1:1], nil +} +func jpfToString(arguments []interface{}) (interface{}, error) { + if v, ok := arguments[0].(string); ok { + return v, nil + } + result, err := json.Marshal(arguments[0]) + if err != nil { + return nil, err + } + return string(result), nil +} +func jpfToNumber(arguments []interface{}) (interface{}, error) { + arg := arguments[0] + if v, ok := arg.(float64); ok { + return v, nil + } + if v, ok := arg.(string); ok { + conv, err := strconv.ParseFloat(v, 64) + if err != nil { + return nil, nil + } + return conv, nil + } + if _, ok := arg.([]interface{}); ok { + return nil, nil + } + if _, ok := arg.(map[string]interface{}); ok { + return nil, nil + } + if arg == nil { + return nil, nil + } + if arg == true || arg == false { + return nil, nil + } + return nil, errors.New("unknown type") +} +func jpfNotNull(arguments []interface{}) (interface{}, error) { + for _, arg := range arguments { + if arg != nil { + return arg, nil + } + } + return nil, nil +} diff --git a/vendor/github.com/jmespath/go-jmespath/interpreter.go b/vendor/github.com/jmespath/go-jmespath/interpreter.go new file mode 100644 index 000000000..13c74604c --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/interpreter.go @@ -0,0 +1,418 @@ +package jmespath + +import ( + "errors" + "reflect" + "unicode" + "unicode/utf8" +) + +/* This is a tree based interpreter. It walks the AST and directly + interprets the AST to search through a JSON document. +*/ + +type treeInterpreter struct { + fCall *functionCaller +} + +func newInterpreter() *treeInterpreter { + interpreter := treeInterpreter{} + interpreter.fCall = newFunctionCaller() + return &interpreter +} + +type expRef struct { + ref ASTNode +} + +// Execute takes an ASTNode and input data and interprets the AST directly. +// It will produce the result of applying the JMESPath expression associated +// with the ASTNode to the input data "value". +func (intr *treeInterpreter) Execute(node ASTNode, value interface{}) (interface{}, error) { + switch node.nodeType { + case ASTComparator: + left, err := intr.Execute(node.children[0], value) + if err != nil { + return nil, err + } + right, err := intr.Execute(node.children[1], value) + if err != nil { + return nil, err + } + switch node.value { + case tEQ: + return objsEqual(left, right), nil + case tNE: + return !objsEqual(left, right), nil + } + leftNum, ok := left.(float64) + if !ok { + return nil, nil + } + rightNum, ok := right.(float64) + if !ok { + return nil, nil + } + switch node.value { + case tGT: + return leftNum > rightNum, nil + case tGTE: + return leftNum >= rightNum, nil + case tLT: + return leftNum < rightNum, nil + case tLTE: + return leftNum <= rightNum, nil + } + case ASTExpRef: + return expRef{ref: node.children[0]}, nil + case ASTFunctionExpression: + resolvedArgs := []interface{}{} + for _, arg := range node.children { + current, err := intr.Execute(arg, value) + if err != nil { + return nil, err + } + resolvedArgs = append(resolvedArgs, current) + } + return intr.fCall.CallFunction(node.value.(string), resolvedArgs, intr) + case ASTField: + if m, ok := value.(map[string]interface{}); ok { + key := node.value.(string) + return m[key], nil + } + return intr.fieldFromStruct(node.value.(string), value) + case ASTFilterProjection: + left, err := intr.Execute(node.children[0], value) + if err != nil { + return nil, nil + } + sliceType, ok := left.([]interface{}) + if !ok { + if isSliceType(left) { + return intr.filterProjectionWithReflection(node, left) + } + return nil, nil + } + compareNode := node.children[2] + collected := []interface{}{} + for _, element := range sliceType { + result, err := intr.Execute(compareNode, element) + if err != nil { + return nil, err + } + if !isFalse(result) { + current, err := intr.Execute(node.children[1], element) + if err != nil { + return nil, err + } + if current != nil { + collected = append(collected, current) + } + } + } + return collected, nil + case ASTFlatten: + left, err := intr.Execute(node.children[0], value) + if err != nil { + return nil, nil + } + sliceType, ok := left.([]interface{}) + if !ok { + // If we can't type convert to []interface{}, there's + // a chance this could still work via reflection if we're + // dealing with user provided types. + if isSliceType(left) { + return intr.flattenWithReflection(left) + } + return nil, nil + } + flattened := []interface{}{} + for _, element := range sliceType { + if elementSlice, ok := element.([]interface{}); ok { + flattened = append(flattened, elementSlice...) + } else if isSliceType(element) { + reflectFlat := []interface{}{} + v := reflect.ValueOf(element) + for i := 0; i < v.Len(); i++ { + reflectFlat = append(reflectFlat, v.Index(i).Interface()) + } + flattened = append(flattened, reflectFlat...) + } else { + flattened = append(flattened, element) + } + } + return flattened, nil + case ASTIdentity, ASTCurrentNode: + return value, nil + case ASTIndex: + if sliceType, ok := value.([]interface{}); ok { + index := node.value.(int) + if index < 0 { + index += len(sliceType) + } + if index < len(sliceType) && index >= 0 { + return sliceType[index], nil + } + return nil, nil + } + // Otherwise try via reflection. + rv := reflect.ValueOf(value) + if rv.Kind() == reflect.Slice { + index := node.value.(int) + if index < 0 { + index += rv.Len() + } + if index < rv.Len() && index >= 0 { + v := rv.Index(index) + return v.Interface(), nil + } + } + return nil, nil + case ASTKeyValPair: + return intr.Execute(node.children[0], value) + case ASTLiteral: + return node.value, nil + case ASTMultiSelectHash: + if value == nil { + return nil, nil + } + collected := make(map[string]interface{}) + for _, child := range node.children { + current, err := intr.Execute(child, value) + if err != nil { + return nil, err + } + key := child.value.(string) + collected[key] = current + } + return collected, nil + case ASTMultiSelectList: + if value == nil { + return nil, nil + } + collected := []interface{}{} + for _, child := range node.children { + current, err := intr.Execute(child, value) + if err != nil { + return nil, err + } + collected = append(collected, current) + } + return collected, nil + case ASTOrExpression: + matched, err := intr.Execute(node.children[0], value) + if err != nil { + return nil, err + } + if isFalse(matched) { + matched, err = intr.Execute(node.children[1], value) + if err != nil { + return nil, err + } + } + return matched, nil + case ASTAndExpression: + matched, err := intr.Execute(node.children[0], value) + if err != nil { + return nil, err + } + if isFalse(matched) { + return matched, nil + } + return intr.Execute(node.children[1], value) + case ASTNotExpression: + matched, err := intr.Execute(node.children[0], value) + if err != nil { + return nil, err + } + if isFalse(matched) { + return true, nil + } + return false, nil + case ASTPipe: + result := value + var err error + for _, child := range node.children { + result, err = intr.Execute(child, result) + if err != nil { + return nil, err + } + } + return result, nil + case ASTProjection: + left, err := intr.Execute(node.children[0], value) + if err != nil { + return nil, err + } + sliceType, ok := left.([]interface{}) + if !ok { + if isSliceType(left) { + return intr.projectWithReflection(node, left) + } + return nil, nil + } + collected := []interface{}{} + var current interface{} + for _, element := range sliceType { + current, err = intr.Execute(node.children[1], element) + if err != nil { + return nil, err + } + if current != nil { + collected = append(collected, current) + } + } + return collected, nil + case ASTSubexpression, ASTIndexExpression: + left, err := intr.Execute(node.children[0], value) + if err != nil { + return nil, err + } + return intr.Execute(node.children[1], left) + case ASTSlice: + sliceType, ok := value.([]interface{}) + if !ok { + if isSliceType(value) { + return intr.sliceWithReflection(node, value) + } + return nil, nil + } + parts := node.value.([]*int) + sliceParams := make([]sliceParam, 3) + for i, part := range parts { + if part != nil { + sliceParams[i].Specified = true + sliceParams[i].N = *part + } + } + return slice(sliceType, sliceParams) + case ASTValueProjection: + left, err := intr.Execute(node.children[0], value) + if err != nil { + return nil, nil + } + mapType, ok := left.(map[string]interface{}) + if !ok { + return nil, nil + } + values := make([]interface{}, len(mapType)) + for _, value := range mapType { + values = append(values, value) + } + collected := []interface{}{} + for _, element := range values { + current, err := intr.Execute(node.children[1], element) + if err != nil { + return nil, err + } + if current != nil { + collected = append(collected, current) + } + } + return collected, nil + } + return nil, errors.New("Unknown AST node: " + node.nodeType.String()) +} + +func (intr *treeInterpreter) fieldFromStruct(key string, value interface{}) (interface{}, error) { + rv := reflect.ValueOf(value) + first, n := utf8.DecodeRuneInString(key) + fieldName := string(unicode.ToUpper(first)) + key[n:] + if rv.Kind() == reflect.Struct { + v := rv.FieldByName(fieldName) + if !v.IsValid() { + return nil, nil + } + return v.Interface(), nil + } else if rv.Kind() == reflect.Ptr { + // Handle multiple levels of indirection? + if rv.IsNil() { + return nil, nil + } + rv = rv.Elem() + v := rv.FieldByName(fieldName) + if !v.IsValid() { + return nil, nil + } + return v.Interface(), nil + } + return nil, nil +} + +func (intr *treeInterpreter) flattenWithReflection(value interface{}) (interface{}, error) { + v := reflect.ValueOf(value) + flattened := []interface{}{} + for i := 0; i < v.Len(); i++ { + element := v.Index(i).Interface() + if reflect.TypeOf(element).Kind() == reflect.Slice { + // Then insert the contents of the element + // slice into the flattened slice, + // i.e flattened = append(flattened, mySlice...) + elementV := reflect.ValueOf(element) + for j := 0; j < elementV.Len(); j++ { + flattened = append( + flattened, elementV.Index(j).Interface()) + } + } else { + flattened = append(flattened, element) + } + } + return flattened, nil +} + +func (intr *treeInterpreter) sliceWithReflection(node ASTNode, value interface{}) (interface{}, error) { + v := reflect.ValueOf(value) + parts := node.value.([]*int) + sliceParams := make([]sliceParam, 3) + for i, part := range parts { + if part != nil { + sliceParams[i].Specified = true + sliceParams[i].N = *part + } + } + final := []interface{}{} + for i := 0; i < v.Len(); i++ { + element := v.Index(i).Interface() + final = append(final, element) + } + return slice(final, sliceParams) +} + +func (intr *treeInterpreter) filterProjectionWithReflection(node ASTNode, value interface{}) (interface{}, error) { + compareNode := node.children[2] + collected := []interface{}{} + v := reflect.ValueOf(value) + for i := 0; i < v.Len(); i++ { + element := v.Index(i).Interface() + result, err := intr.Execute(compareNode, element) + if err != nil { + return nil, err + } + if !isFalse(result) { + current, err := intr.Execute(node.children[1], element) + if err != nil { + return nil, err + } + if current != nil { + collected = append(collected, current) + } + } + } + return collected, nil +} + +func (intr *treeInterpreter) projectWithReflection(node ASTNode, value interface{}) (interface{}, error) { + collected := []interface{}{} + v := reflect.ValueOf(value) + for i := 0; i < v.Len(); i++ { + element := v.Index(i).Interface() + result, err := intr.Execute(node.children[1], element) + if err != nil { + return nil, err + } + if result != nil { + collected = append(collected, result) + } + } + return collected, nil +} diff --git a/vendor/github.com/jmespath/go-jmespath/lexer.go b/vendor/github.com/jmespath/go-jmespath/lexer.go new file mode 100644 index 000000000..817900c8f --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/lexer.go @@ -0,0 +1,420 @@ +package jmespath + +import ( + "bytes" + "encoding/json" + "fmt" + "strconv" + "strings" + "unicode/utf8" +) + +type token struct { + tokenType tokType + value string + position int + length int +} + +type tokType int + +const eof = -1 + +// Lexer contains information about the expression being tokenized. +type Lexer struct { + expression string // The expression provided by the user. + currentPos int // The current position in the string. + lastWidth int // The width of the current rune. This + buf bytes.Buffer // Internal buffer used for building up values. +} + +// SyntaxError is the main error used whenever a lexing or parsing error occurs. +type SyntaxError struct { + msg string // Error message displayed to user + Expression string // Expression that generated a SyntaxError + Offset int // The location in the string where the error occurred +} + +func (e SyntaxError) Error() string { + // In the future, it would be good to underline the specific + // location where the error occurred. + return "SyntaxError: " + e.msg +} + +// HighlightLocation will show where the syntax error occurred. +// It will place a "^" character on a line below the expression +// at the point where the syntax error occurred. +func (e SyntaxError) HighlightLocation() string { + return e.Expression + "\n" + strings.Repeat(" ", e.Offset) + "^" +} + +//go:generate stringer -type=tokType +const ( + tUnknown tokType = iota + tStar + tDot + tFilter + tFlatten + tLparen + tRparen + tLbracket + tRbracket + tLbrace + tRbrace + tOr + tPipe + tNumber + tUnquotedIdentifier + tQuotedIdentifier + tComma + tColon + tLT + tLTE + tGT + tGTE + tEQ + tNE + tJSONLiteral + tStringLiteral + tCurrent + tExpref + tAnd + tNot + tEOF +) + +var basicTokens = map[rune]tokType{ + '.': tDot, + '*': tStar, + ',': tComma, + ':': tColon, + '{': tLbrace, + '}': tRbrace, + ']': tRbracket, // tLbracket not included because it could be "[]" + '(': tLparen, + ')': tRparen, + '@': tCurrent, +} + +// Bit mask for [a-zA-Z_] shifted down 64 bits to fit in a single uint64. +// When using this bitmask just be sure to shift the rune down 64 bits +// before checking against identifierStartBits. +const identifierStartBits uint64 = 576460745995190270 + +// Bit mask for [a-zA-Z0-9], 128 bits -> 2 uint64s. +var identifierTrailingBits = [2]uint64{287948901175001088, 576460745995190270} + +var whiteSpace = map[rune]bool{ + ' ': true, '\t': true, '\n': true, '\r': true, +} + +func (t token) String() string { + return fmt.Sprintf("Token{%+v, %s, %d, %d}", + t.tokenType, t.value, t.position, t.length) +} + +// NewLexer creates a new JMESPath lexer. +func NewLexer() *Lexer { + lexer := Lexer{} + return &lexer +} + +func (lexer *Lexer) next() rune { + if lexer.currentPos >= len(lexer.expression) { + lexer.lastWidth = 0 + return eof + } + r, w := utf8.DecodeRuneInString(lexer.expression[lexer.currentPos:]) + lexer.lastWidth = w + lexer.currentPos += w + return r +} + +func (lexer *Lexer) back() { + lexer.currentPos -= lexer.lastWidth +} + +func (lexer *Lexer) peek() rune { + t := lexer.next() + lexer.back() + return t +} + +// tokenize takes an expression and returns corresponding tokens. +func (lexer *Lexer) tokenize(expression string) ([]token, error) { + var tokens []token + lexer.expression = expression + lexer.currentPos = 0 + lexer.lastWidth = 0 +loop: + for { + r := lexer.next() + if identifierStartBits&(1<<(uint64(r)-64)) > 0 { + t := lexer.consumeUnquotedIdentifier() + tokens = append(tokens, t) + } else if val, ok := basicTokens[r]; ok { + // Basic single char token. + t := token{ + tokenType: val, + value: string(r), + position: lexer.currentPos - lexer.lastWidth, + length: 1, + } + tokens = append(tokens, t) + } else if r == '-' || (r >= '0' && r <= '9') { + t := lexer.consumeNumber() + tokens = append(tokens, t) + } else if r == '[' { + t := lexer.consumeLBracket() + tokens = append(tokens, t) + } else if r == '"' { + t, err := lexer.consumeQuotedIdentifier() + if err != nil { + return tokens, err + } + tokens = append(tokens, t) + } else if r == '\'' { + t, err := lexer.consumeRawStringLiteral() + if err != nil { + return tokens, err + } + tokens = append(tokens, t) + } else if r == '`' { + t, err := lexer.consumeLiteral() + if err != nil { + return tokens, err + } + tokens = append(tokens, t) + } else if r == '|' { + t := lexer.matchOrElse(r, '|', tOr, tPipe) + tokens = append(tokens, t) + } else if r == '<' { + t := lexer.matchOrElse(r, '=', tLTE, tLT) + tokens = append(tokens, t) + } else if r == '>' { + t := lexer.matchOrElse(r, '=', tGTE, tGT) + tokens = append(tokens, t) + } else if r == '!' { + t := lexer.matchOrElse(r, '=', tNE, tNot) + tokens = append(tokens, t) + } else if r == '=' { + t := lexer.matchOrElse(r, '=', tEQ, tUnknown) + tokens = append(tokens, t) + } else if r == '&' { + t := lexer.matchOrElse(r, '&', tAnd, tExpref) + tokens = append(tokens, t) + } else if r == eof { + break loop + } else if _, ok := whiteSpace[r]; ok { + // Ignore whitespace + } else { + return tokens, lexer.syntaxError(fmt.Sprintf("Unknown char: %s", strconv.QuoteRuneToASCII(r))) + } + } + tokens = append(tokens, token{tEOF, "", len(lexer.expression), 0}) + return tokens, nil +} + +// Consume characters until the ending rune "r" is reached. +// If the end of the expression is reached before seeing the +// terminating rune "r", then an error is returned. +// If no error occurs then the matching substring is returned. +// The returned string will not include the ending rune. +func (lexer *Lexer) consumeUntil(end rune) (string, error) { + start := lexer.currentPos + current := lexer.next() + for current != end && current != eof { + if current == '\\' && lexer.peek() != eof { + lexer.next() + } + current = lexer.next() + } + if lexer.lastWidth == 0 { + // Then we hit an EOF so we never reached the closing + // delimiter. + return "", SyntaxError{ + msg: "Unclosed delimiter: " + string(end), + Expression: lexer.expression, + Offset: len(lexer.expression), + } + } + return lexer.expression[start : lexer.currentPos-lexer.lastWidth], nil +} + +func (lexer *Lexer) consumeLiteral() (token, error) { + start := lexer.currentPos + value, err := lexer.consumeUntil('`') + if err != nil { + return token{}, err + } + value = strings.Replace(value, "\\`", "`", -1) + return token{ + tokenType: tJSONLiteral, + value: value, + position: start, + length: len(value), + }, nil +} + +func (lexer *Lexer) consumeRawStringLiteral() (token, error) { + start := lexer.currentPos + currentIndex := start + current := lexer.next() + for current != '\'' && lexer.peek() != eof { + if current == '\\' && lexer.peek() == '\'' { + chunk := lexer.expression[currentIndex : lexer.currentPos-1] + lexer.buf.WriteString(chunk) + lexer.buf.WriteString("'") + lexer.next() + currentIndex = lexer.currentPos + } + current = lexer.next() + } + if lexer.lastWidth == 0 { + // Then we hit an EOF so we never reached the closing + // delimiter. + return token{}, SyntaxError{ + msg: "Unclosed delimiter: '", + Expression: lexer.expression, + Offset: len(lexer.expression), + } + } + if currentIndex < lexer.currentPos { + lexer.buf.WriteString(lexer.expression[currentIndex : lexer.currentPos-1]) + } + value := lexer.buf.String() + // Reset the buffer so it can reused again. + lexer.buf.Reset() + return token{ + tokenType: tStringLiteral, + value: value, + position: start, + length: len(value), + }, nil +} + +func (lexer *Lexer) syntaxError(msg string) SyntaxError { + return SyntaxError{ + msg: msg, + Expression: lexer.expression, + Offset: lexer.currentPos - 1, + } +} + +// Checks for a two char token, otherwise matches a single character +// token. This is used whenever a two char token overlaps a single +// char token, e.g. "||" -> tPipe, "|" -> tOr. +func (lexer *Lexer) matchOrElse(first rune, second rune, matchedType tokType, singleCharType tokType) token { + start := lexer.currentPos - lexer.lastWidth + nextRune := lexer.next() + var t token + if nextRune == second { + t = token{ + tokenType: matchedType, + value: string(first) + string(second), + position: start, + length: 2, + } + } else { + lexer.back() + t = token{ + tokenType: singleCharType, + value: string(first), + position: start, + length: 1, + } + } + return t +} + +func (lexer *Lexer) consumeLBracket() token { + // There's three options here: + // 1. A filter expression "[?" + // 2. A flatten operator "[]" + // 3. A bare rbracket "[" + start := lexer.currentPos - lexer.lastWidth + nextRune := lexer.next() + var t token + if nextRune == '?' { + t = token{ + tokenType: tFilter, + value: "[?", + position: start, + length: 2, + } + } else if nextRune == ']' { + t = token{ + tokenType: tFlatten, + value: "[]", + position: start, + length: 2, + } + } else { + t = token{ + tokenType: tLbracket, + value: "[", + position: start, + length: 1, + } + lexer.back() + } + return t +} + +func (lexer *Lexer) consumeQuotedIdentifier() (token, error) { + start := lexer.currentPos + value, err := lexer.consumeUntil('"') + if err != nil { + return token{}, err + } + var decoded string + asJSON := []byte("\"" + value + "\"") + if err := json.Unmarshal([]byte(asJSON), &decoded); err != nil { + return token{}, err + } + return token{ + tokenType: tQuotedIdentifier, + value: decoded, + position: start - 1, + length: len(decoded), + }, nil +} + +func (lexer *Lexer) consumeUnquotedIdentifier() token { + // Consume runes until we reach the end of an unquoted + // identifier. + start := lexer.currentPos - lexer.lastWidth + for { + r := lexer.next() + if r < 0 || r > 128 || identifierTrailingBits[uint64(r)/64]&(1<<(uint64(r)%64)) == 0 { + lexer.back() + break + } + } + value := lexer.expression[start:lexer.currentPos] + return token{ + tokenType: tUnquotedIdentifier, + value: value, + position: start, + length: lexer.currentPos - start, + } +} + +func (lexer *Lexer) consumeNumber() token { + // Consume runes until we reach something that's not a number. + start := lexer.currentPos - lexer.lastWidth + for { + r := lexer.next() + if r < '0' || r > '9' { + lexer.back() + break + } + } + value := lexer.expression[start:lexer.currentPos] + return token{ + tokenType: tNumber, + value: value, + position: start, + length: lexer.currentPos - start, + } +} diff --git a/vendor/github.com/jmespath/go-jmespath/parser.go b/vendor/github.com/jmespath/go-jmespath/parser.go new file mode 100644 index 000000000..1240a1755 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/parser.go @@ -0,0 +1,603 @@ +package jmespath + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" +) + +type astNodeType int + +//go:generate stringer -type astNodeType +const ( + ASTEmpty astNodeType = iota + ASTComparator + ASTCurrentNode + ASTExpRef + ASTFunctionExpression + ASTField + ASTFilterProjection + ASTFlatten + ASTIdentity + ASTIndex + ASTIndexExpression + ASTKeyValPair + ASTLiteral + ASTMultiSelectHash + ASTMultiSelectList + ASTOrExpression + ASTAndExpression + ASTNotExpression + ASTPipe + ASTProjection + ASTSubexpression + ASTSlice + ASTValueProjection +) + +// ASTNode represents the abstract syntax tree of a JMESPath expression. +type ASTNode struct { + nodeType astNodeType + value interface{} + children []ASTNode +} + +func (node ASTNode) String() string { + return node.PrettyPrint(0) +} + +// PrettyPrint will pretty print the parsed AST. +// The AST is an implementation detail and this pretty print +// function is provided as a convenience method to help with +// debugging. You should not rely on its output as the internal +// structure of the AST may change at any time. +func (node ASTNode) PrettyPrint(indent int) string { + spaces := strings.Repeat(" ", indent) + output := fmt.Sprintf("%s%s {\n", spaces, node.nodeType) + nextIndent := indent + 2 + if node.value != nil { + if converted, ok := node.value.(fmt.Stringer); ok { + // Account for things like comparator nodes + // that are enums with a String() method. + output += fmt.Sprintf("%svalue: %s\n", strings.Repeat(" ", nextIndent), converted.String()) + } else { + output += fmt.Sprintf("%svalue: %#v\n", strings.Repeat(" ", nextIndent), node.value) + } + } + lastIndex := len(node.children) + if lastIndex > 0 { + output += fmt.Sprintf("%schildren: {\n", strings.Repeat(" ", nextIndent)) + childIndent := nextIndent + 2 + for _, elem := range node.children { + output += elem.PrettyPrint(childIndent) + } + } + output += fmt.Sprintf("%s}\n", spaces) + return output +} + +var bindingPowers = map[tokType]int{ + tEOF: 0, + tUnquotedIdentifier: 0, + tQuotedIdentifier: 0, + tRbracket: 0, + tRparen: 0, + tComma: 0, + tRbrace: 0, + tNumber: 0, + tCurrent: 0, + tExpref: 0, + tColon: 0, + tPipe: 1, + tOr: 2, + tAnd: 3, + tEQ: 5, + tLT: 5, + tLTE: 5, + tGT: 5, + tGTE: 5, + tNE: 5, + tFlatten: 9, + tStar: 20, + tFilter: 21, + tDot: 40, + tNot: 45, + tLbrace: 50, + tLbracket: 55, + tLparen: 60, +} + +// Parser holds state about the current expression being parsed. +type Parser struct { + expression string + tokens []token + index int +} + +// NewParser creates a new JMESPath parser. +func NewParser() *Parser { + p := Parser{} + return &p +} + +// Parse will compile a JMESPath expression. +func (p *Parser) Parse(expression string) (ASTNode, error) { + lexer := NewLexer() + p.expression = expression + p.index = 0 + tokens, err := lexer.tokenize(expression) + if err != nil { + return ASTNode{}, err + } + p.tokens = tokens + parsed, err := p.parseExpression(0) + if err != nil { + return ASTNode{}, err + } + if p.current() != tEOF { + return ASTNode{}, p.syntaxError(fmt.Sprintf( + "Unexpected token at the end of the expresssion: %s", p.current())) + } + return parsed, nil +} + +func (p *Parser) parseExpression(bindingPower int) (ASTNode, error) { + var err error + leftToken := p.lookaheadToken(0) + p.advance() + leftNode, err := p.nud(leftToken) + if err != nil { + return ASTNode{}, err + } + currentToken := p.current() + for bindingPower < bindingPowers[currentToken] { + p.advance() + leftNode, err = p.led(currentToken, leftNode) + if err != nil { + return ASTNode{}, err + } + currentToken = p.current() + } + return leftNode, nil +} + +func (p *Parser) parseIndexExpression() (ASTNode, error) { + if p.lookahead(0) == tColon || p.lookahead(1) == tColon { + return p.parseSliceExpression() + } + indexStr := p.lookaheadToken(0).value + parsedInt, err := strconv.Atoi(indexStr) + if err != nil { + return ASTNode{}, err + } + indexNode := ASTNode{nodeType: ASTIndex, value: parsedInt} + p.advance() + if err := p.match(tRbracket); err != nil { + return ASTNode{}, err + } + return indexNode, nil +} + +func (p *Parser) parseSliceExpression() (ASTNode, error) { + parts := []*int{nil, nil, nil} + index := 0 + current := p.current() + for current != tRbracket && index < 3 { + if current == tColon { + index++ + p.advance() + } else if current == tNumber { + parsedInt, err := strconv.Atoi(p.lookaheadToken(0).value) + if err != nil { + return ASTNode{}, err + } + parts[index] = &parsedInt + p.advance() + } else { + return ASTNode{}, p.syntaxError( + "Expected tColon or tNumber" + ", received: " + p.current().String()) + } + current = p.current() + } + if err := p.match(tRbracket); err != nil { + return ASTNode{}, err + } + return ASTNode{ + nodeType: ASTSlice, + value: parts, + }, nil +} + +func (p *Parser) match(tokenType tokType) error { + if p.current() == tokenType { + p.advance() + return nil + } + return p.syntaxError("Expected " + tokenType.String() + ", received: " + p.current().String()) +} + +func (p *Parser) led(tokenType tokType, node ASTNode) (ASTNode, error) { + switch tokenType { + case tDot: + if p.current() != tStar { + right, err := p.parseDotRHS(bindingPowers[tDot]) + return ASTNode{ + nodeType: ASTSubexpression, + children: []ASTNode{node, right}, + }, err + } + p.advance() + right, err := p.parseProjectionRHS(bindingPowers[tDot]) + return ASTNode{ + nodeType: ASTValueProjection, + children: []ASTNode{node, right}, + }, err + case tPipe: + right, err := p.parseExpression(bindingPowers[tPipe]) + return ASTNode{nodeType: ASTPipe, children: []ASTNode{node, right}}, err + case tOr: + right, err := p.parseExpression(bindingPowers[tOr]) + return ASTNode{nodeType: ASTOrExpression, children: []ASTNode{node, right}}, err + case tAnd: + right, err := p.parseExpression(bindingPowers[tAnd]) + return ASTNode{nodeType: ASTAndExpression, children: []ASTNode{node, right}}, err + case tLparen: + name := node.value + var args []ASTNode + for p.current() != tRparen { + expression, err := p.parseExpression(0) + if err != nil { + return ASTNode{}, err + } + if p.current() == tComma { + if err := p.match(tComma); err != nil { + return ASTNode{}, err + } + } + args = append(args, expression) + } + if err := p.match(tRparen); err != nil { + return ASTNode{}, err + } + return ASTNode{ + nodeType: ASTFunctionExpression, + value: name, + children: args, + }, nil + case tFilter: + return p.parseFilter(node) + case tFlatten: + left := ASTNode{nodeType: ASTFlatten, children: []ASTNode{node}} + right, err := p.parseProjectionRHS(bindingPowers[tFlatten]) + return ASTNode{ + nodeType: ASTProjection, + children: []ASTNode{left, right}, + }, err + case tEQ, tNE, tGT, tGTE, tLT, tLTE: + right, err := p.parseExpression(bindingPowers[tokenType]) + if err != nil { + return ASTNode{}, err + } + return ASTNode{ + nodeType: ASTComparator, + value: tokenType, + children: []ASTNode{node, right}, + }, nil + case tLbracket: + tokenType := p.current() + var right ASTNode + var err error + if tokenType == tNumber || tokenType == tColon { + right, err = p.parseIndexExpression() + if err != nil { + return ASTNode{}, err + } + return p.projectIfSlice(node, right) + } + // Otherwise this is a projection. + if err := p.match(tStar); err != nil { + return ASTNode{}, err + } + if err := p.match(tRbracket); err != nil { + return ASTNode{}, err + } + right, err = p.parseProjectionRHS(bindingPowers[tStar]) + if err != nil { + return ASTNode{}, err + } + return ASTNode{ + nodeType: ASTProjection, + children: []ASTNode{node, right}, + }, nil + } + return ASTNode{}, p.syntaxError("Unexpected token: " + tokenType.String()) +} + +func (p *Parser) nud(token token) (ASTNode, error) { + switch token.tokenType { + case tJSONLiteral: + var parsed interface{} + err := json.Unmarshal([]byte(token.value), &parsed) + if err != nil { + return ASTNode{}, err + } + return ASTNode{nodeType: ASTLiteral, value: parsed}, nil + case tStringLiteral: + return ASTNode{nodeType: ASTLiteral, value: token.value}, nil + case tUnquotedIdentifier: + return ASTNode{ + nodeType: ASTField, + value: token.value, + }, nil + case tQuotedIdentifier: + node := ASTNode{nodeType: ASTField, value: token.value} + if p.current() == tLparen { + return ASTNode{}, p.syntaxErrorToken("Can't have quoted identifier as function name.", token) + } + return node, nil + case tStar: + left := ASTNode{nodeType: ASTIdentity} + var right ASTNode + var err error + if p.current() == tRbracket { + right = ASTNode{nodeType: ASTIdentity} + } else { + right, err = p.parseProjectionRHS(bindingPowers[tStar]) + } + return ASTNode{nodeType: ASTValueProjection, children: []ASTNode{left, right}}, err + case tFilter: + return p.parseFilter(ASTNode{nodeType: ASTIdentity}) + case tLbrace: + return p.parseMultiSelectHash() + case tFlatten: + left := ASTNode{ + nodeType: ASTFlatten, + children: []ASTNode{{nodeType: ASTIdentity}}, + } + right, err := p.parseProjectionRHS(bindingPowers[tFlatten]) + if err != nil { + return ASTNode{}, err + } + return ASTNode{nodeType: ASTProjection, children: []ASTNode{left, right}}, nil + case tLbracket: + tokenType := p.current() + //var right ASTNode + if tokenType == tNumber || tokenType == tColon { + right, err := p.parseIndexExpression() + if err != nil { + return ASTNode{}, nil + } + return p.projectIfSlice(ASTNode{nodeType: ASTIdentity}, right) + } else if tokenType == tStar && p.lookahead(1) == tRbracket { + p.advance() + p.advance() + right, err := p.parseProjectionRHS(bindingPowers[tStar]) + if err != nil { + return ASTNode{}, err + } + return ASTNode{ + nodeType: ASTProjection, + children: []ASTNode{{nodeType: ASTIdentity}, right}, + }, nil + } else { + return p.parseMultiSelectList() + } + case tCurrent: + return ASTNode{nodeType: ASTCurrentNode}, nil + case tExpref: + expression, err := p.parseExpression(bindingPowers[tExpref]) + if err != nil { + return ASTNode{}, err + } + return ASTNode{nodeType: ASTExpRef, children: []ASTNode{expression}}, nil + case tNot: + expression, err := p.parseExpression(bindingPowers[tNot]) + if err != nil { + return ASTNode{}, err + } + return ASTNode{nodeType: ASTNotExpression, children: []ASTNode{expression}}, nil + case tLparen: + expression, err := p.parseExpression(0) + if err != nil { + return ASTNode{}, err + } + if err := p.match(tRparen); err != nil { + return ASTNode{}, err + } + return expression, nil + case tEOF: + return ASTNode{}, p.syntaxErrorToken("Incomplete expression", token) + } + + return ASTNode{}, p.syntaxErrorToken("Invalid token: "+token.tokenType.String(), token) +} + +func (p *Parser) parseMultiSelectList() (ASTNode, error) { + var expressions []ASTNode + for { + expression, err := p.parseExpression(0) + if err != nil { + return ASTNode{}, err + } + expressions = append(expressions, expression) + if p.current() == tRbracket { + break + } + err = p.match(tComma) + if err != nil { + return ASTNode{}, err + } + } + err := p.match(tRbracket) + if err != nil { + return ASTNode{}, err + } + return ASTNode{ + nodeType: ASTMultiSelectList, + children: expressions, + }, nil +} + +func (p *Parser) parseMultiSelectHash() (ASTNode, error) { + var children []ASTNode + for { + keyToken := p.lookaheadToken(0) + if err := p.match(tUnquotedIdentifier); err != nil { + if err := p.match(tQuotedIdentifier); err != nil { + return ASTNode{}, p.syntaxError("Expected tQuotedIdentifier or tUnquotedIdentifier") + } + } + keyName := keyToken.value + err := p.match(tColon) + if err != nil { + return ASTNode{}, err + } + value, err := p.parseExpression(0) + if err != nil { + return ASTNode{}, err + } + node := ASTNode{ + nodeType: ASTKeyValPair, + value: keyName, + children: []ASTNode{value}, + } + children = append(children, node) + if p.current() == tComma { + err := p.match(tComma) + if err != nil { + return ASTNode{}, nil + } + } else if p.current() == tRbrace { + err := p.match(tRbrace) + if err != nil { + return ASTNode{}, nil + } + break + } + } + return ASTNode{ + nodeType: ASTMultiSelectHash, + children: children, + }, nil +} + +func (p *Parser) projectIfSlice(left ASTNode, right ASTNode) (ASTNode, error) { + indexExpr := ASTNode{ + nodeType: ASTIndexExpression, + children: []ASTNode{left, right}, + } + if right.nodeType == ASTSlice { + right, err := p.parseProjectionRHS(bindingPowers[tStar]) + return ASTNode{ + nodeType: ASTProjection, + children: []ASTNode{indexExpr, right}, + }, err + } + return indexExpr, nil +} +func (p *Parser) parseFilter(node ASTNode) (ASTNode, error) { + var right, condition ASTNode + var err error + condition, err = p.parseExpression(0) + if err != nil { + return ASTNode{}, err + } + if err := p.match(tRbracket); err != nil { + return ASTNode{}, err + } + if p.current() == tFlatten { + right = ASTNode{nodeType: ASTIdentity} + } else { + right, err = p.parseProjectionRHS(bindingPowers[tFilter]) + if err != nil { + return ASTNode{}, err + } + } + + return ASTNode{ + nodeType: ASTFilterProjection, + children: []ASTNode{node, right, condition}, + }, nil +} + +func (p *Parser) parseDotRHS(bindingPower int) (ASTNode, error) { + lookahead := p.current() + if tokensOneOf([]tokType{tQuotedIdentifier, tUnquotedIdentifier, tStar}, lookahead) { + return p.parseExpression(bindingPower) + } else if lookahead == tLbracket { + if err := p.match(tLbracket); err != nil { + return ASTNode{}, err + } + return p.parseMultiSelectList() + } else if lookahead == tLbrace { + if err := p.match(tLbrace); err != nil { + return ASTNode{}, err + } + return p.parseMultiSelectHash() + } + return ASTNode{}, p.syntaxError("Expected identifier, lbracket, or lbrace") +} + +func (p *Parser) parseProjectionRHS(bindingPower int) (ASTNode, error) { + current := p.current() + if bindingPowers[current] < 10 { + return ASTNode{nodeType: ASTIdentity}, nil + } else if current == tLbracket { + return p.parseExpression(bindingPower) + } else if current == tFilter { + return p.parseExpression(bindingPower) + } else if current == tDot { + err := p.match(tDot) + if err != nil { + return ASTNode{}, err + } + return p.parseDotRHS(bindingPower) + } else { + return ASTNode{}, p.syntaxError("Error") + } +} + +func (p *Parser) lookahead(number int) tokType { + return p.lookaheadToken(number).tokenType +} + +func (p *Parser) current() tokType { + return p.lookahead(0) +} + +func (p *Parser) lookaheadToken(number int) token { + return p.tokens[p.index+number] +} + +func (p *Parser) advance() { + p.index++ +} + +func tokensOneOf(elements []tokType, token tokType) bool { + for _, elem := range elements { + if elem == token { + return true + } + } + return false +} + +func (p *Parser) syntaxError(msg string) SyntaxError { + return SyntaxError{ + msg: msg, + Expression: p.expression, + Offset: p.lookaheadToken(0).position, + } +} + +// Create a SyntaxError based on the provided token. +// This differs from syntaxError() which creates a SyntaxError +// based on the current lookahead token. +func (p *Parser) syntaxErrorToken(msg string, t token) SyntaxError { + return SyntaxError{ + msg: msg, + Expression: p.expression, + Offset: t.position, + } +} diff --git a/vendor/github.com/jmespath/go-jmespath/toktype_string.go b/vendor/github.com/jmespath/go-jmespath/toktype_string.go new file mode 100644 index 000000000..dae79cbdf --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/toktype_string.go @@ -0,0 +1,16 @@ +// generated by stringer -type=tokType; DO NOT EDIT + +package jmespath + +import "fmt" + +const _tokType_name = "tUnknowntStartDottFiltertFlattentLparentRparentLbrackettRbrackettLbracetRbracetOrtPipetNumbertUnquotedIdentifiertQuotedIdentifiertCommatColontLTtLTEtGTtGTEtEQtNEtJSONLiteraltStringLiteraltCurrenttExpreftAndtNottEOF" + +var _tokType_index = [...]uint8{0, 8, 13, 17, 24, 32, 39, 46, 55, 64, 71, 78, 81, 86, 93, 112, 129, 135, 141, 144, 148, 151, 155, 158, 161, 173, 187, 195, 202, 206, 210, 214} + +func (i tokType) String() string { + if i < 0 || i >= tokType(len(_tokType_index)-1) { + return fmt.Sprintf("tokType(%d)", i) + } + return _tokType_name[_tokType_index[i]:_tokType_index[i+1]] +} diff --git a/vendor/github.com/jmespath/go-jmespath/util.go b/vendor/github.com/jmespath/go-jmespath/util.go new file mode 100644 index 000000000..ddc1b7d7d --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/util.go @@ -0,0 +1,185 @@ +package jmespath + +import ( + "errors" + "reflect" +) + +// IsFalse determines if an object is false based on the JMESPath spec. +// JMESPath defines false values to be any of: +// - An empty string array, or hash. +// - The boolean value false. +// - nil +func isFalse(value interface{}) bool { + switch v := value.(type) { + case bool: + return !v + case []interface{}: + return len(v) == 0 + case map[string]interface{}: + return len(v) == 0 + case string: + return len(v) == 0 + case nil: + return true + } + // Try the reflection cases before returning false. + rv := reflect.ValueOf(value) + switch rv.Kind() { + case reflect.Struct: + // A struct type will never be false, even if + // all of its values are the zero type. + return false + case reflect.Slice, reflect.Map: + return rv.Len() == 0 + case reflect.Ptr: + if rv.IsNil() { + return true + } + // If it's a pointer type, we'll try to deref the pointer + // and evaluate the pointer value for isFalse. + element := rv.Elem() + return isFalse(element.Interface()) + } + return false +} + +// ObjsEqual is a generic object equality check. +// It will take two arbitrary objects and recursively determine +// if they are equal. +func objsEqual(left interface{}, right interface{}) bool { + return reflect.DeepEqual(left, right) +} + +// SliceParam refers to a single part of a slice. +// A slice consists of a start, a stop, and a step, similar to +// python slices. +type sliceParam struct { + N int + Specified bool +} + +// Slice supports [start:stop:step] style slicing that's supported in JMESPath. +func slice(slice []interface{}, parts []sliceParam) ([]interface{}, error) { + computed, err := computeSliceParams(len(slice), parts) + if err != nil { + return nil, err + } + start, stop, step := computed[0], computed[1], computed[2] + result := []interface{}{} + if step > 0 { + for i := start; i < stop; i += step { + result = append(result, slice[i]) + } + } else { + for i := start; i > stop; i += step { + result = append(result, slice[i]) + } + } + return result, nil +} + +func computeSliceParams(length int, parts []sliceParam) ([]int, error) { + var start, stop, step int + if !parts[2].Specified { + step = 1 + } else if parts[2].N == 0 { + return nil, errors.New("Invalid slice, step cannot be 0") + } else { + step = parts[2].N + } + var stepValueNegative bool + if step < 0 { + stepValueNegative = true + } else { + stepValueNegative = false + } + + if !parts[0].Specified { + if stepValueNegative { + start = length - 1 + } else { + start = 0 + } + } else { + start = capSlice(length, parts[0].N, step) + } + + if !parts[1].Specified { + if stepValueNegative { + stop = -1 + } else { + stop = length + } + } else { + stop = capSlice(length, parts[1].N, step) + } + return []int{start, stop, step}, nil +} + +func capSlice(length int, actual int, step int) int { + if actual < 0 { + actual += length + if actual < 0 { + if step < 0 { + actual = -1 + } else { + actual = 0 + } + } + } else if actual >= length { + if step < 0 { + actual = length - 1 + } else { + actual = length + } + } + return actual +} + +// ToArrayNum converts an empty interface type to a slice of float64. +// If any element in the array cannot be converted, then nil is returned +// along with a second value of false. +func toArrayNum(data interface{}) ([]float64, bool) { + // Is there a better way to do this with reflect? + if d, ok := data.([]interface{}); ok { + result := make([]float64, len(d)) + for i, el := range d { + item, ok := el.(float64) + if !ok { + return nil, false + } + result[i] = item + } + return result, true + } + return nil, false +} + +// ToArrayStr converts an empty interface type to a slice of strings. +// If any element in the array cannot be converted, then nil is returned +// along with a second value of false. If the input data could be entirely +// converted, then the converted data, along with a second value of true, +// will be returned. +func toArrayStr(data interface{}) ([]string, bool) { + // Is there a better way to do this with reflect? + if d, ok := data.([]interface{}); ok { + result := make([]string, len(d)) + for i, el := range d { + item, ok := el.(string) + if !ok { + return nil, false + } + result[i] = item + } + return result, true + } + return nil, false +} + +func isSliceType(v interface{}) bool { + if v == nil { + return false + } + return reflect.TypeOf(v).Kind() == reflect.Slice +} diff --git a/vendor/github.com/satori/go.uuid/LICENSE b/vendor/github.com/satori/go.uuid/LICENSE new file mode 100644 index 000000000..488357b8a --- /dev/null +++ b/vendor/github.com/satori/go.uuid/LICENSE @@ -0,0 +1,20 @@ +Copyright (C) 2013-2016 by Maxim Bublis + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/satori/go.uuid/README.md b/vendor/github.com/satori/go.uuid/README.md new file mode 100644 index 000000000..b6aad1c81 --- /dev/null +++ b/vendor/github.com/satori/go.uuid/README.md @@ -0,0 +1,65 @@ +# UUID package for Go language + +[![Build Status](https://travis-ci.org/satori/go.uuid.png?branch=master)](https://travis-ci.org/satori/go.uuid) +[![Coverage Status](https://coveralls.io/repos/github/satori/go.uuid/badge.svg?branch=master)](https://coveralls.io/github/satori/go.uuid) +[![GoDoc](http://godoc.org/github.com/satori/go.uuid?status.png)](http://godoc.org/github.com/satori/go.uuid) + +This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs. + +With 100% test coverage and benchmarks out of box. + +Supported versions: +* Version 1, based on timestamp and MAC address (RFC 4122) +* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1) +* Version 3, based on MD5 hashing (RFC 4122) +* Version 4, based on random numbers (RFC 4122) +* Version 5, based on SHA-1 hashing (RFC 4122) + +## Installation + +Use the `go` command: + + $ go get github.com/satori/go.uuid + +## Requirements + +UUID package requires Go >= 1.2. + +## Example + +```go +package main + +import ( + "fmt" + "github.com/satori/go.uuid" +) + +func main() { + // Creating UUID Version 4 + u1 := uuid.NewV4() + fmt.Printf("UUIDv4: %s\n", u1) + + // Parsing UUID from string input + u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + if err != nil { + fmt.Printf("Something gone wrong: %s", err) + } + fmt.Printf("Successfully parsed: %s", u2) +} +``` + +## Documentation + +[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project. + +## Links +* [RFC 4122](http://tools.ietf.org/html/rfc4122) +* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01) + +## Copyright + +Copyright (C) 2013-2016 by Maxim Bublis . + +UUID package released under MIT License. +See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details. diff --git a/vendor/github.com/satori/go.uuid/uuid.go b/vendor/github.com/satori/go.uuid/uuid.go new file mode 100644 index 000000000..295f3fc2c --- /dev/null +++ b/vendor/github.com/satori/go.uuid/uuid.go @@ -0,0 +1,481 @@ +// Copyright (C) 2013-2015 by Maxim Bublis +// +// 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. + +// Package uuid provides implementation of Universally Unique Identifier (UUID). +// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and +// version 2 (as specified in DCE 1.1). +package uuid + +import ( + "bytes" + "crypto/md5" + "crypto/rand" + "crypto/sha1" + "database/sql/driver" + "encoding/binary" + "encoding/hex" + "fmt" + "hash" + "net" + "os" + "sync" + "time" +) + +// UUID layout variants. +const ( + VariantNCS = iota + VariantRFC4122 + VariantMicrosoft + VariantFuture +) + +// UUID DCE domains. +const ( + DomainPerson = iota + DomainGroup + DomainOrg +) + +// Difference in 100-nanosecond intervals between +// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970). +const epochStart = 122192928000000000 + +// Used in string method conversion +const dash byte = '-' + +// UUID v1/v2 storage. +var ( + storageMutex sync.Mutex + storageOnce sync.Once + epochFunc = unixTimeFunc + clockSequence uint16 + lastTime uint64 + hardwareAddr [6]byte + posixUID = uint32(os.Getuid()) + posixGID = uint32(os.Getgid()) +) + +// String parse helpers. +var ( + urnPrefix = []byte("urn:uuid:") + byteGroups = []int{8, 4, 4, 4, 12} +) + +func initClockSequence() { + buf := make([]byte, 2) + safeRandom(buf) + clockSequence = binary.BigEndian.Uint16(buf) +} + +func initHardwareAddr() { + interfaces, err := net.Interfaces() + if err == nil { + for _, iface := range interfaces { + if len(iface.HardwareAddr) >= 6 { + copy(hardwareAddr[:], iface.HardwareAddr) + return + } + } + } + + // Initialize hardwareAddr randomly in case + // of real network interfaces absence + safeRandom(hardwareAddr[:]) + + // Set multicast bit as recommended in RFC 4122 + hardwareAddr[0] |= 0x01 +} + +func initStorage() { + initClockSequence() + initHardwareAddr() +} + +func safeRandom(dest []byte) { + if _, err := rand.Read(dest); err != nil { + panic(err) + } +} + +// Returns difference in 100-nanosecond intervals between +// UUID epoch (October 15, 1582) and current time. +// This is default epoch calculation function. +func unixTimeFunc() uint64 { + return epochStart + uint64(time.Now().UnixNano()/100) +} + +// UUID representation compliant with specification +// described in RFC 4122. +type UUID [16]byte + +// NullUUID can be used with the standard sql package to represent a +// UUID value that can be NULL in the database +type NullUUID struct { + UUID UUID + Valid bool +} + +// The nil UUID is special form of UUID that is specified to have all +// 128 bits set to zero. +var Nil = UUID{} + +// Predefined namespace UUIDs. +var ( + NamespaceDNS, _ = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + NamespaceURL, _ = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8") + NamespaceOID, _ = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8") + NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8") +) + +// And returns result of binary AND of two UUIDs. +func And(u1 UUID, u2 UUID) UUID { + u := UUID{} + for i := 0; i < 16; i++ { + u[i] = u1[i] & u2[i] + } + return u +} + +// Or returns result of binary OR of two UUIDs. +func Or(u1 UUID, u2 UUID) UUID { + u := UUID{} + for i := 0; i < 16; i++ { + u[i] = u1[i] | u2[i] + } + return u +} + +// Equal returns true if u1 and u2 equals, otherwise returns false. +func Equal(u1 UUID, u2 UUID) bool { + return bytes.Equal(u1[:], u2[:]) +} + +// Version returns algorithm version used to generate UUID. +func (u UUID) Version() uint { + return uint(u[6] >> 4) +} + +// Variant returns UUID layout variant. +func (u UUID) Variant() uint { + switch { + case (u[8] & 0x80) == 0x00: + return VariantNCS + case (u[8]&0xc0)|0x80 == 0x80: + return VariantRFC4122 + case (u[8]&0xe0)|0xc0 == 0xc0: + return VariantMicrosoft + } + return VariantFuture +} + +// Bytes returns bytes slice representation of UUID. +func (u UUID) Bytes() []byte { + return u[:] +} + +// Returns canonical string representation of UUID: +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. +func (u UUID) String() string { + buf := make([]byte, 36) + + hex.Encode(buf[0:8], u[0:4]) + buf[8] = dash + hex.Encode(buf[9:13], u[4:6]) + buf[13] = dash + hex.Encode(buf[14:18], u[6:8]) + buf[18] = dash + hex.Encode(buf[19:23], u[8:10]) + buf[23] = dash + hex.Encode(buf[24:], u[10:]) + + return string(buf) +} + +// SetVersion sets version bits. +func (u *UUID) SetVersion(v byte) { + u[6] = (u[6] & 0x0f) | (v << 4) +} + +// SetVariant sets variant bits as described in RFC 4122. +func (u *UUID) SetVariant() { + u[8] = (u[8] & 0xbf) | 0x80 +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The encoding is the same as returned by String. +func (u UUID) MarshalText() (text []byte, err error) { + text = []byte(u.String()) + return +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// Following formats are supported: +// "6ba7b810-9dad-11d1-80b4-00c04fd430c8", +// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", +// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" +func (u *UUID) UnmarshalText(text []byte) (err error) { + if len(text) < 32 { + err = fmt.Errorf("uuid: UUID string too short: %s", text) + return + } + + t := text[:] + braced := false + + if bytes.Equal(t[:9], urnPrefix) { + t = t[9:] + } else if t[0] == '{' { + braced = true + t = t[1:] + } + + b := u[:] + + for i, byteGroup := range byteGroups { + if i > 0 { + if t[0] != '-' { + err = fmt.Errorf("uuid: invalid string format") + return + } + t = t[1:] + } + + if len(t) < byteGroup { + err = fmt.Errorf("uuid: UUID string too short: %s", text) + return + } + + if i == 4 && len(t) > byteGroup && + ((braced && t[byteGroup] != '}') || len(t[byteGroup:]) > 1 || !braced) { + err = fmt.Errorf("uuid: UUID string too long: %s", text) + return + } + + _, err = hex.Decode(b[:byteGroup/2], t[:byteGroup]) + if err != nil { + return + } + + t = t[byteGroup:] + b = b[byteGroup/2:] + } + + return +} + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (u UUID) MarshalBinary() (data []byte, err error) { + data = u.Bytes() + return +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. +// It will return error if the slice isn't 16 bytes long. +func (u *UUID) UnmarshalBinary(data []byte) (err error) { + if len(data) != 16 { + err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data)) + return + } + copy(u[:], data) + + return +} + +// Value implements the driver.Valuer interface. +func (u UUID) Value() (driver.Value, error) { + return u.String(), nil +} + +// Scan implements the sql.Scanner interface. +// A 16-byte slice is handled by UnmarshalBinary, while +// a longer byte slice or a string is handled by UnmarshalText. +func (u *UUID) Scan(src interface{}) error { + switch src := src.(type) { + case []byte: + if len(src) == 16 { + return u.UnmarshalBinary(src) + } + return u.UnmarshalText(src) + + case string: + return u.UnmarshalText([]byte(src)) + } + + return fmt.Errorf("uuid: cannot convert %T to UUID", src) +} + +// Value implements the driver.Valuer interface. +func (u NullUUID) Value() (driver.Value, error) { + if !u.Valid { + return nil, nil + } + // Delegate to UUID Value function + return u.UUID.Value() +} + +// Scan implements the sql.Scanner interface. +func (u *NullUUID) Scan(src interface{}) error { + if src == nil { + u.UUID, u.Valid = Nil, false + return nil + } + + // Delegate to UUID Scan function + u.Valid = true + return u.UUID.Scan(src) +} + +// FromBytes returns UUID converted from raw byte slice input. +// It will return error if the slice isn't 16 bytes long. +func FromBytes(input []byte) (u UUID, err error) { + err = u.UnmarshalBinary(input) + return +} + +// FromBytesOrNil returns UUID converted from raw byte slice input. +// Same behavior as FromBytes, but returns a Nil UUID on error. +func FromBytesOrNil(input []byte) UUID { + uuid, err := FromBytes(input) + if err != nil { + return Nil + } + return uuid +} + +// FromString returns UUID parsed from string input. +// Input is expected in a form accepted by UnmarshalText. +func FromString(input string) (u UUID, err error) { + err = u.UnmarshalText([]byte(input)) + return +} + +// FromStringOrNil returns UUID parsed from string input. +// Same behavior as FromString, but returns a Nil UUID on error. +func FromStringOrNil(input string) UUID { + uuid, err := FromString(input) + if err != nil { + return Nil + } + return uuid +} + +// Returns UUID v1/v2 storage state. +// Returns epoch timestamp, clock sequence, and hardware address. +func getStorage() (uint64, uint16, []byte) { + storageOnce.Do(initStorage) + + storageMutex.Lock() + defer storageMutex.Unlock() + + timeNow := epochFunc() + // Clock changed backwards since last UUID generation. + // Should increase clock sequence. + if timeNow <= lastTime { + clockSequence++ + } + lastTime = timeNow + + return timeNow, clockSequence, hardwareAddr[:] +} + +// NewV1 returns UUID based on current timestamp and MAC address. +func NewV1() UUID { + u := UUID{} + + timeNow, clockSeq, hardwareAddr := getStorage() + + binary.BigEndian.PutUint32(u[0:], uint32(timeNow)) + binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) + binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) + binary.BigEndian.PutUint16(u[8:], clockSeq) + + copy(u[10:], hardwareAddr) + + u.SetVersion(1) + u.SetVariant() + + return u +} + +// NewV2 returns DCE Security UUID based on POSIX UID/GID. +func NewV2(domain byte) UUID { + u := UUID{} + + timeNow, clockSeq, hardwareAddr := getStorage() + + switch domain { + case DomainPerson: + binary.BigEndian.PutUint32(u[0:], posixUID) + case DomainGroup: + binary.BigEndian.PutUint32(u[0:], posixGID) + } + + binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) + binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) + binary.BigEndian.PutUint16(u[8:], clockSeq) + u[9] = domain + + copy(u[10:], hardwareAddr) + + u.SetVersion(2) + u.SetVariant() + + return u +} + +// NewV3 returns UUID based on MD5 hash of namespace UUID and name. +func NewV3(ns UUID, name string) UUID { + u := newFromHash(md5.New(), ns, name) + u.SetVersion(3) + u.SetVariant() + + return u +} + +// NewV4 returns random generated UUID. +func NewV4() UUID { + u := UUID{} + safeRandom(u[:]) + u.SetVersion(4) + u.SetVariant() + + return u +} + +// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name. +func NewV5(ns UUID, name string) UUID { + u := newFromHash(sha1.New(), ns, name) + u.SetVersion(5) + u.SetVariant() + + return u +} + +// Returns UUID based on hashing of namespace UUID and name. +func newFromHash(h hash.Hash, ns UUID, name string) UUID { + u := UUID{} + h.Write(ns[:]) + h.Write([]byte(name)) + copy(u[:], h.Sum(nil)) + + return u +} diff --git a/vendor/github.com/spf13/cobra/LICENSE.txt b/vendor/github.com/spf13/cobra/LICENSE.txt new file mode 100644 index 000000000..298f0e266 --- /dev/null +++ b/vendor/github.com/spf13/cobra/LICENSE.txt @@ -0,0 +1,174 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md new file mode 100644 index 000000000..2de984012 --- /dev/null +++ b/vendor/github.com/spf13/cobra/README.md @@ -0,0 +1,910 @@ +![cobra logo](https://cloud.githubusercontent.com/assets/173412/10886352/ad566232-814f-11e5-9cd0-aa101788c117.png) + +Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. + +Many of the most widely used Go projects are built using Cobra including: + +* [Kubernetes](http://kubernetes.io/) +* [Hugo](http://gohugo.io) +* [rkt](https://github.com/coreos/rkt) +* [etcd](https://github.com/coreos/etcd) +* [Docker](https://github.com/docker/docker) +* [Docker (distribution)](https://github.com/docker/distribution) +* [OpenShift](https://www.openshift.com/) +* [Delve](https://github.com/derekparker/delve) +* [GopherJS](http://www.gopherjs.org/) +* [CockroachDB](http://www.cockroachlabs.com/) +* [Bleve](http://www.blevesearch.com/) +* [ProjectAtomic (enterprise)](http://www.projectatomic.io/) +* [Parse (CLI)](https://parse.com/) +* [GiantSwarm's swarm](https://github.com/giantswarm/cli) +* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) + + +[![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra) +[![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra) +[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra) + +![cobra](https://cloud.githubusercontent.com/assets/173412/10911369/84832a8e-8212-11e5-9f82-cc96660a4794.gif) + +# Overview + +Cobra is a library providing a simple interface to create powerful modern CLI +interfaces similar to git & go tools. + +Cobra is also an application that will generate your application scaffolding to rapidly +develop a Cobra-based application. + +Cobra provides: +* Easy subcommand-based CLIs: `app server`, `app fetch`, etc. +* Fully POSIX-compliant flags (including short & long versions) +* Nested subcommands +* Global, local and cascading flags +* Easy generation of applications & commands with `cobra create appname` & `cobra add cmdname` +* Intelligent suggestions (`app srver`... did you mean `app server`?) +* Automatic help generation for commands and flags +* Automatic detailed help for `app help [command]` +* Automatic help flag recognition of `-h`, `--help`, etc. +* Automatically generated bash autocomplete for your application +* Automatically generated man pages for your application +* Command aliases so you can change things without breaking them +* The flexibilty to define your own help, usage, etc. +* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps + +Cobra has an exceptionally clean interface and simple design without needless +constructors or initialization methods. + +Applications built with Cobra commands are designed to be as user-friendly as +possible. Flags can be placed before or after the command (as long as a +confusing space isn’t provided). Both short and long flags can be used. A +command need not even be fully typed. Help is automatically generated and +available for the application or for a specific command using either the help +command or the `--help` flag. + +# Concepts + +Cobra is built on a structure of commands, arguments & flags. + +**Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions. + +The best applications will read like sentences when used. Users will know how +to use the application because they will natively understand how to use it. + +The pattern to follow is +`APPNAME VERB NOUN --ADJECTIVE.` + or +`APPNAME COMMAND ARG --FLAG` + +A few good real world examples may better illustrate this point. + +In the following example, 'server' is a command, and 'port' is a flag: + + > hugo server --port=1313 + +In this command we are telling Git to clone the url bare. + + > git clone URL --bare + +## Commands + +Command is the central point of the application. Each interaction that +the application supports will be contained in a Command. A command can +have children commands and optionally run an action. + +In the example above, 'server' is the command. + +A Command has the following structure: + +```go +type Command struct { + Use string // The one-line usage message. + Short string // The short description shown in the 'help' output. + Long string // The long message shown in the 'help ' output. + Run func(cmd *Command, args []string) // Run runs the command. +} +``` + +## Flags + +A Flag is a way to modify the behavior of a command. Cobra supports +fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/). +A Cobra command can define flags that persist through to children commands +and flags that are only available to that command. + +In the example above, 'port' is the flag. + +Flag functionality is provided by the [pflag +library](https://github.com/ogier/pflag), a fork of the flag standard library +which maintains the same interface while adding POSIX compliance. + +## Usage + +Cobra works by creating a set of commands and then organizing them into a tree. +The tree defines the structure of the application. + +Once each command is defined with its corresponding flags, then the +tree is assigned to the commander which is finally executed. + +# Installing +Using Cobra is easy. First, use `go get` to install the latest version +of the library. This command will install the `cobra` generator executible +along with the library: + + > go get -v github.com/spf13/cobra/cobra + +Next, include Cobra in your application: + +```go +import "github.com/spf13/cobra" +``` + +# Getting Started + +While you are welcome to provide your own organization, typically a Cobra based +application will follow the following organizational structure. + +``` + ▾ appName/ + ▾ cmd/ + add.go + your.go + commands.go + here.go + main.go +``` + +In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. + +```go +package main + +import ( + "fmt" + "os" + + "{pathToYourApp}/cmd" +) + +func main() { + if err := cmd.RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(-1) + } +} +``` + +## Using the Cobra Generator + +Cobra provides its own program that will create your application and add any +commands you want. It's the easiest way to incorporate Cobra into your application. + +In order to use the cobra command, compile it using the following command: + + > go install github.com/spf13/cobra/cobra + +This will create the cobra executable under your go path bin directory! + +### cobra init + +The `cobra init [yourApp]` command will create your initial application code +for you. It is a very powerful application that will populate your program with +the right structure so you can immediately enjoy all the benefits of Cobra. It +will also automatically apply the license you specify to your application. + +Cobra init is pretty smart. You can provide it a full path, or simply a path +similar to what is expected in the import. + +``` +cobra init github.com/spf13/newAppName +``` + +### cobra add + +Once an application is initialized Cobra can create additional commands for you. +Let's say you created an app and you wanted the following commands for it: + +* app serve +* app config +* app config create + +In your project directory (where your main.go file is) you would run the following: + +``` +cobra add serve +cobra add config +cobra add create -p 'configCmd' +``` + +Once you have run these three commands you would have an app structure that would look like: + +``` + ▾ app/ + ▾ cmd/ + serve.go + config.go + create.go + main.go +``` + +at this point you can run `go run main.go` and it would run your app. `go run +main.go serve`, `go run main.go config`, `go run main.go config create` along +with `go run main.go help serve`, etc would all work. + +Obviously you haven't added your own code to these yet, the commands are ready +for you to give them their tasks. Have fun. + +### Configuring the cobra generator + +The cobra generator will be easier to use if you provide a simple configuration +file which will help you eliminate providing a bunch of repeated information in +flags over and over. + +An example ~/.cobra.yaml file: + +```yaml +author: Steve Francia +license: MIT +``` + +You can specify no license by setting `license` to `none` or you can specify +a custom license: + +```yaml +license: + header: This file is part of {{ .appName }}. + text: | + {{ .copyright }} + + This is my license. There are many like it, but this one is mine. + My license is my best friend. It is my life. I must master it as I must + master my life. +``` + +## Manually implementing Cobra + +To manually implement cobra you need to create a bare main.go file and a RootCmd file. +You will optionally provide additional commands as you see fit. + +### Create the root command + +The root command represents your binary itself. + + +#### Manually create rootCmd + +Cobra doesn't require any special constructors. Simply create your commands. + +Ideally you place this in app/cmd/root.go: + +```go +var RootCmd = &cobra.Command{ + Use: "hugo", + Short: "Hugo is a very fast static site generator", + Long: `A Fast and Flexible Static Site Generator built with + love by spf13 and friends in Go. + Complete documentation is available at http://hugo.spf13.com`, + Run: func(cmd *cobra.Command, args []string) { + // Do Stuff Here + }, +} +``` + +You will additionally define flags and handle configuration in your init() function. + +for example cmd/root.go: + +```go +func init() { + cobra.OnInitialize(initConfig) + RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") + RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") + RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") + RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") + RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") + viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) + viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase")) + viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper")) + viper.SetDefault("author", "NAME HERE ") + viper.SetDefault("license", "apache") +} +``` + +### Create your main.go + +With the root command you need to have your main function execute it. +Execute should be run on the root for clarity, though it can be called on any command. + +In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. + +```go +package main + +import ( + "fmt" + "os" + + "{pathToYourApp}/cmd" +) + +func main() { + if err := cmd.RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(-1) + } +} +``` + + +### Create additional commands + +Additional commands can be defined and typically are each given their own file +inside of the cmd/ directory. + +If you wanted to create a version command you would create cmd/version.go and +populate it with the following: + +```go +package cmd + +import ( + "github.com/spf13/cobra" + "fmt" +) + +func init() { + RootCmd.AddCommand(versionCmd) +} + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the version number of Hugo", + Long: `All software has versions. This is Hugo's`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") + }, +} +``` + +### Attach command to its parent + + +If you notice in the above example we attach the command to its parent. In +this case the parent is the rootCmd. In this example we are attaching it to the +root, but commands can be attached at any level. + +```go +RootCmd.AddCommand(versionCmd) +``` + +### Remove a command from its parent + +Removing a command is not a common action in simple programs, but it allows 3rd +parties to customize an existing command tree. + +In this example, we remove the existing `VersionCmd` command of an existing +root command, and we replace it with our own version: + +```go +mainlib.RootCmd.RemoveCommand(mainlib.VersionCmd) +mainlib.RootCmd.AddCommand(versionCmd) +``` + +## Working with Flags + +Flags provide modifiers to control how the action command operates. + +### Assign flags to a command + +Since the flags are defined and used in different locations, we need to +define a variable outside with the correct scope to assign the flag to +work with. + +```go +var Verbose bool +var Source string +``` + +There are two different approaches to assign a flag. + +### Persistent Flags + +A flag can be 'persistent' meaning that this flag will be available to the +command it's assigned to as well as every command under that command. For +global flags, assign a flag as a persistent flag on the root. + +```go +RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") +``` + +### Local Flags + +A flag can also be assigned locally which will only apply to that specific command. + +```go +RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") +``` + + +## Example + +In the example below, we have defined three commands. Two are at the top level +and one (cmdTimes) is a child of one of the top commands. In this case the root +is not executable meaning that a subcommand is required. This is accomplished +by not providing a 'Run' for the 'rootCmd'. + +We have only defined one flag for a single command. + +More documentation about flags is available at https://github.com/spf13/pflag + +```go +package main + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" +) + +func main() { + + var echoTimes int + + var cmdPrint = &cobra.Command{ + Use: "print [string to print]", + Short: "Print anything to the screen", + Long: `print is for printing anything back to the screen. + For many years people have printed back to the screen. + `, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Print: " + strings.Join(args, " ")) + }, + } + + var cmdEcho = &cobra.Command{ + Use: "echo [string to echo]", + Short: "Echo anything to the screen", + Long: `echo is for echoing anything back. + Echo works a lot like print, except it has a child command. + `, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Print: " + strings.Join(args, " ")) + }, + } + + var cmdTimes = &cobra.Command{ + Use: "times [# times] [string to echo]", + Short: "Echo anything to the screen more times", + Long: `echo things multiple times back to the user by providing + a count and a string.`, + Run: func(cmd *cobra.Command, args []string) { + for i := 0; i < echoTimes; i++ { + fmt.Println("Echo: " + strings.Join(args, " ")) + } + }, + } + + cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") + + var rootCmd = &cobra.Command{Use: "app"} + rootCmd.AddCommand(cmdPrint, cmdEcho) + cmdEcho.AddCommand(cmdTimes) + rootCmd.Execute() +} +``` + +For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/). + +## The Help Command + +Cobra automatically adds a help command to your application when you have subcommands. +This will be called when a user runs 'app help'. Additionally, help will also +support all other commands as input. Say, for instance, you have a command called +'create' without any additional configuration; Cobra will work when 'app help +create' is called. Every command will automatically have the '--help' flag added. + +### Example + +The following output is automatically generated by Cobra. Nothing beyond the +command and flag definitions are needed. + + > hugo help + + hugo is the main command, used to build your Hugo site. + + Hugo is a Fast and Flexible Static Site Generator + built with love by spf13 and friends in Go. + + Complete documentation is available at http://gohugo.io/. + + Usage: + hugo [flags] + hugo [command] + + Available Commands: + server Hugo runs its own webserver to render the files + version Print the version number of Hugo + config Print the site configuration + check Check content in the source directory + benchmark Benchmark hugo by building a site a number of times. + convert Convert your content to different formats + new Create new content for your site + list Listing out various types of content + undraft Undraft changes the content's draft status from 'True' to 'False' + genautocomplete Generate shell autocompletion script for Hugo + gendoc Generate Markdown documentation for the Hugo CLI. + genman Generate man page for Hugo + import Import your site from others. + + Flags: + -b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/ + -D, --buildDrafts[=false]: include content marked as draft + -F, --buildFuture[=false]: include content with publishdate in the future + --cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/ + --canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL + --config="": config file (default is path/config.yaml|json|toml) + -d, --destination="": filesystem path to write files to + --disableRSS[=false]: Do not build RSS files + --disableSitemap[=false]: Do not build Sitemap file + --editor="": edit new content with this editor, if provided + --ignoreCache[=false]: Ignores the cache directory for reading but still writes to it + --log[=false]: Enable Logging + --logFile="": Log File path (if set, logging enabled automatically) + --noTimes[=false]: Don't sync modification time of files + --pluralizeListTitles[=true]: Pluralize titles in lists using inflect + --preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu") + -s, --source="": filesystem path to read files relative from + --stepAnalysis[=false]: display memory and timing of different steps of the program + -t, --theme="": theme to use (located in /themes/THEMENAME/) + --uglyURLs[=false]: if true, use /filename.html instead of /filename/ + -v, --verbose[=false]: verbose output + --verboseLog[=false]: verbose logging + -w, --watch[=false]: watch filesystem for changes and recreate as needed + + Use "hugo [command] --help" for more information about a command. + + +Help is just a command like any other. There is no special logic or behavior +around it. In fact, you can provide your own if you want. + +### Defining your own help + +You can provide your own Help command or your own template for the default command to use. + +The default help command is + +```go +func (c *Command) initHelp() { + if c.helpCommand == nil { + c.helpCommand = &Command{ + Use: "help [command]", + Short: "Help about any command", + Long: `Help provides help for any command in the application. + Simply type ` + c.Name() + ` help [path to command] for full details.`, + Run: c.HelpFunc(), + } + } + c.AddCommand(c.helpCommand) +} +``` + +You can provide your own command, function or template through the following methods: + +```go +command.SetHelpCommand(cmd *Command) + +command.SetHelpFunc(f func(*Command, []string)) + +command.SetHelpTemplate(s string) +``` + +The latter two will also apply to any children commands. + +## Usage + +When the user provides an invalid flag or invalid command, Cobra responds by +showing the user the 'usage'. + +### Example +You may recognize this from the help above. That's because the default help +embeds the usage as part of its output. + + Usage: + hugo [flags] + hugo [command] + + Available Commands: + server Hugo runs its own webserver to render the files + version Print the version number of Hugo + config Print the site configuration + check Check content in the source directory + benchmark Benchmark hugo by building a site a number of times. + convert Convert your content to different formats + new Create new content for your site + list Listing out various types of content + undraft Undraft changes the content's draft status from 'True' to 'False' + genautocomplete Generate shell autocompletion script for Hugo + gendoc Generate Markdown documentation for the Hugo CLI. + genman Generate man page for Hugo + import Import your site from others. + + Flags: + -b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/ + -D, --buildDrafts[=false]: include content marked as draft + -F, --buildFuture[=false]: include content with publishdate in the future + --cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/ + --canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL + --config="": config file (default is path/config.yaml|json|toml) + -d, --destination="": filesystem path to write files to + --disableRSS[=false]: Do not build RSS files + --disableSitemap[=false]: Do not build Sitemap file + --editor="": edit new content with this editor, if provided + --ignoreCache[=false]: Ignores the cache directory for reading but still writes to it + --log[=false]: Enable Logging + --logFile="": Log File path (if set, logging enabled automatically) + --noTimes[=false]: Don't sync modification time of files + --pluralizeListTitles[=true]: Pluralize titles in lists using inflect + --preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu") + -s, --source="": filesystem path to read files relative from + --stepAnalysis[=false]: display memory and timing of different steps of the program + -t, --theme="": theme to use (located in /themes/THEMENAME/) + --uglyURLs[=false]: if true, use /filename.html instead of /filename/ + -v, --verbose[=false]: verbose output + --verboseLog[=false]: verbose logging + -w, --watch[=false]: watch filesystem for changes and recreate as needed + +### Defining your own usage +You can provide your own usage function or template for Cobra to use. + +The default usage function is: + +```go +return func(c *Command) error { + err := tmpl(c.Out(), c.UsageTemplate(), c) + return err +} +``` + +Like help, the function and template are overridable through public methods: + +```go +command.SetUsageFunc(f func(*Command) error) + +command.SetUsageTemplate(s string) +``` + +## PreRun or PostRun Hooks + +It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: + +- `PersistentPreRun` +- `PreRun` +- `Run` +- `PostRun` +- `PersistentPostRun` + +An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`: + +```go +package main + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func main() { + + var rootCmd = &cobra.Command{ + Use: "root [sub]", + Short: "My root command", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) + }, + PreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd Run with args: %v\n", args) + }, + PostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) + }, + } + + var subCmd = &cobra.Command{ + Use: "sub [no options!]", + Short: "My subcommand", + PreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PreRun with args: %v\n", args) + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd Run with args: %v\n", args) + }, + PostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PostRun with args: %v\n", args) + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) + }, + } + + rootCmd.AddCommand(subCmd) + + rootCmd.SetArgs([]string{""}) + _ = rootCmd.Execute() + fmt.Print("\n") + rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) + _ = rootCmd.Execute() +} +``` + + +## Alternative Error Handling + +Cobra also has functions where the return signature is an error. This allows for errors to bubble up to the top, +providing a way to handle the errors in one location. The current list of functions that return an error is: + +* PersistentPreRunE +* PreRunE +* RunE +* PostRunE +* PersistentPostRunE + +If you would like to silence the default `error` and `usage` output in favor of your own, you can set `SilenceUsage` +and `SilenceErrors` to `true` on the command. A child command respects these flags if they are set on the parent +command. + +**Example Usage using RunE:** + +```go +package main + +import ( + "errors" + "log" + + "github.com/spf13/cobra" +) + +func main() { + var rootCmd = &cobra.Command{ + Use: "hugo", + Short: "Hugo is a very fast static site generator", + Long: `A Fast and Flexible Static Site Generator built with + love by spf13 and friends in Go. + Complete documentation is available at http://hugo.spf13.com`, + RunE: func(cmd *cobra.Command, args []string) error { + // Do Stuff Here + return errors.New("some random error") + }, + } + + if err := rootCmd.Execute(); err != nil { + log.Fatal(err) + } +} +``` + +## Suggestions when "unknown command" happens + +Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example: + +``` +$ hugo srever +Error: unknown command "srever" for "hugo" + +Did you mean this? + server + +Run 'hugo --help' for usage. +``` + +Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion. + +If you need to disable suggestions or tweak the string distance in your command, use: + +```go +command.DisableSuggestions = true +``` + +or + +```go +command.SuggestionsMinimumDistance = 1 +``` + +You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but makes sense in your set of commands and for some which you don't want aliases. Example: + +``` +$ kubectl remove +Error: unknown command "remove" for "kubectl" + +Did you mean this? + delete + +Run 'kubectl help' for usage. +``` + +## Generating Markdown-formatted documentation for your command + +Cobra can generate a Markdown-formatted document based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Markdown Docs](doc/md_docs.md). + +## Generating man pages for your command + +Cobra can generate a man page based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Man Docs](doc/man_docs.md). + +## Generating bash completions for your command + +Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md). + +## Debugging + +Cobra provides a ‘DebugFlags’ method on a command which, when called, will print +out everything Cobra knows about the flags for each command. + +### Example + +```go +command.DebugFlags() +``` + +## Release Notes +* **0.9.0** June 17, 2014 + * flags can appears anywhere in the args (provided they are unambiguous) + * --help prints usage screen for app or command + * Prefix matching for commands + * Cleaner looking help and usage output + * Extensive test suite +* **0.8.0** Nov 5, 2013 + * Reworked interface to remove commander completely + * Command now primary structure + * No initialization needed + * Usage & Help templates & functions definable at any level + * Updated Readme +* **0.7.0** Sept 24, 2013 + * Needs more eyes + * Test suite + * Support for automatic error messages + * Support for help command + * Support for printing to any io.Writer instead of os.Stderr + * Support for persistent flags which cascade down tree + * Ready for integration into Hugo +* **0.1.0** Sept 3, 2013 + * Implement first draft + +## Extensions + +Libraries for extending Cobra: + +* [cmdns](https://github.com/gosuri/cmdns): Enables name spacing a command's immediate children. It provides an alternative way to structure subcommands, similar to `heroku apps:create` and `ovrclk clusters:launch`. + +## ToDo +* Launch proper documentation site + +## Contributing + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request + +## Contributors + +Names in no particular order: + +* [spf13](https://github.com/spf13), +[eparis](https://github.com/eparis), +[bep](https://github.com/bep), and many more! + +## License + +Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt) + + +[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/spf13/cobra/trend.png)](https://bitdeli.com/free "Bitdeli Badge") diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go new file mode 100644 index 000000000..8820ba8fc --- /dev/null +++ b/vendor/github.com/spf13/cobra/bash_completions.go @@ -0,0 +1,645 @@ +package cobra + +import ( + "fmt" + "io" + "os" + "sort" + "strings" + + "github.com/spf13/pflag" +) + +// Annotations for Bash completion. +const ( + BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions" + BashCompCustom = "cobra_annotation_bash_completion_custom" + BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag" + BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir" +) + +func preamble(out io.Writer, name string) error { + _, err := fmt.Fprintf(out, "# bash completion for %-36s -*- shell-script -*-\n", name) + if err != nil { + return err + } + preamStr := ` +__debug() +{ + if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" + fi +} + +# Homebrew on Macs have version 1.3 of bash-completion which doesn't include +# _init_completion. This is a very minimal version of that function. +__my_init_completion() +{ + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} + +__index_of_word() +{ + local w word=$1 + shift + index=0 + for w in "$@"; do + [[ $w = "$word" ]] && return + index=$((index+1)) + done + index=-1 +} + +__contains_word() +{ + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done + return 1 +} + +__handle_reply() +{ + __debug "${FUNCNAME[0]}" + case $cur in + -*) + if [[ $(type -t compopt) = "builtin" ]]; then + compopt -o nospace + fi + local allflags + if [ ${#must_have_one_flag[@]} -ne 0 ]; then + allflags=("${must_have_one_flag[@]}") + else + allflags=("${flags[*]} ${two_word_flags[*]}") + fi + COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) + if [[ $(type -t compopt) = "builtin" ]]; then + [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace + fi + + # complete after --flag=abc + if [[ $cur == *=* ]]; then + if [[ $(type -t compopt) = "builtin" ]]; then + compopt +o nospace + fi + + local index flag + flag="${cur%%=*}" + __index_of_word "${flag}" "${flags_with_completion[@]}" + if [[ ${index} -ge 0 ]]; then + COMPREPLY=() + PREFIX="" + cur="${cur#*=}" + ${flags_completion[${index}]} + if [ -n "${ZSH_VERSION}" ]; then + # zfs completion needs --flag= prefix + eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" + fi + fi + fi + return 0; + ;; + esac + + # check if we are handling a flag with special work handling + local index + __index_of_word "${prev}" "${flags_with_completion[@]}" + if [[ ${index} -ge 0 ]]; then + ${flags_completion[${index}]} + return + fi + + # we are parsing a flag and don't have a special handler, no completion + if [[ ${cur} != "${words[cword]}" ]]; then + return + fi + + local completions + completions=("${commands[@]}") + if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then + completions=("${must_have_one_noun[@]}") + fi + if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then + completions+=("${must_have_one_flag[@]}") + fi + COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) + + if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then + COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) + fi + + if [[ ${#COMPREPLY[@]} -eq 0 ]]; then + declare -F __custom_func >/dev/null && __custom_func + fi + + __ltrim_colon_completions "$cur" +} + +# The arguments should be in the form "ext1|ext2|extn" +__handle_filename_extension_flag() +{ + local ext="$1" + _filedir "@(${ext})" +} + +__handle_subdirs_in_dir_flag() +{ + local dir="$1" + pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 +} + +__handle_flag() +{ + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + # if a command required a flag, and we found it, unset must_have_one_flag() + local flagname=${words[c]} + local flagvalue + # if the word contained an = + if [[ ${words[c]} == *"="* ]]; then + flagvalue=${flagname#*=} # take in as flagvalue after the = + flagname=${flagname%%=*} # strip everything after the = + flagname="${flagname}=" # but put the = back + fi + __debug "${FUNCNAME[0]}: looking for ${flagname}" + if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then + must_have_one_flag=() + fi + + # if you set a flag which only applies to this command, don't show subcommands + if __contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then + commands=() + fi + + # keep flag value with flagname as flaghash + if [ -n "${flagvalue}" ] ; then + flaghash[${flagname}]=${flagvalue} + elif [ -n "${words[ $((c+1)) ]}" ] ; then + flaghash[${flagname}]=${words[ $((c+1)) ]} + else + flaghash[${flagname}]="true" # pad "true" for bool flag + fi + + # skip the argument to a two word flag + if __contains_word "${words[c]}" "${two_word_flags[@]}"; then + c=$((c+1)) + # if we are looking for a flags value, don't show commands + if [[ $c -eq $cword ]]; then + commands=() + fi + fi + + c=$((c+1)) + +} + +__handle_noun() +{ + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then + must_have_one_noun=() + elif __contains_word "${words[c]}" "${noun_aliases[@]}"; then + must_have_one_noun=() + fi + + nouns+=("${words[c]}") + c=$((c+1)) +} + +__handle_command() +{ + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + local next_command + if [[ -n ${last_command} ]]; then + next_command="_${last_command}_${words[c]//:/__}" + else + if [[ $c -eq 0 ]]; then + next_command="_$(basename "${words[c]//:/__}")" + else + next_command="_${words[c]//:/__}" + fi + fi + c=$((c+1)) + __debug "${FUNCNAME[0]}: looking for ${next_command}" + declare -F $next_command >/dev/null && $next_command +} + +__handle_word() +{ + if [[ $c -ge $cword ]]; then + __handle_reply + return + fi + __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + if [[ "${words[c]}" == -* ]]; then + __handle_flag + elif __contains_word "${words[c]}" "${commands[@]}"; then + __handle_command + elif [[ $c -eq 0 ]] && __contains_word "$(basename "${words[c]}")" "${commands[@]}"; then + __handle_command + else + __handle_noun + fi + __handle_word +} + +` + _, err = fmt.Fprint(out, preamStr) + return err +} + +func postscript(w io.Writer, name string) error { + name = strings.Replace(name, ":", "__", -1) + _, err := fmt.Fprintf(w, "__start_%s()\n", name) + if err != nil { + return err + } + _, err = fmt.Fprintf(w, `{ + local cur prev words cword + declare -A flaghash 2>/dev/null || : + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -s || return + else + __my_init_completion -n "=" || return + fi + + local c=0 + local flags=() + local two_word_flags=() + local local_nonpersistent_flags=() + local flags_with_completion=() + local flags_completion=() + local commands=("%s") + local must_have_one_flag=() + local must_have_one_noun=() + local last_command + local nouns=() + + __handle_word +} + +`, name) + if err != nil { + return err + } + _, err = fmt.Fprintf(w, `if [[ $(type -t compopt) = "builtin" ]]; then + complete -o default -F __start_%s %s +else + complete -o default -o nospace -F __start_%s %s +fi + +`, name, name, name, name) + if err != nil { + return err + } + _, err = fmt.Fprintf(w, "# ex: ts=4 sw=4 et filetype=sh\n") + return err +} + +func writeCommands(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " commands=()\n"); err != nil { + return err + } + for _, c := range cmd.Commands() { + if !c.IsAvailableCommand() || c == cmd.helpCommand { + continue + } + if _, err := fmt.Fprintf(w, " commands+=(%q)\n", c.Name()); err != nil { + return err + } + } + _, err := fmt.Fprintf(w, "\n") + return err +} + +func writeFlagHandler(name string, annotations map[string][]string, w io.Writer) error { + for key, value := range annotations { + switch key { + case BashCompFilenameExt: + _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) + if err != nil { + return err + } + + if len(value) > 0 { + ext := "__handle_filename_extension_flag " + strings.Join(value, "|") + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + } else { + ext := "_filedir" + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + } + if err != nil { + return err + } + case BashCompCustom: + _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) + if err != nil { + return err + } + if len(value) > 0 { + handlers := strings.Join(value, "; ") + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", handlers) + } else { + _, err = fmt.Fprintf(w, " flags_completion+=(:)\n") + } + if err != nil { + return err + } + case BashCompSubdirsInDir: + _, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name) + + if len(value) == 1 { + ext := "__handle_subdirs_in_dir_flag " + value[0] + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + } else { + ext := "_filedir -d" + _, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", ext) + } + if err != nil { + return err + } + } + } + return nil +} + +func writeShortFlag(flag *pflag.Flag, w io.Writer) error { + b := (len(flag.NoOptDefVal) > 0) + name := flag.Shorthand + format := " " + if !b { + format += "two_word_" + } + format += "flags+=(\"-%s\")\n" + if _, err := fmt.Fprintf(w, format, name); err != nil { + return err + } + return writeFlagHandler("-"+name, flag.Annotations, w) +} + +func writeFlag(flag *pflag.Flag, w io.Writer) error { + b := (len(flag.NoOptDefVal) > 0) + name := flag.Name + format := " flags+=(\"--%s" + if !b { + format += "=" + } + format += "\")\n" + if _, err := fmt.Fprintf(w, format, name); err != nil { + return err + } + return writeFlagHandler("--"+name, flag.Annotations, w) +} + +func writeLocalNonPersistentFlag(flag *pflag.Flag, w io.Writer) error { + b := (len(flag.NoOptDefVal) > 0) + name := flag.Name + format := " local_nonpersistent_flags+=(\"--%s" + if !b { + format += "=" + } + format += "\")\n" + _, err := fmt.Fprintf(w, format, name) + return err +} + +func writeFlags(cmd *Command, w io.Writer) error { + _, err := fmt.Fprintf(w, ` flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + +`) + if err != nil { + return err + } + localNonPersistentFlags := cmd.LocalNonPersistentFlags() + var visitErr error + cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { + if nonCompletableFlag(flag) { + return + } + if err := writeFlag(flag, w); err != nil { + visitErr = err + return + } + if len(flag.Shorthand) > 0 { + if err := writeShortFlag(flag, w); err != nil { + visitErr = err + return + } + } + if localNonPersistentFlags.Lookup(flag.Name) != nil { + if err := writeLocalNonPersistentFlag(flag, w); err != nil { + visitErr = err + return + } + } + }) + if visitErr != nil { + return visitErr + } + cmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { + if nonCompletableFlag(flag) { + return + } + if err := writeFlag(flag, w); err != nil { + visitErr = err + return + } + if len(flag.Shorthand) > 0 { + if err := writeShortFlag(flag, w); err != nil { + visitErr = err + return + } + } + }) + if visitErr != nil { + return visitErr + } + + _, err = fmt.Fprintf(w, "\n") + return err +} + +func writeRequiredFlag(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " must_have_one_flag=()\n"); err != nil { + return err + } + flags := cmd.NonInheritedFlags() + var visitErr error + flags.VisitAll(func(flag *pflag.Flag) { + if nonCompletableFlag(flag) { + return + } + for key := range flag.Annotations { + switch key { + case BashCompOneRequiredFlag: + format := " must_have_one_flag+=(\"--%s" + b := (flag.Value.Type() == "bool") + if !b { + format += "=" + } + format += "\")\n" + if _, err := fmt.Fprintf(w, format, flag.Name); err != nil { + visitErr = err + return + } + + if len(flag.Shorthand) > 0 { + if _, err := fmt.Fprintf(w, " must_have_one_flag+=(\"-%s\")\n", flag.Shorthand); err != nil { + visitErr = err + return + } + } + } + } + }) + return visitErr +} + +func writeRequiredNouns(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " must_have_one_noun=()\n"); err != nil { + return err + } + sort.Sort(sort.StringSlice(cmd.ValidArgs)) + for _, value := range cmd.ValidArgs { + if _, err := fmt.Fprintf(w, " must_have_one_noun+=(%q)\n", value); err != nil { + return err + } + } + return nil +} + +func writeArgAliases(cmd *Command, w io.Writer) error { + if _, err := fmt.Fprintf(w, " noun_aliases=()\n"); err != nil { + return err + } + sort.Sort(sort.StringSlice(cmd.ArgAliases)) + for _, value := range cmd.ArgAliases { + if _, err := fmt.Fprintf(w, " noun_aliases+=(%q)\n", value); err != nil { + return err + } + } + return nil +} + +func gen(cmd *Command, w io.Writer) error { + for _, c := range cmd.Commands() { + if !c.IsAvailableCommand() || c == cmd.helpCommand { + continue + } + if err := gen(c, w); err != nil { + return err + } + } + commandName := cmd.CommandPath() + commandName = strings.Replace(commandName, " ", "_", -1) + commandName = strings.Replace(commandName, ":", "__", -1) + if _, err := fmt.Fprintf(w, "_%s()\n{\n", commandName); err != nil { + return err + } + if _, err := fmt.Fprintf(w, " last_command=%q\n", commandName); err != nil { + return err + } + if err := writeCommands(cmd, w); err != nil { + return err + } + if err := writeFlags(cmd, w); err != nil { + return err + } + if err := writeRequiredFlag(cmd, w); err != nil { + return err + } + if err := writeRequiredNouns(cmd, w); err != nil { + return err + } + if err := writeArgAliases(cmd, w); err != nil { + return err + } + if _, err := fmt.Fprintf(w, "}\n\n"); err != nil { + return err + } + return nil +} + +// GenBashCompletion generates bash completion file and writes to the passed writer. +func (cmd *Command) GenBashCompletion(w io.Writer) error { + if err := preamble(w, cmd.Name()); err != nil { + return err + } + if len(cmd.BashCompletionFunction) > 0 { + if _, err := fmt.Fprintf(w, "%s\n", cmd.BashCompletionFunction); err != nil { + return err + } + } + if err := gen(cmd, w); err != nil { + return err + } + return postscript(w, cmd.Name()) +} + +func nonCompletableFlag(flag *pflag.Flag) bool { + return flag.Hidden || len(flag.Deprecated) > 0 +} + +// GenBashCompletionFile generates bash completion file. +func (cmd *Command) GenBashCompletionFile(filename string) error { + outFile, err := os.Create(filename) + if err != nil { + return err + } + defer outFile.Close() + + return cmd.GenBashCompletion(outFile) +} + +// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists. +func (cmd *Command) MarkFlagRequired(name string) error { + return MarkFlagRequired(cmd.Flags(), name) +} + +// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists. +func (cmd *Command) MarkPersistentFlagRequired(name string) error { + return MarkFlagRequired(cmd.PersistentFlags(), name) +} + +// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists. +func MarkFlagRequired(flags *pflag.FlagSet, name string) error { + return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) +} + +// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. +// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. +func (cmd *Command) MarkFlagFilename(name string, extensions ...string) error { + return MarkFlagFilename(cmd.Flags(), name, extensions...) +} + +// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. +// Generated bash autocompletion will call the bash function f for the flag. +func (cmd *Command) MarkFlagCustom(name string, f string) error { + return MarkFlagCustom(cmd.Flags(), name, f) +} + +// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists. +// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. +func (cmd *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { + return MarkFlagFilename(cmd.PersistentFlags(), name, extensions...) +} + +// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists. +// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. +func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error { + return flags.SetAnnotation(name, BashCompFilenameExt, extensions) +} + +// MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists. +// Generated bash autocompletion will call the bash function f for the flag. +func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error { + return flags.SetAnnotation(name, BashCompCustom, []string{f}) +} diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go new file mode 100644 index 000000000..9605b984c --- /dev/null +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -0,0 +1,174 @@ +// Copyright © 2013 Steve Francia . +// +// 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. + +// Commands similar to git, go tools and other modern CLI tools +// inspired by go, go-Commander, gh and subcommand + +package cobra + +import ( + "fmt" + "io" + "reflect" + "strconv" + "strings" + "text/template" + "unicode" +) + +var templateFuncs = template.FuncMap{ + "trim": strings.TrimSpace, + "trimRightSpace": trimRightSpace, + "appendIfNotPresent": appendIfNotPresent, + "rpad": rpad, + "gt": Gt, + "eq": Eq, +} + +var initializers []func() + +// EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing +// to automatically enable in CLI tools. +// Set this to true to enable it. +var EnablePrefixMatching = false + +// EnableCommandSorting controls sorting of the slice of commands, which is turned on by default. +// To disable sorting, set it to false. +var EnableCommandSorting = true + +// AddTemplateFunc adds a template function that's available to Usage and Help +// template generation. +func AddTemplateFunc(name string, tmplFunc interface{}) { + templateFuncs[name] = tmplFunc +} + +// AddTemplateFuncs adds multiple template functions availalble to Usage and +// Help template generation. +func AddTemplateFuncs(tmplFuncs template.FuncMap) { + for k, v := range tmplFuncs { + templateFuncs[k] = v + } +} + +// OnInitialize takes a series of func() arguments and appends them to a slice of func(). +func OnInitialize(y ...func()) { + initializers = append(initializers, y...) +} + +// Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans, +// Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as +// ints and then compared. +func Gt(a interface{}, b interface{}) bool { + var left, right int64 + av := reflect.ValueOf(a) + + switch av.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + left = int64(av.Len()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + left = av.Int() + case reflect.String: + left, _ = strconv.ParseInt(av.String(), 10, 64) + } + + bv := reflect.ValueOf(b) + + switch bv.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + right = int64(bv.Len()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + right = bv.Int() + case reflect.String: + right, _ = strconv.ParseInt(bv.String(), 10, 64) + } + + return left > right +} + +// Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic. +func Eq(a interface{}, b interface{}) bool { + av := reflect.ValueOf(a) + bv := reflect.ValueOf(b) + + switch av.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + panic("Eq called on unsupported type") + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return av.Int() == bv.Int() + case reflect.String: + return av.String() == bv.String() + } + return false +} + +func trimRightSpace(s string) string { + return strings.TrimRightFunc(s, unicode.IsSpace) +} + +// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s. +func appendIfNotPresent(s, stringToAppend string) string { + if strings.Contains(s, stringToAppend) { + return s + } + return s + " " + stringToAppend +} + +// rpad adds padding to the right of a string. +func rpad(s string, padding int) string { + template := fmt.Sprintf("%%-%ds", padding) + return fmt.Sprintf(template, s) +} + +// tmpl executes the given template text on data, writing the result to w. +func tmpl(w io.Writer, text string, data interface{}) error { + t := template.New("top") + t.Funcs(templateFuncs) + template.Must(t.Parse(text)) + return t.Execute(w, data) +} + +// ld compares two strings and returns the levenshtein distance between them. +func ld(s, t string, ignoreCase bool) int { + if ignoreCase { + s = strings.ToLower(s) + t = strings.ToLower(t) + } + d := make([][]int, len(s)+1) + for i := range d { + d[i] = make([]int, len(t)+1) + } + for i := range d { + d[i][0] = i + } + for j := range d[0] { + d[0][j] = j + } + for j := 1; j <= len(t); j++ { + for i := 1; i <= len(s); i++ { + if s[i-1] == t[j-1] { + d[i][j] = d[i-1][j-1] + } else { + min := d[i-1][j] + if d[i][j-1] < min { + min = d[i][j-1] + } + if d[i-1][j-1] < min { + min = d[i-1][j-1] + } + d[i][j] = min + 1 + } + } + + } + return d[len(s)][len(t)] +} diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go new file mode 100644 index 000000000..664bf5aa5 --- /dev/null +++ b/vendor/github.com/spf13/cobra/command.go @@ -0,0 +1,1306 @@ +// Copyright © 2013 Steve Francia . +// +// 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 cobra is a commander providing a simple interface to create powerful modern CLI interfaces. +//In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. +package cobra + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + + flag "github.com/spf13/pflag" +) + +// Command is just that, a command for your application. +// eg. 'go run' ... 'run' is the command. Cobra requires +// you to define the usage and description as part of your command +// definition to ensure usability. +type Command struct { + // Name is the command name, usually the executable's name. + name string + // The one-line usage message. + Use string + // An array of aliases that can be used instead of the first word in Use. + Aliases []string + // An array of command names for which this command will be suggested - similar to aliases but only suggests. + SuggestFor []string + // The short description shown in the 'help' output. + Short string + // The long message shown in the 'help ' output. + Long string + // Examples of how to use the command + Example string + // List of all valid non-flag arguments that are accepted in bash completions + ValidArgs []string + // List of aliases for ValidArgs. These are not suggested to the user in the bash + // completion, but accepted if entered manually. + ArgAliases []string + // Custom functions used by the bash autocompletion generator + BashCompletionFunction string + // Is this command deprecated and should print this string when used? + Deprecated string + // Is this command hidden and should NOT show up in the list of available commands? + Hidden bool + // Annotations are key/value pairs that can be used by applications to identify or + // group commands + Annotations map[string]string + // Full set of flags + flags *flag.FlagSet + // Set of flags childrens of this command will inherit + pflags *flag.FlagSet + // Flags that are declared specifically by this command (not inherited). + lflags *flag.FlagSet + // SilenceErrors is an option to quiet errors down stream + SilenceErrors bool + // Silence Usage is an option to silence usage when an error occurs. + SilenceUsage bool + // The *Run functions are executed in the following order: + // * PersistentPreRun() + // * PreRun() + // * Run() + // * PostRun() + // * PersistentPostRun() + // All functions get the same args, the arguments after the command name + // PersistentPreRun: children of this command will inherit and execute + PersistentPreRun func(cmd *Command, args []string) + // PersistentPreRunE: PersistentPreRun but returns an error + PersistentPreRunE func(cmd *Command, args []string) error + // PreRun: children of this command will not inherit. + PreRun func(cmd *Command, args []string) + // PreRunE: PreRun but returns an error + PreRunE func(cmd *Command, args []string) error + // Run: Typically the actual work function. Most commands will only implement this + Run func(cmd *Command, args []string) + // RunE: Run but returns an error + RunE func(cmd *Command, args []string) error + // PostRun: run after the Run command. + PostRun func(cmd *Command, args []string) + // PostRunE: PostRun but returns an error + PostRunE func(cmd *Command, args []string) error + // PersistentPostRun: children of this command will inherit and execute after PostRun + PersistentPostRun func(cmd *Command, args []string) + // PersistentPostRunE: PersistentPostRun but returns an error + PersistentPostRunE func(cmd *Command, args []string) error + // DisableAutoGenTag remove + DisableAutoGenTag bool + // Commands is the list of commands supported by this program. + commands []*Command + // Parent Command for this command + parent *Command + // max lengths of commands' string lengths for use in padding + commandsMaxUseLen int + commandsMaxCommandPathLen int + commandsMaxNameLen int + // is commands slice are sorted or not + commandsAreSorted bool + + flagErrorBuf *bytes.Buffer + + args []string // actual args parsed from flags + output *io.Writer // out writer if set in SetOutput(w) + usageFunc func(*Command) error // Usage can be defined by application + usageTemplate string // Can be defined by Application + flagErrorFunc func(*Command, error) error + helpTemplate string // Can be defined by Application + helpFunc func(*Command, []string) // Help can be defined by application + helpCommand *Command // The help command + // The global normalization function that we can use on every pFlag set and children commands + globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName + + // Disable the suggestions based on Levenshtein distance that go along with 'unknown command' messages + DisableSuggestions bool + // If displaying suggestions, allows to set the minimum levenshtein distance to display, must be > 0 + SuggestionsMinimumDistance int + + // Disable the flag parsing. If this is true all flags will be passed to the command as arguments. + DisableFlagParsing bool +} + +// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden +// particularly useful when testing. +func (c *Command) SetArgs(a []string) { + c.args = a +} + +// SetOutput sets the destination for usage and error messages. +// If output is nil, os.Stderr is used. +func (c *Command) SetOutput(output io.Writer) { + c.output = &output +} + +// SetUsageFunc sets usage function. Usage can be defined by application. +func (c *Command) SetUsageFunc(f func(*Command) error) { + c.usageFunc = f +} + +// SetUsageTemplate sets usage template. Can be defined by Application. +func (c *Command) SetUsageTemplate(s string) { + c.usageTemplate = s +} + +// SetFlagErrorFunc sets a function to generate an error when flag parsing +// fails. +func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) { + c.flagErrorFunc = f +} + +// SetHelpFunc sets help function. Can be defined by Application. +func (c *Command) SetHelpFunc(f func(*Command, []string)) { + c.helpFunc = f +} + +// SetHelpCommand sets help command. +func (c *Command) SetHelpCommand(cmd *Command) { + c.helpCommand = cmd +} + +// SetHelpTemplate sets help template to be used. Application can use it to set custom template. +func (c *Command) SetHelpTemplate(s string) { + c.helpTemplate = s +} + +// SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. +// The user should not have a cyclic dependency on commands. +func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) { + c.Flags().SetNormalizeFunc(n) + c.PersistentFlags().SetNormalizeFunc(n) + c.globNormFunc = n + + for _, command := range c.commands { + command.SetGlobalNormalizationFunc(n) + } +} + +// OutOrStdout returns output to stdout. +func (c *Command) OutOrStdout() io.Writer { + return c.getOut(os.Stdout) +} + +// OutOrStderr returns output to stderr +func (c *Command) OutOrStderr() io.Writer { + return c.getOut(os.Stderr) +} + +func (c *Command) getOut(def io.Writer) io.Writer { + if c.output != nil { + return *c.output + } + if c.HasParent() { + return c.parent.getOut(def) + } + return def +} + +// UsageFunc returns either the function set by SetUsageFunc for this command +// or a parent, or it returns a default usage function. +func (c *Command) UsageFunc() (f func(*Command) error) { + if c.usageFunc != nil { + return c.usageFunc + } + + if c.HasParent() { + return c.parent.UsageFunc() + } + return func(c *Command) error { + c.mergePersistentFlags() + err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) + if err != nil { + c.Println(err) + } + return err + } +} + +// Usage puts out the usage for the command. +// Used when a user provides invalid input. +// Can be defined by user by overriding UsageFunc. +func (c *Command) Usage() error { + return c.UsageFunc()(c) +} + +// HelpFunc returns either the function set by SetHelpFunc for this command +// or a parent, or it returns a function with default help behavior. +func (c *Command) HelpFunc() func(*Command, []string) { + if helpFunc := c.checkHelpFunc(); helpFunc != nil { + return helpFunc + } + return func(*Command, []string) { + c.mergePersistentFlags() + err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) + if err != nil { + c.Println(err) + } + } +} + +// checkHelpFunc checks if there is helpFunc in ancestors of c. +func (c *Command) checkHelpFunc() func(*Command, []string) { + if c == nil { + return nil + } + if c.helpFunc != nil { + return c.helpFunc + } + if c.HasParent() { + return c.parent.checkHelpFunc() + } + return nil +} + +// Help puts out the help for the command. +// Used when a user calls help [command]. +// Can be defined by user by overriding HelpFunc. +func (c *Command) Help() error { + c.HelpFunc()(c, []string{}) + return nil +} + +// UsageString return usage string. +func (c *Command) UsageString() string { + tmpOutput := c.output + bb := new(bytes.Buffer) + c.SetOutput(bb) + c.Usage() + c.output = tmpOutput + return bb.String() +} + +// FlagErrorFunc returns either the function set by SetFlagErrorFunc for this +// command or a parent, or it returns a function which returns the original +// error. +func (c *Command) FlagErrorFunc() (f func(*Command, error) error) { + if c.flagErrorFunc != nil { + return c.flagErrorFunc + } + + if c.HasParent() { + return c.parent.FlagErrorFunc() + } + return func(c *Command, err error) error { + return err + } +} + +var minUsagePadding = 25 + +// UsagePadding return padding for the usage. +func (c *Command) UsagePadding() int { + if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { + return minUsagePadding + } + return c.parent.commandsMaxUseLen +} + +var minCommandPathPadding = 11 + +// CommandPathPadding return padding for the command path. +func (c *Command) CommandPathPadding() int { + if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen { + return minCommandPathPadding + } + return c.parent.commandsMaxCommandPathLen +} + +var minNamePadding = 11 + +// NamePadding returns padding for the name. +func (c *Command) NamePadding() int { + if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { + return minNamePadding + } + return c.parent.commandsMaxNameLen +} + +// UsageTemplate returns usage template for the command. +func (c *Command) UsageTemplate() string { + if c.usageTemplate != "" { + return c.usageTemplate + } + + if c.HasParent() { + return c.parent.UsageTemplate() + } + return `Usage:{{if .Runnable}} + {{if .HasAvailableFlags}}{{appendIfNotPresent .UseLine "[flags]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasAvailableSubCommands}} + {{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}} + +Aliases: + {{.NameAndAliases}} +{{end}}{{if .HasExample}} + +Examples: +{{ .Example }}{{end}}{{if .HasAvailableSubCommands}} + +Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} + +Flags: +{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasAvailableInheritedFlags}} + +Global Flags: +{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}} + +Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} + +Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} +` +} + +// HelpTemplate return help template for the command. +func (c *Command) HelpTemplate() string { + if c.helpTemplate != "" { + return c.helpTemplate + } + + if c.HasParent() { + return c.parent.HelpTemplate() + } + return `{{with or .Long .Short }}{{. | trim}} + +{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` +} + +// Really only used when casting a command to a commander. +func (c *Command) resetChildrensParents() { + for _, x := range c.commands { + x.parent = c + } +} + +func hasNoOptDefVal(name string, f *flag.FlagSet) bool { + flag := f.Lookup(name) + if flag == nil { + return false + } + return len(flag.NoOptDefVal) > 0 +} + +func shortHasNoOptDefVal(name string, fs *flag.FlagSet) bool { + result := false + fs.VisitAll(func(flag *flag.Flag) { + if flag.Shorthand == name && len(flag.NoOptDefVal) > 0 { + result = true + } + }) + return result +} + +func stripFlags(args []string, c *Command) []string { + if len(args) < 1 { + return args + } + c.mergePersistentFlags() + + commands := []string{} + + inQuote := false + inFlag := false + for _, y := range args { + if !inQuote { + switch { + case strings.HasPrefix(y, "\""): + inQuote = true + case strings.Contains(y, "=\""): + inQuote = true + case strings.HasPrefix(y, "--") && !strings.Contains(y, "="): + // TODO: this isn't quite right, we should really check ahead for 'true' or 'false' + inFlag = !hasNoOptDefVal(y[2:], c.Flags()) + case strings.HasPrefix(y, "-") && !strings.Contains(y, "=") && len(y) == 2 && !shortHasNoOptDefVal(y[1:], c.Flags()): + inFlag = true + case inFlag: + inFlag = false + case y == "": + // strip empty commands, as the go tests expect this to be ok.... + case !strings.HasPrefix(y, "-"): + commands = append(commands, y) + inFlag = false + } + } + + if strings.HasSuffix(y, "\"") && !strings.HasSuffix(y, "\\\"") { + inQuote = false + } + } + + return commands +} + +// argsMinusFirstX removes only the first x from args. Otherwise, commands that look like +// openshift admin policy add-role-to-user admin my-user, lose the admin argument (arg[4]). +func argsMinusFirstX(args []string, x string) []string { + for i, y := range args { + if x == y { + ret := []string{} + ret = append(ret, args[:i]...) + ret = append(ret, args[i+1:]...) + return ret + } + } + return args +} + +// Find the target command given the args and command tree +// Meant to be run on the highest node. Only searches down. +func (c *Command) Find(args []string) (*Command, []string, error) { + if c == nil { + return nil, nil, fmt.Errorf("Called find() on a nil Command") + } + + var innerfind func(*Command, []string) (*Command, []string) + + innerfind = func(c *Command, innerArgs []string) (*Command, []string) { + argsWOflags := stripFlags(innerArgs, c) + if len(argsWOflags) == 0 { + return c, innerArgs + } + nextSubCmd := argsWOflags[0] + matches := make([]*Command, 0) + for _, cmd := range c.commands { + if cmd.Name() == nextSubCmd || cmd.HasAlias(nextSubCmd) { // exact name or alias match + return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) + } + if EnablePrefixMatching { + if strings.HasPrefix(cmd.Name(), nextSubCmd) { // prefix match + matches = append(matches, cmd) + } + for _, x := range cmd.Aliases { + if strings.HasPrefix(x, nextSubCmd) { + matches = append(matches, cmd) + } + } + } + } + + // only accept a single prefix match - multiple matches would be ambiguous + if len(matches) == 1 { + return innerfind(matches[0], argsMinusFirstX(innerArgs, argsWOflags[0])) + } + + return c, innerArgs + } + + commandFound, a := innerfind(c, args) + argsWOflags := stripFlags(a, commandFound) + + // no subcommand, always take args + if !commandFound.HasSubCommands() { + return commandFound, a, nil + } + + // root command with subcommands, do subcommand checking + if commandFound == c && len(argsWOflags) > 0 { + suggestionsString := "" + if !c.DisableSuggestions { + if c.SuggestionsMinimumDistance <= 0 { + c.SuggestionsMinimumDistance = 2 + } + if suggestions := c.SuggestionsFor(argsWOflags[0]); len(suggestions) > 0 { + suggestionsString += "\n\nDid you mean this?\n" + for _, s := range suggestions { + suggestionsString += fmt.Sprintf("\t%v\n", s) + } + } + } + return commandFound, a, fmt.Errorf("unknown command %q for %q%s", argsWOflags[0], commandFound.CommandPath(), suggestionsString) + } + + return commandFound, a, nil +} + +// SuggestionsFor provides suggestions for the typedName. +func (c *Command) SuggestionsFor(typedName string) []string { + suggestions := []string{} + for _, cmd := range c.commands { + if cmd.IsAvailableCommand() { + levenshteinDistance := ld(typedName, cmd.Name(), true) + suggestByLevenshtein := levenshteinDistance <= c.SuggestionsMinimumDistance + suggestByPrefix := strings.HasPrefix(strings.ToLower(cmd.Name()), strings.ToLower(typedName)) + if suggestByLevenshtein || suggestByPrefix { + suggestions = append(suggestions, cmd.Name()) + } + for _, explicitSuggestion := range cmd.SuggestFor { + if strings.EqualFold(typedName, explicitSuggestion) { + suggestions = append(suggestions, cmd.Name()) + } + } + } + } + return suggestions +} + +// VisitParents visits all parents of the command and invokes fn on each parent. +func (c *Command) VisitParents(fn func(*Command)) { + var traverse func(*Command) *Command + + traverse = func(x *Command) *Command { + if x != c { + fn(x) + } + if x.HasParent() { + return traverse(x.parent) + } + return x + } + traverse(c) +} + +// Root finds root command. +func (c *Command) Root() *Command { + var findRoot func(*Command) *Command + + findRoot = func(x *Command) *Command { + if x.HasParent() { + return findRoot(x.parent) + } + return x + } + + return findRoot(c) +} + +// ArgsLenAtDash will return the length of f.Args at the moment when a -- was +// found during arg parsing. This allows your program to know which args were +// before the -- and which came after. (Description from +// https://godoc.org/github.com/spf13/pflag#FlagSet.ArgsLenAtDash). +func (c *Command) ArgsLenAtDash() int { + return c.Flags().ArgsLenAtDash() +} + +func (c *Command) execute(a []string) (err error) { + if c == nil { + return fmt.Errorf("Called Execute() on a nil Command") + } + + if len(c.Deprecated) > 0 { + c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated) + } + + // initialize help flag as the last point possible to allow for user + // overriding + c.initHelpFlag() + + err = c.ParseFlags(a) + if err != nil { + return c.FlagErrorFunc()(c, err) + } + // If help is called, regardless of other flags, return we want help + // Also say we need help if the command isn't runnable. + helpVal, err := c.Flags().GetBool("help") + if err != nil { + // should be impossible to get here as we always declare a help + // flag in initHelpFlag() + c.Println("\"help\" flag declared as non-bool. Please correct your code") + return err + } + + if helpVal || !c.Runnable() { + return flag.ErrHelp + } + + c.preRun() + + argWoFlags := c.Flags().Args() + if c.DisableFlagParsing { + argWoFlags = a + } + + for p := c; p != nil; p = p.Parent() { + if p.PersistentPreRunE != nil { + if err := p.PersistentPreRunE(c, argWoFlags); err != nil { + return err + } + break + } else if p.PersistentPreRun != nil { + p.PersistentPreRun(c, argWoFlags) + break + } + } + if c.PreRunE != nil { + if err := c.PreRunE(c, argWoFlags); err != nil { + return err + } + } else if c.PreRun != nil { + c.PreRun(c, argWoFlags) + } + + if c.RunE != nil { + if err := c.RunE(c, argWoFlags); err != nil { + return err + } + } else { + c.Run(c, argWoFlags) + } + if c.PostRunE != nil { + if err := c.PostRunE(c, argWoFlags); err != nil { + return err + } + } else if c.PostRun != nil { + c.PostRun(c, argWoFlags) + } + for p := c; p != nil; p = p.Parent() { + if p.PersistentPostRunE != nil { + if err := p.PersistentPostRunE(c, argWoFlags); err != nil { + return err + } + break + } else if p.PersistentPostRun != nil { + p.PersistentPostRun(c, argWoFlags) + break + } + } + + return nil +} + +func (c *Command) preRun() { + for _, x := range initializers { + x() + } +} + +func (c *Command) errorMsgFromParse() string { + s := c.flagErrorBuf.String() + + x := strings.Split(s, "\n") + + if len(x) > 0 { + return x[0] + } + return "" +} + +// Execute Call execute to use the args (os.Args[1:] by default) +// and run through the command tree finding appropriate matches +// for commands and then corresponding flags. +func (c *Command) Execute() error { + _, err := c.ExecuteC() + return err +} + +// ExecuteC executes the command. +func (c *Command) ExecuteC() (cmd *Command, err error) { + // Regardless of what command execute is called on, run on Root only + if c.HasParent() { + return c.Root().ExecuteC() + } + + // windows hook + if preExecHookFn != nil { + preExecHookFn(c) + } + + // initialize help as the last point possible to allow for user + // overriding + c.initHelpCmd() + + var args []string + + // Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 + if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { + args = os.Args[1:] + } else { + args = c.args + } + + cmd, flags, err := c.Find(args) + if err != nil { + // If found parse to a subcommand and then failed, talk about the subcommand + if cmd != nil { + c = cmd + } + if !c.SilenceErrors { + c.Println("Error:", err.Error()) + c.Printf("Run '%v --help' for usage.\n", c.CommandPath()) + } + return c, err + } + err = cmd.execute(flags) + if err != nil { + // Always show help if requested, even if SilenceErrors is in + // effect + if err == flag.ErrHelp { + cmd.HelpFunc()(cmd, args) + return cmd, nil + } + + // If root command has SilentErrors flagged, + // all subcommands should respect it + if !cmd.SilenceErrors && !c.SilenceErrors { + c.Println("Error:", err.Error()) + } + + // If root command has SilentUsage flagged, + // all subcommands should respect it + if !cmd.SilenceUsage && !c.SilenceUsage { + c.Println(cmd.UsageString()) + } + return cmd, err + } + return cmd, nil +} + +func (c *Command) initHelpFlag() { + c.mergePersistentFlags() + if c.Flags().Lookup("help") == nil { + c.Flags().BoolP("help", "h", false, "help for "+c.Name()) + } +} + +func (c *Command) initHelpCmd() { + if c.helpCommand == nil { + if !c.HasSubCommands() { + return + } + + c.helpCommand = &Command{ + Use: "help [command]", + Short: "Help about any command", + Long: `Help provides help for any command in the application. + Simply type ` + c.Name() + ` help [path to command] for full details.`, + PersistentPreRun: func(cmd *Command, args []string) {}, + PersistentPostRun: func(cmd *Command, args []string) {}, + + Run: func(c *Command, args []string) { + cmd, _, e := c.Root().Find(args) + if cmd == nil || e != nil { + c.Printf("Unknown help topic %#q\n", args) + c.Root().Usage() + } else { + cmd.Help() + } + }, + } + } + c.RemoveCommand(c.helpCommand) + c.AddCommand(c.helpCommand) +} + +// ResetCommands used for testing. +func (c *Command) ResetCommands() { + c.commands = nil + c.helpCommand = nil +} + +// Sorts commands by their names. +type commandSorterByName []*Command + +func (c commandSorterByName) Len() int { return len(c) } +func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } +func (c commandSorterByName) Less(i, j int) bool { return c[i].Name() < c[j].Name() } + +// Commands returns a sorted slice of child commands. +func (c *Command) Commands() []*Command { + // do not sort commands if it already sorted or sorting was disabled + if EnableCommandSorting && !c.commandsAreSorted { + sort.Sort(commandSorterByName(c.commands)) + c.commandsAreSorted = true + } + return c.commands +} + +// AddCommand adds one or more commands to this parent command. +func (c *Command) AddCommand(cmds ...*Command) { + for i, x := range cmds { + if cmds[i] == c { + panic("Command can't be a child of itself") + } + cmds[i].parent = c + // update max lengths + usageLen := len(x.Use) + if usageLen > c.commandsMaxUseLen { + c.commandsMaxUseLen = usageLen + } + commandPathLen := len(x.CommandPath()) + if commandPathLen > c.commandsMaxCommandPathLen { + c.commandsMaxCommandPathLen = commandPathLen + } + nameLen := len(x.Name()) + if nameLen > c.commandsMaxNameLen { + c.commandsMaxNameLen = nameLen + } + // If global normalization function exists, update all children + if c.globNormFunc != nil { + x.SetGlobalNormalizationFunc(c.globNormFunc) + } + c.commands = append(c.commands, x) + c.commandsAreSorted = false + } +} + +// RemoveCommand removes one or more commands from a parent command. +func (c *Command) RemoveCommand(cmds ...*Command) { + commands := []*Command{} +main: + for _, command := range c.commands { + for _, cmd := range cmds { + if command == cmd { + command.parent = nil + continue main + } + } + commands = append(commands, command) + } + c.commands = commands + // recompute all lengths + c.commandsMaxUseLen = 0 + c.commandsMaxCommandPathLen = 0 + c.commandsMaxNameLen = 0 + for _, command := range c.commands { + usageLen := len(command.Use) + if usageLen > c.commandsMaxUseLen { + c.commandsMaxUseLen = usageLen + } + commandPathLen := len(command.CommandPath()) + if commandPathLen > c.commandsMaxCommandPathLen { + c.commandsMaxCommandPathLen = commandPathLen + } + nameLen := len(command.Name()) + if nameLen > c.commandsMaxNameLen { + c.commandsMaxNameLen = nameLen + } + } +} + +// Print is a convenience method to Print to the defined output, fallback to Stderr if not set. +func (c *Command) Print(i ...interface{}) { + fmt.Fprint(c.OutOrStderr(), i...) +} + +// Println is a convenience method to Println to the defined output, fallback to Stderr if not set. +func (c *Command) Println(i ...interface{}) { + str := fmt.Sprintln(i...) + c.Print(str) +} + +// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set. +func (c *Command) Printf(format string, i ...interface{}) { + str := fmt.Sprintf(format, i...) + c.Print(str) +} + +// CommandPath returns the full path to this command. +func (c *Command) CommandPath() string { + str := c.Name() + x := c + for x.HasParent() { + str = x.parent.Name() + " " + str + x = x.parent + } + return str +} + +// UseLine puts out the full usage for a given command (including parents). +func (c *Command) UseLine() string { + str := "" + if c.HasParent() { + str = c.parent.CommandPath() + " " + } + return str + c.Use +} + +// DebugFlags used to determine which flags have been assigned to which commands +// and which persist. +func (c *Command) DebugFlags() { + c.Println("DebugFlags called on", c.Name()) + var debugflags func(*Command) + + debugflags = func(x *Command) { + if x.HasFlags() || x.HasPersistentFlags() { + c.Println(x.Name()) + } + if x.HasFlags() { + x.flags.VisitAll(func(f *flag.Flag) { + if x.HasPersistentFlags() { + if x.persistentFlag(f.Name) == nil { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [L]") + } else { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [LP]") + } + } else { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [L]") + } + }) + } + if x.HasPersistentFlags() { + x.pflags.VisitAll(func(f *flag.Flag) { + if x.HasFlags() { + if x.flags.Lookup(f.Name) == nil { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") + } + } else { + c.Println(" -"+f.Shorthand+",", "--"+f.Name, "["+f.DefValue+"]", "", f.Value, " [P]") + } + }) + } + c.Println(x.flagErrorBuf) + if x.HasSubCommands() { + for _, y := range x.commands { + debugflags(y) + } + } + } + + debugflags(c) +} + +// Name returns the command's name: the first word in the use line. +func (c *Command) Name() string { + if c.name != "" { + return c.name + } + name := c.Use + i := strings.Index(name, " ") + if i >= 0 { + name = name[:i] + } + c.name = name + return c.name +} + +// HasAlias determines if a given string is an alias of the command. +func (c *Command) HasAlias(s string) bool { + for _, a := range c.Aliases { + if a == s { + return true + } + } + return false +} + +// NameAndAliases returns string containing name and all aliases +func (c *Command) NameAndAliases() string { + return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ") +} + +// HasExample determines if the command has example. +func (c *Command) HasExample() bool { + return len(c.Example) > 0 +} + +// Runnable determines if the command is itself runnable. +func (c *Command) Runnable() bool { + return c.Run != nil || c.RunE != nil +} + +// HasSubCommands determines if the command has children commands. +func (c *Command) HasSubCommands() bool { + return len(c.commands) > 0 +} + +// IsAvailableCommand determines if a command is available as a non-help command +// (this includes all non deprecated/hidden commands). +func (c *Command) IsAvailableCommand() bool { + if len(c.Deprecated) != 0 || c.Hidden { + return false + } + + if c.HasParent() && c.Parent().helpCommand == c { + return false + } + + if c.Runnable() || c.HasAvailableSubCommands() { + return true + } + + return false +} + +// IsAdditionalHelpTopicCommand determines if a command is an additional +// help topic command; additional help topic command is determined by the +// fact that it is NOT runnable/hidden/deprecated, and has no sub commands that +// are runnable/hidden/deprecated. +// Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. +func (c *Command) IsAdditionalHelpTopicCommand() bool { + // if a command is runnable, deprecated, or hidden it is not a 'help' command + if c.Runnable() || len(c.Deprecated) != 0 || c.Hidden { + return false + } + + // if any non-help sub commands are found, the command is not a 'help' command + for _, sub := range c.commands { + if !sub.IsAdditionalHelpTopicCommand() { + return false + } + } + + // the command either has no sub commands, or no non-help sub commands + return true +} + +// HasHelpSubCommands determines if a command has any available 'help' sub commands +// that need to be shown in the usage/help default template under 'additional help +// topics'. +func (c *Command) HasHelpSubCommands() bool { + // return true on the first found available 'help' sub command + for _, sub := range c.commands { + if sub.IsAdditionalHelpTopicCommand() { + return true + } + } + + // the command either has no sub commands, or no available 'help' sub commands + return false +} + +// HasAvailableSubCommands determines if a command has available sub commands that +// need to be shown in the usage/help default template under 'available commands'. +func (c *Command) HasAvailableSubCommands() bool { + // return true on the first found available (non deprecated/help/hidden) + // sub command + for _, sub := range c.commands { + if sub.IsAvailableCommand() { + return true + } + } + + // the command either has no sub comamnds, or no available (non deprecated/help/hidden) + // sub commands + return false +} + +// HasParent determines if the command is a child command. +func (c *Command) HasParent() bool { + return c.parent != nil +} + +// GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists. +func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { + return c.globNormFunc +} + +// Flags returns the complete FlagSet that applies +// to this command (local and persistent declared here and by all parents). +func (c *Command) Flags() *flag.FlagSet { + if c.flags == nil { + c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.flags.SetOutput(c.flagErrorBuf) + } + return c.flags +} + +// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands. +func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { + persistentFlags := c.PersistentFlags() + + out := flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.LocalFlags().VisitAll(func(f *flag.Flag) { + if persistentFlags.Lookup(f.Name) == nil { + out.AddFlag(f) + } + }) + return out +} + +// LocalFlags returns the local FlagSet specifically set in the current command. +func (c *Command) LocalFlags() *flag.FlagSet { + c.mergePersistentFlags() + + local := flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.lflags.VisitAll(func(f *flag.Flag) { + local.AddFlag(f) + }) + if !c.HasParent() { + flag.CommandLine.VisitAll(func(f *flag.Flag) { + if local.Lookup(f.Name) == nil { + local.AddFlag(f) + } + }) + } + return local +} + +// InheritedFlags returns all flags which were inherited from parents commands. +func (c *Command) InheritedFlags() *flag.FlagSet { + c.mergePersistentFlags() + + inherited := flag.NewFlagSet(c.Name(), flag.ContinueOnError) + local := c.LocalFlags() + + var rmerge func(x *Command) + + rmerge = func(x *Command) { + if x.HasPersistentFlags() { + x.PersistentFlags().VisitAll(func(f *flag.Flag) { + if inherited.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil { + inherited.AddFlag(f) + } + }) + } + if x.HasParent() { + rmerge(x.parent) + } + } + + if c.HasParent() { + rmerge(c.parent) + } + + return inherited +} + +// NonInheritedFlags returns all flags which were not inherited from parent commands. +func (c *Command) NonInheritedFlags() *flag.FlagSet { + return c.LocalFlags() +} + +// PersistentFlags returns the persistent FlagSet specifically set in the current command. +func (c *Command) PersistentFlags() *flag.FlagSet { + if c.pflags == nil { + c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.pflags.SetOutput(c.flagErrorBuf) + } + return c.pflags +} + +// ResetFlags is used in testing. +func (c *Command) ResetFlags() { + c.flagErrorBuf = new(bytes.Buffer) + c.flagErrorBuf.Reset() + c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.flags.SetOutput(c.flagErrorBuf) + c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + c.pflags.SetOutput(c.flagErrorBuf) +} + +// HasFlags checks if the command contains any flags (local plus persistent from the entire structure). +func (c *Command) HasFlags() bool { + return c.Flags().HasFlags() +} + +// HasPersistentFlags checks if the command contains persistent flags. +func (c *Command) HasPersistentFlags() bool { + return c.PersistentFlags().HasFlags() +} + +// HasLocalFlags checks if the command has flags specifically declared locally. +func (c *Command) HasLocalFlags() bool { + return c.LocalFlags().HasFlags() +} + +// HasInheritedFlags checks if the command has flags inherited from its parent command. +func (c *Command) HasInheritedFlags() bool { + return c.InheritedFlags().HasFlags() +} + +// HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire +// structure) which are not hidden or deprecated. +func (c *Command) HasAvailableFlags() bool { + return c.Flags().HasAvailableFlags() +} + +// HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated. +func (c *Command) HasAvailablePersistentFlags() bool { + return c.PersistentFlags().HasAvailableFlags() +} + +// HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden +// or deprecated. +func (c *Command) HasAvailableLocalFlags() bool { + return c.LocalFlags().HasAvailableFlags() +} + +// HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are +// not hidden or deprecated. +func (c *Command) HasAvailableInheritedFlags() bool { + return c.InheritedFlags().HasAvailableFlags() +} + +// Flag climbs up the command tree looking for matching flag. +func (c *Command) Flag(name string) (flag *flag.Flag) { + flag = c.Flags().Lookup(name) + + if flag == nil { + flag = c.persistentFlag(name) + } + + return +} + +// Recursively find matching persistent flag. +func (c *Command) persistentFlag(name string) (flag *flag.Flag) { + if c.HasPersistentFlags() { + flag = c.PersistentFlags().Lookup(name) + } + + if flag == nil && c.HasParent() { + flag = c.parent.persistentFlag(name) + } + return +} + +// ParseFlags parses persistent flag tree and local flags. +func (c *Command) ParseFlags(args []string) (err error) { + if c.DisableFlagParsing { + return nil + } + c.mergePersistentFlags() + err = c.Flags().Parse(args) + return +} + +// Parent returns a commands parent command. +func (c *Command) Parent() *Command { + return c.parent +} + +func (c *Command) mergePersistentFlags() { + var rmerge func(x *Command) + + // Save the set of local flags + if c.lflags == nil { + c.lflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) + if c.flagErrorBuf == nil { + c.flagErrorBuf = new(bytes.Buffer) + } + c.lflags.SetOutput(c.flagErrorBuf) + addtolocal := func(f *flag.Flag) { + c.lflags.AddFlag(f) + } + c.Flags().VisitAll(addtolocal) + c.PersistentFlags().VisitAll(addtolocal) + } + rmerge = func(x *Command) { + if !x.HasParent() { + flag.CommandLine.VisitAll(func(f *flag.Flag) { + if x.PersistentFlags().Lookup(f.Name) == nil { + x.PersistentFlags().AddFlag(f) + } + }) + } + if x.HasPersistentFlags() { + x.PersistentFlags().VisitAll(func(f *flag.Flag) { + if c.Flags().Lookup(f.Name) == nil { + c.Flags().AddFlag(f) + } + }) + } + if x.HasParent() { + rmerge(x.parent) + } + } + + rmerge(c) +} diff --git a/vendor/github.com/spf13/cobra/command_notwin.go b/vendor/github.com/spf13/cobra/command_notwin.go new file mode 100644 index 000000000..6159c1cc1 --- /dev/null +++ b/vendor/github.com/spf13/cobra/command_notwin.go @@ -0,0 +1,5 @@ +// +build !windows + +package cobra + +var preExecHookFn func(*Command) diff --git a/vendor/github.com/spf13/cobra/command_win.go b/vendor/github.com/spf13/cobra/command_win.go new file mode 100644 index 000000000..4b0eaa1b6 --- /dev/null +++ b/vendor/github.com/spf13/cobra/command_win.go @@ -0,0 +1,26 @@ +// +build windows + +package cobra + +import ( + "os" + "time" + + "github.com/inconshreveable/mousetrap" +) + +var preExecHookFn = preExecHook + +// enables an information splash screen on Windows if the CLI is started from explorer.exe. +var MousetrapHelpText string = `This is a command line tool + +You need to open cmd.exe and run it from there. +` + +func preExecHook(c *Command) { + if mousetrap.StartedByExplorer() { + c.Print(MousetrapHelpText) + time.Sleep(5 * time.Second) + os.Exit(1) + } +} diff --git a/vendor/github.com/spf13/pflag/LICENSE b/vendor/github.com/spf13/pflag/LICENSE new file mode 100644 index 000000000..63ed1cfea --- /dev/null +++ b/vendor/github.com/spf13/pflag/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2012 Alex Ogier. All rights reserved. +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/spf13/pflag/README.md b/vendor/github.com/spf13/pflag/README.md new file mode 100644 index 000000000..eefb46dec --- /dev/null +++ b/vendor/github.com/spf13/pflag/README.md @@ -0,0 +1,277 @@ +[![Build Status](https://travis-ci.org/spf13/pflag.svg?branch=master)](https://travis-ci.org/spf13/pflag) +[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/pflag)](https://goreportcard.com/report/github.com/spf13/pflag) +[![GoDoc](https://godoc.org/github.com/spf13/pflag?status.svg)](https://godoc.org/github.com/spf13/pflag) + +## Description + +pflag is a drop-in replacement for Go's flag package, implementing +POSIX/GNU-style --flags. + +pflag is compatible with the [GNU extensions to the POSIX recommendations +for command-line options][1]. For a more precise description, see the +"Command-line flag syntax" section below. + +[1]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + +pflag is available under the same style of BSD license as the Go language, +which can be found in the LICENSE file. + +## Installation + +pflag is available using the standard `go get` command. + +Install by running: + + go get github.com/spf13/pflag + +Run tests by running: + + go test github.com/spf13/pflag + +## Usage + +pflag is a drop-in replacement of Go's native flag package. If you import +pflag under the name "flag" then all code should continue to function +with no changes. + +``` go +import flag "github.com/spf13/pflag" +``` + +There is one exception to this: if you directly instantiate the Flag struct +there is one more field "Shorthand" that you will need to set. +Most code never instantiates this struct directly, and instead uses +functions such as String(), BoolVar(), and Var(), and is therefore +unaffected. + +Define flags using flag.String(), Bool(), Int(), etc. + +This declares an integer flag, -flagname, stored in the pointer ip, with type *int. + +``` go +var ip *int = flag.Int("flagname", 1234, "help message for flagname") +``` + +If you like, you can bind the flag to a variable using the Var() functions. + +``` go +var flagvar int +func init() { + flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") +} +``` + +Or you can create custom flags that satisfy the Value interface (with +pointer receivers) and couple them to flag parsing by + +``` go +flag.Var(&flagVal, "name", "help message for flagname") +``` + +For such flags, the default value is just the initial value of the variable. + +After all flags are defined, call + +``` go +flag.Parse() +``` + +to parse the command line into the defined flags. + +Flags may then be used directly. If you're using the flags themselves, +they are all pointers; if you bind to variables, they're values. + +``` go +fmt.Println("ip has value ", *ip) +fmt.Println("flagvar has value ", flagvar) +``` + +There are helpers function to get values later if you have the FlagSet but +it was difficult to keep up with all of the flag pointers in your code. +If you have a pflag.FlagSet with a flag called 'flagname' of type int you +can use GetInt() to get the int value. But notice that 'flagname' must exist +and it must be an int. GetString("flagname") will fail. + +``` go +i, err := flagset.GetInt("flagname") +``` + +After parsing, the arguments after the flag are available as the +slice flag.Args() or individually as flag.Arg(i). +The arguments are indexed from 0 through flag.NArg()-1. + +The pflag package also defines some new functions that are not in flag, +that give one-letter shorthands for flags. You can use these by appending +'P' to the name of any function that defines a flag. + +``` go +var ip = flag.IntP("flagname", "f", 1234, "help message") +var flagvar bool +func init() { + flag.BoolVarP(&flagvar, "boolname", "b", true, "help message") +} +flag.VarP(&flagVal, "varname", "v", "help message") +``` + +Shorthand letters can be used with single dashes on the command line. +Boolean shorthand flags can be combined with other shorthand flags. + +The default set of command-line flags is controlled by +top-level functions. The FlagSet type allows one to define +independent sets of flags, such as to implement subcommands +in a command-line interface. The methods of FlagSet are +analogous to the top-level functions for the command-line +flag set. + +## Setting no option default values for flags + +After you create a flag it is possible to set the pflag.NoOptDefVal for +the given flag. Doing this changes the meaning of the flag slightly. If +a flag has a NoOptDefVal and the flag is set on the command line without +an option the flag will be set to the NoOptDefVal. For example given: + +``` go +var ip = flag.IntP("flagname", "f", 1234, "help message") +flag.Lookup("flagname").NoOptDefVal = "4321" +``` + +Would result in something like + +| Parsed Arguments | Resulting Value | +| ------------- | ------------- | +| --flagname=1357 | ip=1357 | +| --flagname | ip=4321 | +| [nothing] | ip=1234 | + +## Command line flag syntax + +``` +--flag // boolean flags, or flags with no option default values +--flag x // only on flags without a default value +--flag=x +``` + +Unlike the flag package, a single dash before an option means something +different than a double dash. Single dashes signify a series of shorthand +letters for flags. All but the last shorthand letter must be boolean flags +or a flag with a default value + +``` +// boolean or flags where the 'no option default value' is set +-f +-f=true +-abc +but +-b true is INVALID + +// non-boolean and flags without a 'no option default value' +-n 1234 +-n=1234 +-n1234 + +// mixed +-abcs "hello" +-absd="hello" +-abcs1234 +``` + +Flag parsing stops after the terminator "--". Unlike the flag package, +flags can be interspersed with arguments anywhere on the command line +before this terminator. + +Integer flags accept 1234, 0664, 0x1234 and may be negative. +Boolean flags (in their long form) accept 1, 0, t, f, true, false, +TRUE, FALSE, True, False. +Duration flags accept any input valid for time.ParseDuration. + +## Mutating or "Normalizing" Flag names + +It is possible to set a custom flag name 'normalization function.' It allows flag names to be mutated both when created in the code and when used on the command line to some 'normalized' form. The 'normalized' form is used for comparison. Two examples of using the custom normalization func follow. + +**Example #1**: You want -, _, and . in flags to compare the same. aka --my-flag == --my_flag == --my.flag + +``` go +func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { + from := []string{"-", "_"} + to := "." + for _, sep := range from { + name = strings.Replace(name, sep, to, -1) + } + return pflag.NormalizedName(name) +} + +myFlagSet.SetNormalizeFunc(wordSepNormalizeFunc) +``` + +**Example #2**: You want to alias two flags. aka --old-flag-name == --new-flag-name + +``` go +func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { + switch name { + case "old-flag-name": + name = "new-flag-name" + break + } + return pflag.NormalizedName(name) +} + +myFlagSet.SetNormalizeFunc(aliasNormalizeFunc) +``` + +## Deprecating a flag or its shorthand +It is possible to deprecate a flag, or just its shorthand. Deprecating a flag/shorthand hides it from help text and prints a usage message when the deprecated flag/shorthand is used. + +**Example #1**: You want to deprecate a flag named "badflag" as well as inform the users what flag they should use instead. +```go +// deprecate a flag by specifying its name and a usage message +flags.MarkDeprecated("badflag", "please use --good-flag instead") +``` +This hides "badflag" from help text, and prints `Flag --badflag has been deprecated, please use --good-flag instead` when "badflag" is used. + +**Example #2**: You want to keep a flag name "noshorthandflag" but deprecate its shortname "n". +```go +// deprecate a flag shorthand by specifying its flag name and a usage message +flags.MarkShorthandDeprecated("noshorthandflag", "please use --noshorthandflag only") +``` +This hides the shortname "n" from help text, and prints `Flag shorthand -n has been deprecated, please use --noshorthandflag only` when the shorthand "n" is used. + +Note that usage message is essential here, and it should not be empty. + +## Hidden flags +It is possible to mark a flag as hidden, meaning it will still function as normal, however will not show up in usage/help text. + +**Example**: You have a flag named "secretFlag" that you need for internal use only and don't want it showing up in help text, or for its usage text to be available. +```go +// hide a flag by specifying its name +flags.MarkHidden("secretFlag") +``` + +## Supporting Go flags when using pflag +In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary +to support flags defined by third-party dependencies (e.g. `golang/glog`). + +**Example**: You want to add the Go flags to the `CommandLine` flagset +```go +import ( + goflag "flag" + flag "github.com/spf13/pflag" +) + +var ip *int = flag.Int("flagname", 1234, "help message for flagname") + +func main() { + flag.CommandLine.AddGoFlagSet(goflag.CommandLine) + flag.Parse() +} +``` + +## More info + +You can see the full reference documentation of the pflag package +[at godoc.org][3], or through go's standard documentation system by +running `godoc -http=:6060` and browsing to +[http://localhost:6060/pkg/github.com/ogier/pflag][2] after +installation. + +[2]: http://localhost:6060/pkg/github.com/ogier/pflag +[3]: http://godoc.org/github.com/ogier/pflag diff --git a/vendor/github.com/spf13/pflag/bool.go b/vendor/github.com/spf13/pflag/bool.go new file mode 100644 index 000000000..c4c5c0bfd --- /dev/null +++ b/vendor/github.com/spf13/pflag/bool.go @@ -0,0 +1,94 @@ +package pflag + +import "strconv" + +// optional interface to indicate boolean flags that can be +// supplied without "=value" text +type boolFlag interface { + Value + IsBoolFlag() bool +} + +// -- bool Value +type boolValue bool + +func newBoolValue(val bool, p *bool) *boolValue { + *p = val + return (*boolValue)(p) +} + +func (b *boolValue) Set(s string) error { + v, err := strconv.ParseBool(s) + *b = boolValue(v) + return err +} + +func (b *boolValue) Type() string { + return "bool" +} + +func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) } + +func (b *boolValue) IsBoolFlag() bool { return true } + +func boolConv(sval string) (interface{}, error) { + return strconv.ParseBool(sval) +} + +// GetBool return the bool value of a flag with the given name +func (f *FlagSet) GetBool(name string) (bool, error) { + val, err := f.getFlagType(name, "bool", boolConv) + if err != nil { + return false, err + } + return val.(bool), nil +} + +// BoolVar defines a bool flag with specified name, default value, and usage string. +// The argument p points to a bool variable in which to store the value of the flag. +func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) { + f.BoolVarP(p, name, "", value, usage) +} + +// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) { + flag := f.VarPF(newBoolValue(value, p), name, shorthand, usage) + flag.NoOptDefVal = "true" +} + +// BoolVar defines a bool flag with specified name, default value, and usage string. +// The argument p points to a bool variable in which to store the value of the flag. +func BoolVar(p *bool, name string, value bool, usage string) { + BoolVarP(p, name, "", value, usage) +} + +// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. +func BoolVarP(p *bool, name, shorthand string, value bool, usage string) { + flag := CommandLine.VarPF(newBoolValue(value, p), name, shorthand, usage) + flag.NoOptDefVal = "true" +} + +// Bool defines a bool flag with specified name, default value, and usage string. +// The return value is the address of a bool variable that stores the value of the flag. +func (f *FlagSet) Bool(name string, value bool, usage string) *bool { + return f.BoolP(name, "", value, usage) +} + +// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool { + p := new(bool) + f.BoolVarP(p, name, shorthand, value, usage) + return p +} + +// Bool defines a bool flag with specified name, default value, and usage string. +// The return value is the address of a bool variable that stores the value of the flag. +func Bool(name string, value bool, usage string) *bool { + return BoolP(name, "", value, usage) +} + +// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. +func BoolP(name, shorthand string, value bool, usage string) *bool { + b := CommandLine.BoolP(name, shorthand, value, usage) + return b +} diff --git a/vendor/github.com/spf13/pflag/bool_slice.go b/vendor/github.com/spf13/pflag/bool_slice.go new file mode 100644 index 000000000..5af02f1a7 --- /dev/null +++ b/vendor/github.com/spf13/pflag/bool_slice.go @@ -0,0 +1,147 @@ +package pflag + +import ( + "io" + "strconv" + "strings" +) + +// -- boolSlice Value +type boolSliceValue struct { + value *[]bool + changed bool +} + +func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue { + bsv := new(boolSliceValue) + bsv.value = p + *bsv.value = val + return bsv +} + +// Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag. +// If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended. +func (s *boolSliceValue) Set(val string) error { + + // remove all quote characters + rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") + + // read flag arguments with CSV parser + boolStrSlice, err := readAsCSV(rmQuote.Replace(val)) + if err != nil && err != io.EOF { + return err + } + + // parse boolean values into slice + out := make([]bool, 0, len(boolStrSlice)) + for _, boolStr := range boolStrSlice { + b, err := strconv.ParseBool(strings.TrimSpace(boolStr)) + if err != nil { + return err + } + out = append(out, b) + } + + if !s.changed { + *s.value = out + } else { + *s.value = append(*s.value, out...) + } + + s.changed = true + + return nil +} + +// Type returns a string that uniquely represents this flag's type. +func (s *boolSliceValue) Type() string { + return "boolSlice" +} + +// String defines a "native" format for this boolean slice flag value. +func (s *boolSliceValue) String() string { + + boolStrSlice := make([]string, len(*s.value)) + for i, b := range *s.value { + boolStrSlice[i] = strconv.FormatBool(b) + } + + out, _ := writeAsCSV(boolStrSlice) + + return "[" + out + "]" +} + +func boolSliceConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // Empty string would cause a slice with one (empty) entry + if len(val) == 0 { + return []bool{}, nil + } + ss := strings.Split(val, ",") + out := make([]bool, len(ss)) + for i, t := range ss { + var err error + out[i], err = strconv.ParseBool(t) + if err != nil { + return nil, err + } + } + return out, nil +} + +// GetBoolSlice returns the []bool value of a flag with the given name. +func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) { + val, err := f.getFlagType(name, "boolSlice", boolSliceConv) + if err != nil { + return []bool{}, err + } + return val.([]bool), nil +} + +// BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string. +// The argument p points to a []bool variable in which to store the value of the flag. +func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) { + f.VarP(newBoolSliceValue(value, p), name, "", usage) +} + +// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { + f.VarP(newBoolSliceValue(value, p), name, shorthand, usage) +} + +// BoolSliceVar defines a []bool flag with specified name, default value, and usage string. +// The argument p points to a []bool variable in which to store the value of the flag. +func BoolSliceVar(p *[]bool, name string, value []bool, usage string) { + CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage) +} + +// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. +func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { + CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage) +} + +// BoolSlice defines a []bool flag with specified name, default value, and usage string. +// The return value is the address of a []bool variable that stores the value of the flag. +func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool { + p := []bool{} + f.BoolSliceVarP(&p, name, "", value, usage) + return &p +} + +// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { + p := []bool{} + f.BoolSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// BoolSlice defines a []bool flag with specified name, default value, and usage string. +// The return value is the address of a []bool variable that stores the value of the flag. +func BoolSlice(name string, value []bool, usage string) *[]bool { + return CommandLine.BoolSliceP(name, "", value, usage) +} + +// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. +func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { + return CommandLine.BoolSliceP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/count.go b/vendor/github.com/spf13/pflag/count.go new file mode 100644 index 000000000..d22be41f2 --- /dev/null +++ b/vendor/github.com/spf13/pflag/count.go @@ -0,0 +1,94 @@ +package pflag + +import "strconv" + +// -- count Value +type countValue int + +func newCountValue(val int, p *int) *countValue { + *p = val + return (*countValue)(p) +} + +func (i *countValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + // -1 means that no specific value was passed, so increment + if v == -1 { + *i = countValue(*i + 1) + } else { + *i = countValue(v) + } + return err +} + +func (i *countValue) Type() string { + return "count" +} + +func (i *countValue) String() string { return strconv.Itoa(int(*i)) } + +func countConv(sval string) (interface{}, error) { + i, err := strconv.Atoi(sval) + if err != nil { + return nil, err + } + return i, nil +} + +// GetCount return the int value of a flag with the given name +func (f *FlagSet) GetCount(name string) (int, error) { + val, err := f.getFlagType(name, "count", countConv) + if err != nil { + return 0, err + } + return val.(int), nil +} + +// CountVar defines a count flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +// A count flag will add 1 to its value evey time it is found on the command line +func (f *FlagSet) CountVar(p *int, name string, usage string) { + f.CountVarP(p, name, "", usage) +} + +// CountVarP is like CountVar only take a shorthand for the flag name. +func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) { + flag := f.VarPF(newCountValue(0, p), name, shorthand, usage) + flag.NoOptDefVal = "-1" +} + +// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set +func CountVar(p *int, name string, usage string) { + CommandLine.CountVar(p, name, usage) +} + +// CountVarP is like CountVar only take a shorthand for the flag name. +func CountVarP(p *int, name, shorthand string, usage string) { + CommandLine.CountVarP(p, name, shorthand, usage) +} + +// Count defines a count flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +// A count flag will add 1 to its value evey time it is found on the command line +func (f *FlagSet) Count(name string, usage string) *int { + p := new(int) + f.CountVarP(p, name, "", usage) + return p +} + +// CountP is like Count only takes a shorthand for the flag name. +func (f *FlagSet) CountP(name, shorthand string, usage string) *int { + p := new(int) + f.CountVarP(p, name, shorthand, usage) + return p +} + +// Count like Count only the flag is placed on the CommandLine isntead of a given flag set +func Count(name string, usage string) *int { + return CommandLine.CountP(name, "", usage) +} + +// CountP is like Count only takes a shorthand for the flag name. +func CountP(name, shorthand string, usage string) *int { + return CommandLine.CountP(name, shorthand, usage) +} diff --git a/vendor/github.com/spf13/pflag/duration.go b/vendor/github.com/spf13/pflag/duration.go new file mode 100644 index 000000000..e9debef88 --- /dev/null +++ b/vendor/github.com/spf13/pflag/duration.go @@ -0,0 +1,86 @@ +package pflag + +import ( + "time" +) + +// -- time.Duration Value +type durationValue time.Duration + +func newDurationValue(val time.Duration, p *time.Duration) *durationValue { + *p = val + return (*durationValue)(p) +} + +func (d *durationValue) Set(s string) error { + v, err := time.ParseDuration(s) + *d = durationValue(v) + return err +} + +func (d *durationValue) Type() string { + return "duration" +} + +func (d *durationValue) String() string { return (*time.Duration)(d).String() } + +func durationConv(sval string) (interface{}, error) { + return time.ParseDuration(sval) +} + +// GetDuration return the duration value of a flag with the given name +func (f *FlagSet) GetDuration(name string) (time.Duration, error) { + val, err := f.getFlagType(name, "duration", durationConv) + if err != nil { + return 0, err + } + return val.(time.Duration), nil +} + +// DurationVar defines a time.Duration flag with specified name, default value, and usage string. +// The argument p points to a time.Duration variable in which to store the value of the flag. +func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) { + f.VarP(newDurationValue(value, p), name, "", usage) +} + +// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { + f.VarP(newDurationValue(value, p), name, shorthand, usage) +} + +// DurationVar defines a time.Duration flag with specified name, default value, and usage string. +// The argument p points to a time.Duration variable in which to store the value of the flag. +func DurationVar(p *time.Duration, name string, value time.Duration, usage string) { + CommandLine.VarP(newDurationValue(value, p), name, "", usage) +} + +// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. +func DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { + CommandLine.VarP(newDurationValue(value, p), name, shorthand, usage) +} + +// Duration defines a time.Duration flag with specified name, default value, and usage string. +// The return value is the address of a time.Duration variable that stores the value of the flag. +func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration { + p := new(time.Duration) + f.DurationVarP(p, name, "", value, usage) + return p +} + +// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { + p := new(time.Duration) + f.DurationVarP(p, name, shorthand, value, usage) + return p +} + +// Duration defines a time.Duration flag with specified name, default value, and usage string. +// The return value is the address of a time.Duration variable that stores the value of the flag. +func Duration(name string, value time.Duration, usage string) *time.Duration { + return CommandLine.DurationP(name, "", value, usage) +} + +// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. +func DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { + return CommandLine.DurationP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/flag.go b/vendor/github.com/spf13/pflag/flag.go new file mode 100644 index 000000000..746af6327 --- /dev/null +++ b/vendor/github.com/spf13/pflag/flag.go @@ -0,0 +1,1063 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package pflag is a drop-in replacement for Go's flag package, implementing +POSIX/GNU-style --flags. + +pflag is compatible with the GNU extensions to the POSIX recommendations +for command-line options. See +http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + +Usage: + +pflag is a drop-in replacement of Go's native flag package. If you import +pflag under the name "flag" then all code should continue to function +with no changes. + + import flag "github.com/ogier/pflag" + + There is one exception to this: if you directly instantiate the Flag struct +there is one more field "Shorthand" that you will need to set. +Most code never instantiates this struct directly, and instead uses +functions such as String(), BoolVar(), and Var(), and is therefore +unaffected. + +Define flags using flag.String(), Bool(), Int(), etc. + +This declares an integer flag, -flagname, stored in the pointer ip, with type *int. + var ip = flag.Int("flagname", 1234, "help message for flagname") +If you like, you can bind the flag to a variable using the Var() functions. + var flagvar int + func init() { + flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") + } +Or you can create custom flags that satisfy the Value interface (with +pointer receivers) and couple them to flag parsing by + flag.Var(&flagVal, "name", "help message for flagname") +For such flags, the default value is just the initial value of the variable. + +After all flags are defined, call + flag.Parse() +to parse the command line into the defined flags. + +Flags may then be used directly. If you're using the flags themselves, +they are all pointers; if you bind to variables, they're values. + fmt.Println("ip has value ", *ip) + fmt.Println("flagvar has value ", flagvar) + +After parsing, the arguments after the flag are available as the +slice flag.Args() or individually as flag.Arg(i). +The arguments are indexed from 0 through flag.NArg()-1. + +The pflag package also defines some new functions that are not in flag, +that give one-letter shorthands for flags. You can use these by appending +'P' to the name of any function that defines a flag. + var ip = flag.IntP("flagname", "f", 1234, "help message") + var flagvar bool + func init() { + flag.BoolVarP("boolname", "b", true, "help message") + } + flag.VarP(&flagVar, "varname", "v", 1234, "help message") +Shorthand letters can be used with single dashes on the command line. +Boolean shorthand flags can be combined with other shorthand flags. + +Command line flag syntax: + --flag // boolean flags only + --flag=x + +Unlike the flag package, a single dash before an option means something +different than a double dash. Single dashes signify a series of shorthand +letters for flags. All but the last shorthand letter must be boolean flags. + // boolean flags + -f + -abc + // non-boolean flags + -n 1234 + -Ifile + // mixed + -abcs "hello" + -abcn1234 + +Flag parsing stops after the terminator "--". Unlike the flag package, +flags can be interspersed with arguments anywhere on the command line +before this terminator. + +Integer flags accept 1234, 0664, 0x1234 and may be negative. +Boolean flags (in their long form) accept 1, 0, t, f, true, false, +TRUE, FALSE, True, False. +Duration flags accept any input valid for time.ParseDuration. + +The default set of command-line flags is controlled by +top-level functions. The FlagSet type allows one to define +independent sets of flags, such as to implement subcommands +in a command-line interface. The methods of FlagSet are +analogous to the top-level functions for the command-line +flag set. +*/ +package pflag + +import ( + "bytes" + "errors" + "fmt" + "io" + "os" + "sort" + "strings" +) + +// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. +var ErrHelp = errors.New("pflag: help requested") + +// ErrorHandling defines how to handle flag parsing errors. +type ErrorHandling int + +const ( + // ContinueOnError will return an err from Parse() if an error is found + ContinueOnError ErrorHandling = iota + // ExitOnError will call os.Exit(2) if an error is found when parsing + ExitOnError + // PanicOnError will panic() if an error is found when parsing flags + PanicOnError +) + +// NormalizedName is a flag name that has been normalized according to rules +// for the FlagSet (e.g. making '-' and '_' equivalent). +type NormalizedName string + +// A FlagSet represents a set of defined flags. +type FlagSet struct { + // Usage is the function called when an error occurs while parsing flags. + // The field is a function (not a method) that may be changed to point to + // a custom error handler. + Usage func() + + name string + parsed bool + actual map[NormalizedName]*Flag + formal map[NormalizedName]*Flag + shorthands map[byte]*Flag + args []string // arguments after flags + argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no -- + exitOnError bool // does the program exit if there's an error? + errorHandling ErrorHandling + output io.Writer // nil means stderr; use out() accessor + interspersed bool // allow interspersed option/non-option args + normalizeNameFunc func(f *FlagSet, name string) NormalizedName +} + +// A Flag represents the state of a flag. +type Flag struct { + Name string // name as it appears on command line + Shorthand string // one-letter abbreviated flag + Usage string // help message + Value Value // value as set + DefValue string // default value (as text); for usage message + Changed bool // If the user set the value (or if left to default) + NoOptDefVal string //default value (as text); if the flag is on the command line without any options + Deprecated string // If this flag is deprecated, this string is the new or now thing to use + Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text + ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use + Annotations map[string][]string // used by cobra.Command bash autocomple code +} + +// Value is the interface to the dynamic value stored in a flag. +// (The default value is represented as a string.) +type Value interface { + String() string + Set(string) error + Type() string +} + +// sortFlags returns the flags as a slice in lexicographical sorted order. +func sortFlags(flags map[NormalizedName]*Flag) []*Flag { + list := make(sort.StringSlice, len(flags)) + i := 0 + for k := range flags { + list[i] = string(k) + i++ + } + list.Sort() + result := make([]*Flag, len(list)) + for i, name := range list { + result[i] = flags[NormalizedName(name)] + } + return result +} + +// SetNormalizeFunc allows you to add a function which can translate flag names. +// Flags added to the FlagSet will be translated and then when anything tries to +// look up the flag that will also be translated. So it would be possible to create +// a flag named "getURL" and have it translated to "geturl". A user could then pass +// "--getUrl" which may also be translated to "geturl" and everything will work. +func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { + f.normalizeNameFunc = n + for k, v := range f.formal { + delete(f.formal, k) + nname := f.normalizeFlagName(string(k)) + f.formal[nname] = v + v.Name = string(nname) + } +} + +// GetNormalizeFunc returns the previously set NormalizeFunc of a function which +// does no translation, if not set previously. +func (f *FlagSet) GetNormalizeFunc() func(f *FlagSet, name string) NormalizedName { + if f.normalizeNameFunc != nil { + return f.normalizeNameFunc + } + return func(f *FlagSet, name string) NormalizedName { return NormalizedName(name) } +} + +func (f *FlagSet) normalizeFlagName(name string) NormalizedName { + n := f.GetNormalizeFunc() + return n(f, name) +} + +func (f *FlagSet) out() io.Writer { + if f.output == nil { + return os.Stderr + } + return f.output +} + +// SetOutput sets the destination for usage and error messages. +// If output is nil, os.Stderr is used. +func (f *FlagSet) SetOutput(output io.Writer) { + f.output = output +} + +// VisitAll visits the flags in lexicographical order, calling fn for each. +// It visits all flags, even those not set. +func (f *FlagSet) VisitAll(fn func(*Flag)) { + for _, flag := range sortFlags(f.formal) { + fn(flag) + } +} + +// HasFlags returns a bool to indicate if the FlagSet has any flags definied. +func (f *FlagSet) HasFlags() bool { + return len(f.formal) > 0 +} + +// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags +// definied that are not hidden or deprecated. +func (f *FlagSet) HasAvailableFlags() bool { + for _, flag := range f.formal { + if !flag.Hidden && len(flag.Deprecated) == 0 { + return true + } + } + return false +} + +// VisitAll visits the command-line flags in lexicographical order, calling +// fn for each. It visits all flags, even those not set. +func VisitAll(fn func(*Flag)) { + CommandLine.VisitAll(fn) +} + +// Visit visits the flags in lexicographical order, calling fn for each. +// It visits only those flags that have been set. +func (f *FlagSet) Visit(fn func(*Flag)) { + for _, flag := range sortFlags(f.actual) { + fn(flag) + } +} + +// Visit visits the command-line flags in lexicographical order, calling fn +// for each. It visits only those flags that have been set. +func Visit(fn func(*Flag)) { + CommandLine.Visit(fn) +} + +// Lookup returns the Flag structure of the named flag, returning nil if none exists. +func (f *FlagSet) Lookup(name string) *Flag { + return f.lookup(f.normalizeFlagName(name)) +} + +// lookup returns the Flag structure of the named flag, returning nil if none exists. +func (f *FlagSet) lookup(name NormalizedName) *Flag { + return f.formal[name] +} + +// func to return a given type for a given flag name +func (f *FlagSet) getFlagType(name string, ftype string, convFunc func(sval string) (interface{}, error)) (interface{}, error) { + flag := f.Lookup(name) + if flag == nil { + err := fmt.Errorf("flag accessed but not defined: %s", name) + return nil, err + } + + if flag.Value.Type() != ftype { + err := fmt.Errorf("trying to get %s value of flag of type %s", ftype, flag.Value.Type()) + return nil, err + } + + sval := flag.Value.String() + result, err := convFunc(sval) + if err != nil { + return nil, err + } + return result, nil +} + +// ArgsLenAtDash will return the length of f.Args at the moment when a -- was +// found during arg parsing. This allows your program to know which args were +// before the -- and which came after. +func (f *FlagSet) ArgsLenAtDash() int { + return f.argsLenAtDash +} + +// MarkDeprecated indicated that a flag is deprecated in your program. It will +// continue to function but will not show up in help or usage messages. Using +// this flag will also print the given usageMessage. +func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { + flag := f.Lookup(name) + if flag == nil { + return fmt.Errorf("flag %q does not exist", name) + } + if len(usageMessage) == 0 { + return fmt.Errorf("deprecated message for flag %q must be set", name) + } + flag.Deprecated = usageMessage + return nil +} + +// MarkShorthandDeprecated will mark the shorthand of a flag deprecated in your +// program. It will continue to function but will not show up in help or usage +// messages. Using this flag will also print the given usageMessage. +func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) error { + flag := f.Lookup(name) + if flag == nil { + return fmt.Errorf("flag %q does not exist", name) + } + if len(usageMessage) == 0 { + return fmt.Errorf("deprecated message for flag %q must be set", name) + } + flag.ShorthandDeprecated = usageMessage + return nil +} + +// MarkHidden sets a flag to 'hidden' in your program. It will continue to +// function but will not show up in help or usage messages. +func (f *FlagSet) MarkHidden(name string) error { + flag := f.Lookup(name) + if flag == nil { + return fmt.Errorf("flag %q does not exist", name) + } + flag.Hidden = true + return nil +} + +// Lookup returns the Flag structure of the named command-line flag, +// returning nil if none exists. +func Lookup(name string) *Flag { + return CommandLine.Lookup(name) +} + +// Set sets the value of the named flag. +func (f *FlagSet) Set(name, value string) error { + normalName := f.normalizeFlagName(name) + flag, ok := f.formal[normalName] + if !ok { + return fmt.Errorf("no such flag -%v", name) + } + err := flag.Value.Set(value) + if err != nil { + return err + } + if f.actual == nil { + f.actual = make(map[NormalizedName]*Flag) + } + f.actual[normalName] = flag + flag.Changed = true + if len(flag.Deprecated) > 0 { + fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) + } + return nil +} + +// SetAnnotation allows one to set arbitrary annotations on a flag in the FlagSet. +// This is sometimes used by spf13/cobra programs which want to generate additional +// bash completion information. +func (f *FlagSet) SetAnnotation(name, key string, values []string) error { + normalName := f.normalizeFlagName(name) + flag, ok := f.formal[normalName] + if !ok { + return fmt.Errorf("no such flag -%v", name) + } + if flag.Annotations == nil { + flag.Annotations = map[string][]string{} + } + flag.Annotations[key] = values + return nil +} + +// Changed returns true if the flag was explicitly set during Parse() and false +// otherwise +func (f *FlagSet) Changed(name string) bool { + flag := f.Lookup(name) + // If a flag doesn't exist, it wasn't changed.... + if flag == nil { + return false + } + return flag.Changed +} + +// Set sets the value of the named command-line flag. +func Set(name, value string) error { + return CommandLine.Set(name, value) +} + +// PrintDefaults prints, to standard error unless configured +// otherwise, the default values of all defined flags in the set. +func (f *FlagSet) PrintDefaults() { + usages := f.FlagUsages() + fmt.Fprint(f.out(), usages) +} + +// defaultIsZeroValue returns true if the default value for this flag represents +// a zero value. +func (f *Flag) defaultIsZeroValue() bool { + switch f.Value.(type) { + case boolFlag: + return f.DefValue == "false" + case *durationValue: + // Beginning in Go 1.7, duration zero values are "0s" + return f.DefValue == "0" || f.DefValue == "0s" + case *intValue, *int8Value, *int32Value, *int64Value, *uintValue, *uint8Value, *uint16Value, *uint32Value, *uint64Value, *countValue, *float32Value, *float64Value: + return f.DefValue == "0" + case *stringValue: + return f.DefValue == "" + case *ipValue, *ipMaskValue, *ipNetValue: + return f.DefValue == "" + case *intSliceValue, *stringSliceValue, *stringArrayValue: + return f.DefValue == "[]" + default: + switch f.Value.String() { + case "false": + return true + case "": + return true + case "": + return true + case "0": + return true + } + return false + } +} + +// UnquoteUsage extracts a back-quoted name from the usage +// string for a flag and returns it and the un-quoted usage. +// Given "a `name` to show" it returns ("name", "a name to show"). +// If there are no back quotes, the name is an educated guess of the +// type of the flag's value, or the empty string if the flag is boolean. +func UnquoteUsage(flag *Flag) (name string, usage string) { + // Look for a back-quoted name, but avoid the strings package. + usage = flag.Usage + 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 // Only one back quote; use type name. + } + } + + name = flag.Value.Type() + switch name { + case "bool": + name = "" + case "float64": + name = "float" + case "int64": + name = "int" + case "uint64": + name = "uint" + } + + return +} + +// Splits the string `s` on whitespace into an initial substring up to +// `i` runes in length and the remainder. Will go `slop` over `i` if +// that encompasses the entire string (which allows the caller to +// avoid short orphan words on the final line). +func wrapN(i, slop int, s string) (string, string) { + if i+slop > len(s) { + return s, "" + } + + w := strings.LastIndexAny(s[:i], " \t") + if w <= 0 { + return s, "" + } + + return s[:w], s[w+1:] +} + +// Wraps the string `s` to a maximum width `w` with leading indent +// `i`. The first line is not indented (this is assumed to be done by +// caller). Pass `w` == 0 to do no wrapping +func wrap(i, w int, s string) string { + if w == 0 { + return s + } + + // space between indent i and end of line width w into which + // we should wrap the text. + wrap := w - i + + var r, l string + + // Not enough space for sensible wrapping. Wrap as a block on + // the next line instead. + if wrap < 24 { + i = 16 + wrap = w - i + r += "\n" + strings.Repeat(" ", i) + } + // If still not enough space then don't even try to wrap. + if wrap < 24 { + return s + } + + // Try to avoid short orphan words on the final line, by + // allowing wrapN to go a bit over if that would fit in the + // remainder of the line. + slop := 5 + wrap = wrap - slop + + // Handle first line, which is indented by the caller (or the + // special case above) + l, s = wrapN(wrap, slop, s) + r = r + l + + // Now wrap the rest + for s != "" { + var t string + + t, s = wrapN(wrap, slop, s) + r = r + "\n" + strings.Repeat(" ", i) + t + } + + return r + +} + +// FlagUsagesWrapped returns a string containing the usage information +// for all flags in the FlagSet. Wrapped to `cols` columns (0 for no +// wrapping) +func (f *FlagSet) FlagUsagesWrapped(cols int) string { + x := new(bytes.Buffer) + + lines := make([]string, 0, len(f.formal)) + + maxlen := 0 + f.VisitAll(func(flag *Flag) { + if len(flag.Deprecated) > 0 || flag.Hidden { + return + } + + line := "" + if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 { + line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name) + } else { + line = fmt.Sprintf(" --%s", flag.Name) + } + + varname, usage := UnquoteUsage(flag) + if len(varname) > 0 { + line += " " + varname + } + if len(flag.NoOptDefVal) > 0 { + switch flag.Value.Type() { + case "string": + line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal) + case "bool": + if flag.NoOptDefVal != "true" { + line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) + } + default: + line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) + } + } + + // This special character will be replaced with spacing once the + // correct alignment is calculated + line += "\x00" + if len(line) > maxlen { + maxlen = len(line) + } + + line += usage + if !flag.defaultIsZeroValue() { + if flag.Value.Type() == "string" { + line += fmt.Sprintf(" (default \"%s\")", flag.DefValue) + } else { + line += fmt.Sprintf(" (default %s)", flag.DefValue) + } + } + + lines = append(lines, line) + }) + + for _, line := range lines { + sidx := strings.Index(line, "\x00") + spacing := strings.Repeat(" ", maxlen-sidx) + // maxlen + 2 comes from + 1 for the \x00 and + 1 for the (deliberate) off-by-one in maxlen-sidx + fmt.Fprintln(x, line[:sidx], spacing, wrap(maxlen+2, cols, line[sidx+1:])) + } + + return x.String() +} + +// FlagUsages returns a string containing the usage information for all flags in +// the FlagSet +func (f *FlagSet) FlagUsages() string { + return f.FlagUsagesWrapped(0) +} + +// PrintDefaults prints to standard error the default values of all defined command-line flags. +func PrintDefaults() { + CommandLine.PrintDefaults() +} + +// defaultUsage is the default function to print a usage message. +func defaultUsage(f *FlagSet) { + fmt.Fprintf(f.out(), "Usage of %s:\n", f.name) + f.PrintDefaults() +} + +// NOTE: Usage is not just defaultUsage(CommandLine) +// because it serves (via godoc flag Usage) as the example +// for how to write your own usage function. + +// Usage prints to standard error a usage message documenting all defined command-line flags. +// The function is a variable that may be changed to point to a custom function. +// By default it prints a simple header and calls PrintDefaults; for details about the +// format of the output and how to control it, see the documentation for PrintDefaults. +var Usage = func() { + fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) + PrintDefaults() +} + +// NFlag returns the number of flags that have been set. +func (f *FlagSet) NFlag() int { return len(f.actual) } + +// NFlag returns the number of command-line flags that have been set. +func NFlag() int { return len(CommandLine.actual) } + +// Arg returns the i'th argument. Arg(0) is the first remaining argument +// after flags have been processed. +func (f *FlagSet) Arg(i int) string { + if i < 0 || i >= len(f.args) { + return "" + } + return f.args[i] +} + +// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument +// after flags have been processed. +func Arg(i int) string { + return CommandLine.Arg(i) +} + +// NArg is the number of arguments remaining after flags have been processed. +func (f *FlagSet) NArg() int { return len(f.args) } + +// NArg is the number of arguments remaining after flags have been processed. +func NArg() int { return len(CommandLine.args) } + +// Args returns the non-flag arguments. +func (f *FlagSet) Args() []string { return f.args } + +// Args returns the non-flag command-line arguments. +func Args() []string { return CommandLine.args } + +// Var defines a flag with the specified name and usage string. The type and +// value of the flag are represented by the first argument, of type Value, which +// typically holds a user-defined implementation of Value. For instance, the +// caller could create a flag that turns a comma-separated string into a slice +// of strings by giving the slice the methods of Value; in particular, Set would +// decompose the comma-separated string into the slice. +func (f *FlagSet) Var(value Value, name string, usage string) { + f.VarP(value, name, "", usage) +} + +// VarPF is like VarP, but returns the flag created +func (f *FlagSet) VarPF(value Value, name, shorthand, usage string) *Flag { + // Remember the default value as a string; it won't change. + flag := &Flag{ + Name: name, + Shorthand: shorthand, + Usage: usage, + Value: value, + DefValue: value.String(), + } + f.AddFlag(flag) + return flag +} + +// VarP is like Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) VarP(value Value, name, shorthand, usage string) { + f.VarPF(value, name, shorthand, usage) +} + +// AddFlag will add the flag to the FlagSet +func (f *FlagSet) AddFlag(flag *Flag) { + // Call normalizeFlagName function only once + normalizedFlagName := f.normalizeFlagName(flag.Name) + + _, alreadythere := f.formal[normalizedFlagName] + if alreadythere { + msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name) + fmt.Fprintln(f.out(), msg) + panic(msg) // Happens only if flags are declared with identical names + } + if f.formal == nil { + f.formal = make(map[NormalizedName]*Flag) + } + + flag.Name = string(normalizedFlagName) + f.formal[normalizedFlagName] = flag + + if len(flag.Shorthand) == 0 { + return + } + if len(flag.Shorthand) > 1 { + fmt.Fprintf(f.out(), "%s shorthand more than ASCII character: %s\n", f.name, flag.Shorthand) + panic("shorthand is more than one character") + } + if f.shorthands == nil { + f.shorthands = make(map[byte]*Flag) + } + c := flag.Shorthand[0] + old, alreadythere := f.shorthands[c] + if alreadythere { + fmt.Fprintf(f.out(), "%s shorthand reused: %q for %s already used for %s\n", f.name, c, flag.Name, old.Name) + panic("shorthand redefinition") + } + f.shorthands[c] = flag +} + +// AddFlagSet adds one FlagSet to another. If a flag is already present in f +// the flag from newSet will be ignored +func (f *FlagSet) AddFlagSet(newSet *FlagSet) { + if newSet == nil { + return + } + newSet.VisitAll(func(flag *Flag) { + if f.Lookup(flag.Name) == nil { + f.AddFlag(flag) + } + }) +} + +// Var defines a flag with the specified name and usage string. The type and +// value of the flag are represented by the first argument, of type Value, which +// typically holds a user-defined implementation of Value. For instance, the +// caller could create a flag that turns a comma-separated string into a slice +// of strings by giving the slice the methods of Value; in particular, Set would +// decompose the comma-separated string into the slice. +func Var(value Value, name string, usage string) { + CommandLine.VarP(value, name, "", usage) +} + +// VarP is like Var, but accepts a shorthand letter that can be used after a single dash. +func VarP(value Value, name, shorthand, usage string) { + CommandLine.VarP(value, name, shorthand, usage) +} + +// failf prints to standard error a formatted error and usage message and +// returns the error. +func (f *FlagSet) failf(format string, a ...interface{}) error { + err := fmt.Errorf(format, a...) + fmt.Fprintln(f.out(), err) + f.usage() + return err +} + +// usage calls the Usage method for the flag set, or the usage function if +// the flag set is CommandLine. +func (f *FlagSet) usage() { + if f == CommandLine { + Usage() + } else if f.Usage == nil { + defaultUsage(f) + } else { + f.Usage() + } +} + +func (f *FlagSet) setFlag(flag *Flag, value string, origArg string) error { + if err := flag.Value.Set(value); err != nil { + return f.failf("invalid argument %q for %s: %v", value, origArg, err) + } + // mark as visited for Visit() + if f.actual == nil { + f.actual = make(map[NormalizedName]*Flag) + } + f.actual[f.normalizeFlagName(flag.Name)] = flag + flag.Changed = true + if len(flag.Deprecated) > 0 { + fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) + } + if len(flag.ShorthandDeprecated) > 0 && containsShorthand(origArg, flag.Shorthand) { + fmt.Fprintf(os.Stderr, "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated) + } + return nil +} + +func containsShorthand(arg, shorthand string) bool { + // filter out flags -- + if strings.HasPrefix(arg, "-") { + return false + } + arg = strings.SplitN(arg, "=", 2)[0] + return strings.Contains(arg, shorthand) +} + +func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) { + a = args + name := s[2:] + if len(name) == 0 || name[0] == '-' || name[0] == '=' { + err = f.failf("bad flag syntax: %s", s) + return + } + split := strings.SplitN(name, "=", 2) + name = split[0] + flag, alreadythere := f.formal[f.normalizeFlagName(name)] + if !alreadythere { + if name == "help" { // special case for nice help message. + f.usage() + return a, ErrHelp + } + err = f.failf("unknown flag: --%s", name) + return + } + var value string + if len(split) == 2 { + // '--flag=arg' + value = split[1] + } else if len(flag.NoOptDefVal) > 0 { + // '--flag' (arg was optional) + value = flag.NoOptDefVal + } else if len(a) > 0 { + // '--flag arg' + value = a[0] + a = a[1:] + } else { + // '--flag' (arg was required) + err = f.failf("flag needs an argument: %s", s) + return + } + err = fn(flag, value, s) + return +} + +func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) { + if strings.HasPrefix(shorthands, "test.") { + return + } + outArgs = args + outShorts = shorthands[1:] + c := shorthands[0] + + flag, alreadythere := f.shorthands[c] + if !alreadythere { + if c == 'h' { // special case for nice help message. + f.usage() + err = ErrHelp + return + } + //TODO continue on error + err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) + return + } + var value string + if len(shorthands) > 2 && shorthands[1] == '=' { + value = shorthands[2:] + outShorts = "" + } else if len(flag.NoOptDefVal) > 0 { + value = flag.NoOptDefVal + } else if len(shorthands) > 1 { + value = shorthands[1:] + outShorts = "" + } else if len(args) > 0 { + value = args[0] + outArgs = args[1:] + } else { + err = f.failf("flag needs an argument: %q in -%s", c, shorthands) + return + } + err = fn(flag, value, shorthands) + return +} + +func (f *FlagSet) parseShortArg(s string, args []string, fn parseFunc) (a []string, err error) { + a = args + shorthands := s[1:] + + for len(shorthands) > 0 { + shorthands, a, err = f.parseSingleShortArg(shorthands, args, fn) + if err != nil { + return + } + } + + return +} + +func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) { + for len(args) > 0 { + s := args[0] + args = args[1:] + if len(s) == 0 || s[0] != '-' || len(s) == 1 { + if !f.interspersed { + f.args = append(f.args, s) + f.args = append(f.args, args...) + return nil + } + f.args = append(f.args, s) + continue + } + + if s[1] == '-' { + if len(s) == 2 { // "--" terminates the flags + f.argsLenAtDash = len(f.args) + f.args = append(f.args, args...) + break + } + args, err = f.parseLongArg(s, args, fn) + } else { + args, err = f.parseShortArg(s, args, fn) + } + if err != nil { + return + } + } + return +} + +// Parse parses flag definitions from the argument list, which should not +// include the command name. Must be called after all flags in the FlagSet +// are defined and before flags are accessed by the program. +// The return value will be ErrHelp if -help was set but not defined. +func (f *FlagSet) Parse(arguments []string) error { + f.parsed = true + f.args = make([]string, 0, len(arguments)) + + assign := func(flag *Flag, value, origArg string) error { + return f.setFlag(flag, value, origArg) + } + + err := f.parseArgs(arguments, assign) + if err != nil { + switch f.errorHandling { + case ContinueOnError: + return err + case ExitOnError: + os.Exit(2) + case PanicOnError: + panic(err) + } + } + return nil +} + +type parseFunc func(flag *Flag, value, origArg string) error + +// ParseAll parses flag definitions from the argument list, which should not +// include the command name. The arguments for fn are flag and value. Must be +// called after all flags in the FlagSet are defined and before flags are +// accessed by the program. The return value will be ErrHelp if -help was set +// but not defined. +func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string) error) error { + f.parsed = true + f.args = make([]string, 0, len(arguments)) + + assign := func(flag *Flag, value, origArg string) error { + return fn(flag, value) + } + + err := f.parseArgs(arguments, assign) + if err != nil { + switch f.errorHandling { + case ContinueOnError: + return err + case ExitOnError: + os.Exit(2) + case PanicOnError: + panic(err) + } + } + return nil +} + +// Parsed reports whether f.Parse has been called. +func (f *FlagSet) Parsed() bool { + return f.parsed +} + +// Parse parses the command-line flags from os.Args[1:]. Must be called +// after all flags are defined and before flags are accessed by the program. +func Parse() { + // Ignore errors; CommandLine is set for ExitOnError. + CommandLine.Parse(os.Args[1:]) +} + +// ParseAll parses the command-line flags from os.Args[1:] and called fn for each. +// The arguments for fn are flag and value. Must be called after all flags are +// defined and before flags are accessed by the program. +func ParseAll(fn func(flag *Flag, value string) error) { + // Ignore errors; CommandLine is set for ExitOnError. + CommandLine.ParseAll(os.Args[1:], fn) +} + +// SetInterspersed sets whether to support interspersed option/non-option arguments. +func SetInterspersed(interspersed bool) { + CommandLine.SetInterspersed(interspersed) +} + +// Parsed returns true if the command-line flags have been parsed. +func Parsed() bool { + return CommandLine.Parsed() +} + +// CommandLine is the default set of command-line flags, parsed from os.Args. +var CommandLine = NewFlagSet(os.Args[0], ExitOnError) + +// NewFlagSet returns a new, empty flag set with the specified name and +// error handling property. +func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { + f := &FlagSet{ + name: name, + errorHandling: errorHandling, + argsLenAtDash: -1, + interspersed: true, + } + return f +} + +// SetInterspersed sets whether to support interspersed option/non-option arguments. +func (f *FlagSet) SetInterspersed(interspersed bool) { + f.interspersed = interspersed +} + +// Init sets the name and error handling property for a flag set. +// By default, the zero FlagSet uses an empty name and the +// ContinueOnError error handling policy. +func (f *FlagSet) Init(name string, errorHandling ErrorHandling) { + f.name = name + f.errorHandling = errorHandling + f.argsLenAtDash = -1 +} diff --git a/vendor/github.com/spf13/pflag/float32.go b/vendor/github.com/spf13/pflag/float32.go new file mode 100644 index 000000000..a243f81f7 --- /dev/null +++ b/vendor/github.com/spf13/pflag/float32.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- float32 Value +type float32Value float32 + +func newFloat32Value(val float32, p *float32) *float32Value { + *p = val + return (*float32Value)(p) +} + +func (f *float32Value) Set(s string) error { + v, err := strconv.ParseFloat(s, 32) + *f = float32Value(v) + return err +} + +func (f *float32Value) Type() string { + return "float32" +} + +func (f *float32Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 32) } + +func float32Conv(sval string) (interface{}, error) { + v, err := strconv.ParseFloat(sval, 32) + if err != nil { + return 0, err + } + return float32(v), nil +} + +// GetFloat32 return the float32 value of a flag with the given name +func (f *FlagSet) GetFloat32(name string) (float32, error) { + val, err := f.getFlagType(name, "float32", float32Conv) + if err != nil { + return 0, err + } + return val.(float32), nil +} + +// Float32Var defines a float32 flag with specified name, default value, and usage string. +// The argument p points to a float32 variable in which to store the value of the flag. +func (f *FlagSet) Float32Var(p *float32, name string, value float32, usage string) { + f.VarP(newFloat32Value(value, p), name, "", usage) +} + +// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Float32VarP(p *float32, name, shorthand string, value float32, usage string) { + f.VarP(newFloat32Value(value, p), name, shorthand, usage) +} + +// Float32Var defines a float32 flag with specified name, default value, and usage string. +// The argument p points to a float32 variable in which to store the value of the flag. +func Float32Var(p *float32, name string, value float32, usage string) { + CommandLine.VarP(newFloat32Value(value, p), name, "", usage) +} + +// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. +func Float32VarP(p *float32, name, shorthand string, value float32, usage string) { + CommandLine.VarP(newFloat32Value(value, p), name, shorthand, usage) +} + +// Float32 defines a float32 flag with specified name, default value, and usage string. +// The return value is the address of a float32 variable that stores the value of the flag. +func (f *FlagSet) Float32(name string, value float32, usage string) *float32 { + p := new(float32) + f.Float32VarP(p, name, "", value, usage) + return p +} + +// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Float32P(name, shorthand string, value float32, usage string) *float32 { + p := new(float32) + f.Float32VarP(p, name, shorthand, value, usage) + return p +} + +// Float32 defines a float32 flag with specified name, default value, and usage string. +// The return value is the address of a float32 variable that stores the value of the flag. +func Float32(name string, value float32, usage string) *float32 { + return CommandLine.Float32P(name, "", value, usage) +} + +// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. +func Float32P(name, shorthand string, value float32, usage string) *float32 { + return CommandLine.Float32P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/float64.go b/vendor/github.com/spf13/pflag/float64.go new file mode 100644 index 000000000..04b5492a7 --- /dev/null +++ b/vendor/github.com/spf13/pflag/float64.go @@ -0,0 +1,84 @@ +package pflag + +import "strconv" + +// -- float64 Value +type float64Value float64 + +func newFloat64Value(val float64, p *float64) *float64Value { + *p = val + return (*float64Value)(p) +} + +func (f *float64Value) Set(s string) error { + v, err := strconv.ParseFloat(s, 64) + *f = float64Value(v) + return err +} + +func (f *float64Value) Type() string { + return "float64" +} + +func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) } + +func float64Conv(sval string) (interface{}, error) { + return strconv.ParseFloat(sval, 64) +} + +// GetFloat64 return the float64 value of a flag with the given name +func (f *FlagSet) GetFloat64(name string) (float64, error) { + val, err := f.getFlagType(name, "float64", float64Conv) + if err != nil { + return 0, err + } + return val.(float64), nil +} + +// Float64Var defines a float64 flag with specified name, default value, and usage string. +// The argument p points to a float64 variable in which to store the value of the flag. +func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) { + f.VarP(newFloat64Value(value, p), name, "", usage) +} + +// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Float64VarP(p *float64, name, shorthand string, value float64, usage string) { + f.VarP(newFloat64Value(value, p), name, shorthand, usage) +} + +// Float64Var defines a float64 flag with specified name, default value, and usage string. +// The argument p points to a float64 variable in which to store the value of the flag. +func Float64Var(p *float64, name string, value float64, usage string) { + CommandLine.VarP(newFloat64Value(value, p), name, "", usage) +} + +// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. +func Float64VarP(p *float64, name, shorthand string, value float64, usage string) { + CommandLine.VarP(newFloat64Value(value, p), name, shorthand, usage) +} + +// Float64 defines a float64 flag with specified name, default value, and usage string. +// The return value is the address of a float64 variable that stores the value of the flag. +func (f *FlagSet) Float64(name string, value float64, usage string) *float64 { + p := new(float64) + f.Float64VarP(p, name, "", value, usage) + return p +} + +// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Float64P(name, shorthand string, value float64, usage string) *float64 { + p := new(float64) + f.Float64VarP(p, name, shorthand, value, usage) + return p +} + +// Float64 defines a float64 flag with specified name, default value, and usage string. +// The return value is the address of a float64 variable that stores the value of the flag. +func Float64(name string, value float64, usage string) *float64 { + return CommandLine.Float64P(name, "", value, usage) +} + +// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. +func Float64P(name, shorthand string, value float64, usage string) *float64 { + return CommandLine.Float64P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/golangflag.go b/vendor/github.com/spf13/pflag/golangflag.go new file mode 100644 index 000000000..c4f47ebe5 --- /dev/null +++ b/vendor/github.com/spf13/pflag/golangflag.go @@ -0,0 +1,101 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + goflag "flag" + "reflect" + "strings" +) + +// flagValueWrapper implements pflag.Value around a flag.Value. The main +// difference here is the addition of the Type method that returns a string +// name of the type. As this is generally unknown, we approximate that with +// reflection. +type flagValueWrapper struct { + inner goflag.Value + flagType string +} + +// We are just copying the boolFlag interface out of goflag as that is what +// they use to decide if a flag should get "true" when no arg is given. +type goBoolFlag interface { + goflag.Value + IsBoolFlag() bool +} + +func wrapFlagValue(v goflag.Value) Value { + // If the flag.Value happens to also be a pflag.Value, just use it directly. + if pv, ok := v.(Value); ok { + return pv + } + + pv := &flagValueWrapper{ + inner: v, + } + + t := reflect.TypeOf(v) + if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr { + t = t.Elem() + } + + pv.flagType = strings.TrimSuffix(t.Name(), "Value") + return pv +} + +func (v *flagValueWrapper) String() string { + return v.inner.String() +} + +func (v *flagValueWrapper) Set(s string) error { + return v.inner.Set(s) +} + +func (v *flagValueWrapper) Type() string { + return v.flagType +} + +// PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag +// If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei +// with both `-v` and `--v` in flags. If the golang flag was more than a single +// character (ex: `verbose`) it will only be accessible via `--verbose` +func PFlagFromGoFlag(goflag *goflag.Flag) *Flag { + // Remember the default value as a string; it won't change. + flag := &Flag{ + Name: goflag.Name, + Usage: goflag.Usage, + Value: wrapFlagValue(goflag.Value), + // Looks like golang flags don't set DefValue correctly :-( + //DefValue: goflag.DefValue, + DefValue: goflag.Value.String(), + } + // Ex: if the golang flag was -v, allow both -v and --v to work + if len(flag.Name) == 1 { + flag.Shorthand = flag.Name + } + if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() { + flag.NoOptDefVal = "true" + } + return flag +} + +// AddGoFlag will add the given *flag.Flag to the pflag.FlagSet +func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) { + if f.Lookup(goflag.Name) != nil { + return + } + newflag := PFlagFromGoFlag(goflag) + f.AddFlag(newflag) +} + +// AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet +func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { + if newSet == nil { + return + } + newSet.VisitAll(func(goflag *goflag.Flag) { + f.AddGoFlag(goflag) + }) +} diff --git a/vendor/github.com/spf13/pflag/int.go b/vendor/github.com/spf13/pflag/int.go new file mode 100644 index 000000000..1474b89df --- /dev/null +++ b/vendor/github.com/spf13/pflag/int.go @@ -0,0 +1,84 @@ +package pflag + +import "strconv" + +// -- int Value +type intValue int + +func newIntValue(val int, p *int) *intValue { + *p = val + return (*intValue)(p) +} + +func (i *intValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *i = intValue(v) + return err +} + +func (i *intValue) Type() string { + return "int" +} + +func (i *intValue) String() string { return strconv.Itoa(int(*i)) } + +func intConv(sval string) (interface{}, error) { + return strconv.Atoi(sval) +} + +// GetInt return the int value of a flag with the given name +func (f *FlagSet) GetInt(name string) (int, error) { + val, err := f.getFlagType(name, "int", intConv) + if err != nil { + return 0, err + } + return val.(int), nil +} + +// IntVar defines an int flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +func (f *FlagSet) IntVar(p *int, name string, value int, usage string) { + f.VarP(newIntValue(value, p), name, "", usage) +} + +// IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) { + f.VarP(newIntValue(value, p), name, shorthand, usage) +} + +// IntVar defines an int flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +func IntVar(p *int, name string, value int, usage string) { + CommandLine.VarP(newIntValue(value, p), name, "", usage) +} + +// IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. +func IntVarP(p *int, name, shorthand string, value int, usage string) { + CommandLine.VarP(newIntValue(value, p), name, shorthand, usage) +} + +// Int defines an int flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +func (f *FlagSet) Int(name string, value int, usage string) *int { + p := new(int) + f.IntVarP(p, name, "", value, usage) + return p +} + +// IntP is like Int, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IntP(name, shorthand string, value int, usage string) *int { + p := new(int) + f.IntVarP(p, name, shorthand, value, usage) + return p +} + +// Int defines an int flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +func Int(name string, value int, usage string) *int { + return CommandLine.IntP(name, "", value, usage) +} + +// IntP is like Int, but accepts a shorthand letter that can be used after a single dash. +func IntP(name, shorthand string, value int, usage string) *int { + return CommandLine.IntP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/int32.go b/vendor/github.com/spf13/pflag/int32.go new file mode 100644 index 000000000..9b95944f0 --- /dev/null +++ b/vendor/github.com/spf13/pflag/int32.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- int32 Value +type int32Value int32 + +func newInt32Value(val int32, p *int32) *int32Value { + *p = val + return (*int32Value)(p) +} + +func (i *int32Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 32) + *i = int32Value(v) + return err +} + +func (i *int32Value) Type() string { + return "int32" +} + +func (i *int32Value) String() string { return strconv.FormatInt(int64(*i), 10) } + +func int32Conv(sval string) (interface{}, error) { + v, err := strconv.ParseInt(sval, 0, 32) + if err != nil { + return 0, err + } + return int32(v), nil +} + +// GetInt32 return the int32 value of a flag with the given name +func (f *FlagSet) GetInt32(name string) (int32, error) { + val, err := f.getFlagType(name, "int32", int32Conv) + if err != nil { + return 0, err + } + return val.(int32), nil +} + +// Int32Var defines an int32 flag with specified name, default value, and usage string. +// The argument p points to an int32 variable in which to store the value of the flag. +func (f *FlagSet) Int32Var(p *int32, name string, value int32, usage string) { + f.VarP(newInt32Value(value, p), name, "", usage) +} + +// Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int32VarP(p *int32, name, shorthand string, value int32, usage string) { + f.VarP(newInt32Value(value, p), name, shorthand, usage) +} + +// Int32Var defines an int32 flag with specified name, default value, and usage string. +// The argument p points to an int32 variable in which to store the value of the flag. +func Int32Var(p *int32, name string, value int32, usage string) { + CommandLine.VarP(newInt32Value(value, p), name, "", usage) +} + +// Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. +func Int32VarP(p *int32, name, shorthand string, value int32, usage string) { + CommandLine.VarP(newInt32Value(value, p), name, shorthand, usage) +} + +// Int32 defines an int32 flag with specified name, default value, and usage string. +// The return value is the address of an int32 variable that stores the value of the flag. +func (f *FlagSet) Int32(name string, value int32, usage string) *int32 { + p := new(int32) + f.Int32VarP(p, name, "", value, usage) + return p +} + +// Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int32P(name, shorthand string, value int32, usage string) *int32 { + p := new(int32) + f.Int32VarP(p, name, shorthand, value, usage) + return p +} + +// Int32 defines an int32 flag with specified name, default value, and usage string. +// The return value is the address of an int32 variable that stores the value of the flag. +func Int32(name string, value int32, usage string) *int32 { + return CommandLine.Int32P(name, "", value, usage) +} + +// Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. +func Int32P(name, shorthand string, value int32, usage string) *int32 { + return CommandLine.Int32P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/int64.go b/vendor/github.com/spf13/pflag/int64.go new file mode 100644 index 000000000..0026d781d --- /dev/null +++ b/vendor/github.com/spf13/pflag/int64.go @@ -0,0 +1,84 @@ +package pflag + +import "strconv" + +// -- int64 Value +type int64Value int64 + +func newInt64Value(val int64, p *int64) *int64Value { + *p = val + return (*int64Value)(p) +} + +func (i *int64Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *i = int64Value(v) + return err +} + +func (i *int64Value) Type() string { + return "int64" +} + +func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) } + +func int64Conv(sval string) (interface{}, error) { + return strconv.ParseInt(sval, 0, 64) +} + +// GetInt64 return the int64 value of a flag with the given name +func (f *FlagSet) GetInt64(name string) (int64, error) { + val, err := f.getFlagType(name, "int64", int64Conv) + if err != nil { + return 0, err + } + return val.(int64), nil +} + +// Int64Var defines an int64 flag with specified name, default value, and usage string. +// The argument p points to an int64 variable in which to store the value of the flag. +func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) { + f.VarP(newInt64Value(value, p), name, "", usage) +} + +// Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int64VarP(p *int64, name, shorthand string, value int64, usage string) { + f.VarP(newInt64Value(value, p), name, shorthand, usage) +} + +// Int64Var defines an int64 flag with specified name, default value, and usage string. +// The argument p points to an int64 variable in which to store the value of the flag. +func Int64Var(p *int64, name string, value int64, usage string) { + CommandLine.VarP(newInt64Value(value, p), name, "", usage) +} + +// Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. +func Int64VarP(p *int64, name, shorthand string, value int64, usage string) { + CommandLine.VarP(newInt64Value(value, p), name, shorthand, usage) +} + +// Int64 defines an int64 flag with specified name, default value, and usage string. +// The return value is the address of an int64 variable that stores the value of the flag. +func (f *FlagSet) Int64(name string, value int64, usage string) *int64 { + p := new(int64) + f.Int64VarP(p, name, "", value, usage) + return p +} + +// Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int64P(name, shorthand string, value int64, usage string) *int64 { + p := new(int64) + f.Int64VarP(p, name, shorthand, value, usage) + return p +} + +// Int64 defines an int64 flag with specified name, default value, and usage string. +// The return value is the address of an int64 variable that stores the value of the flag. +func Int64(name string, value int64, usage string) *int64 { + return CommandLine.Int64P(name, "", value, usage) +} + +// Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. +func Int64P(name, shorthand string, value int64, usage string) *int64 { + return CommandLine.Int64P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/int8.go b/vendor/github.com/spf13/pflag/int8.go new file mode 100644 index 000000000..4da92228e --- /dev/null +++ b/vendor/github.com/spf13/pflag/int8.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- int8 Value +type int8Value int8 + +func newInt8Value(val int8, p *int8) *int8Value { + *p = val + return (*int8Value)(p) +} + +func (i *int8Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 8) + *i = int8Value(v) + return err +} + +func (i *int8Value) Type() string { + return "int8" +} + +func (i *int8Value) String() string { return strconv.FormatInt(int64(*i), 10) } + +func int8Conv(sval string) (interface{}, error) { + v, err := strconv.ParseInt(sval, 0, 8) + if err != nil { + return 0, err + } + return int8(v), nil +} + +// GetInt8 return the int8 value of a flag with the given name +func (f *FlagSet) GetInt8(name string) (int8, error) { + val, err := f.getFlagType(name, "int8", int8Conv) + if err != nil { + return 0, err + } + return val.(int8), nil +} + +// Int8Var defines an int8 flag with specified name, default value, and usage string. +// The argument p points to an int8 variable in which to store the value of the flag. +func (f *FlagSet) Int8Var(p *int8, name string, value int8, usage string) { + f.VarP(newInt8Value(value, p), name, "", usage) +} + +// Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int8VarP(p *int8, name, shorthand string, value int8, usage string) { + f.VarP(newInt8Value(value, p), name, shorthand, usage) +} + +// Int8Var defines an int8 flag with specified name, default value, and usage string. +// The argument p points to an int8 variable in which to store the value of the flag. +func Int8Var(p *int8, name string, value int8, usage string) { + CommandLine.VarP(newInt8Value(value, p), name, "", usage) +} + +// Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. +func Int8VarP(p *int8, name, shorthand string, value int8, usage string) { + CommandLine.VarP(newInt8Value(value, p), name, shorthand, usage) +} + +// Int8 defines an int8 flag with specified name, default value, and usage string. +// The return value is the address of an int8 variable that stores the value of the flag. +func (f *FlagSet) Int8(name string, value int8, usage string) *int8 { + p := new(int8) + f.Int8VarP(p, name, "", value, usage) + return p +} + +// Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Int8P(name, shorthand string, value int8, usage string) *int8 { + p := new(int8) + f.Int8VarP(p, name, shorthand, value, usage) + return p +} + +// Int8 defines an int8 flag with specified name, default value, and usage string. +// The return value is the address of an int8 variable that stores the value of the flag. +func Int8(name string, value int8, usage string) *int8 { + return CommandLine.Int8P(name, "", value, usage) +} + +// Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. +func Int8P(name, shorthand string, value int8, usage string) *int8 { + return CommandLine.Int8P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/int_slice.go b/vendor/github.com/spf13/pflag/int_slice.go new file mode 100644 index 000000000..1e7c9edde --- /dev/null +++ b/vendor/github.com/spf13/pflag/int_slice.go @@ -0,0 +1,128 @@ +package pflag + +import ( + "fmt" + "strconv" + "strings" +) + +// -- intSlice Value +type intSliceValue struct { + value *[]int + changed bool +} + +func newIntSliceValue(val []int, p *[]int) *intSliceValue { + isv := new(intSliceValue) + isv.value = p + *isv.value = val + return isv +} + +func (s *intSliceValue) Set(val string) error { + ss := strings.Split(val, ",") + out := make([]int, len(ss)) + for i, d := range ss { + var err error + out[i], err = strconv.Atoi(d) + if err != nil { + return err + } + + } + if !s.changed { + *s.value = out + } else { + *s.value = append(*s.value, out...) + } + s.changed = true + return nil +} + +func (s *intSliceValue) Type() string { + return "intSlice" +} + +func (s *intSliceValue) String() string { + out := make([]string, len(*s.value)) + for i, d := range *s.value { + out[i] = fmt.Sprintf("%d", d) + } + return "[" + strings.Join(out, ",") + "]" +} + +func intSliceConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // Empty string would cause a slice with one (empty) entry + if len(val) == 0 { + return []int{}, nil + } + ss := strings.Split(val, ",") + out := make([]int, len(ss)) + for i, d := range ss { + var err error + out[i], err = strconv.Atoi(d) + if err != nil { + return nil, err + } + + } + return out, nil +} + +// GetIntSlice return the []int value of a flag with the given name +func (f *FlagSet) GetIntSlice(name string) ([]int, error) { + val, err := f.getFlagType(name, "intSlice", intSliceConv) + if err != nil { + return []int{}, err + } + return val.([]int), nil +} + +// IntSliceVar defines a intSlice flag with specified name, default value, and usage string. +// The argument p points to a []int variable in which to store the value of the flag. +func (f *FlagSet) IntSliceVar(p *[]int, name string, value []int, usage string) { + f.VarP(newIntSliceValue(value, p), name, "", usage) +} + +// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { + f.VarP(newIntSliceValue(value, p), name, shorthand, usage) +} + +// IntSliceVar defines a int[] flag with specified name, default value, and usage string. +// The argument p points to a int[] variable in which to store the value of the flag. +func IntSliceVar(p *[]int, name string, value []int, usage string) { + CommandLine.VarP(newIntSliceValue(value, p), name, "", usage) +} + +// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. +func IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { + CommandLine.VarP(newIntSliceValue(value, p), name, shorthand, usage) +} + +// IntSlice defines a []int flag with specified name, default value, and usage string. +// The return value is the address of a []int variable that stores the value of the flag. +func (f *FlagSet) IntSlice(name string, value []int, usage string) *[]int { + p := []int{} + f.IntSliceVarP(&p, name, "", value, usage) + return &p +} + +// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IntSliceP(name, shorthand string, value []int, usage string) *[]int { + p := []int{} + f.IntSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// IntSlice defines a []int flag with specified name, default value, and usage string. +// The return value is the address of a []int variable that stores the value of the flag. +func IntSlice(name string, value []int, usage string) *[]int { + return CommandLine.IntSliceP(name, "", value, usage) +} + +// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. +func IntSliceP(name, shorthand string, value []int, usage string) *[]int { + return CommandLine.IntSliceP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/ip.go b/vendor/github.com/spf13/pflag/ip.go new file mode 100644 index 000000000..3d414ba69 --- /dev/null +++ b/vendor/github.com/spf13/pflag/ip.go @@ -0,0 +1,94 @@ +package pflag + +import ( + "fmt" + "net" + "strings" +) + +// -- net.IP value +type ipValue net.IP + +func newIPValue(val net.IP, p *net.IP) *ipValue { + *p = val + return (*ipValue)(p) +} + +func (i *ipValue) String() string { return net.IP(*i).String() } +func (i *ipValue) Set(s string) error { + ip := net.ParseIP(strings.TrimSpace(s)) + if ip == nil { + return fmt.Errorf("failed to parse IP: %q", s) + } + *i = ipValue(ip) + return nil +} + +func (i *ipValue) Type() string { + return "ip" +} + +func ipConv(sval string) (interface{}, error) { + ip := net.ParseIP(sval) + if ip != nil { + return ip, nil + } + return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) +} + +// GetIP return the net.IP value of a flag with the given name +func (f *FlagSet) GetIP(name string) (net.IP, error) { + val, err := f.getFlagType(name, "ip", ipConv) + if err != nil { + return nil, err + } + return val.(net.IP), nil +} + +// IPVar defines an net.IP flag with specified name, default value, and usage string. +// The argument p points to an net.IP variable in which to store the value of the flag. +func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) { + f.VarP(newIPValue(value, p), name, "", usage) +} + +// IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { + f.VarP(newIPValue(value, p), name, shorthand, usage) +} + +// IPVar defines an net.IP flag with specified name, default value, and usage string. +// The argument p points to an net.IP variable in which to store the value of the flag. +func IPVar(p *net.IP, name string, value net.IP, usage string) { + CommandLine.VarP(newIPValue(value, p), name, "", usage) +} + +// IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. +func IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { + CommandLine.VarP(newIPValue(value, p), name, shorthand, usage) +} + +// IP defines an net.IP flag with specified name, default value, and usage string. +// The return value is the address of an net.IP variable that stores the value of the flag. +func (f *FlagSet) IP(name string, value net.IP, usage string) *net.IP { + p := new(net.IP) + f.IPVarP(p, name, "", value, usage) + return p +} + +// IPP is like IP, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPP(name, shorthand string, value net.IP, usage string) *net.IP { + p := new(net.IP) + f.IPVarP(p, name, shorthand, value, usage) + return p +} + +// IP defines an net.IP flag with specified name, default value, and usage string. +// The return value is the address of an net.IP variable that stores the value of the flag. +func IP(name string, value net.IP, usage string) *net.IP { + return CommandLine.IPP(name, "", value, usage) +} + +// IPP is like IP, but accepts a shorthand letter that can be used after a single dash. +func IPP(name, shorthand string, value net.IP, usage string) *net.IP { + return CommandLine.IPP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/ip_slice.go b/vendor/github.com/spf13/pflag/ip_slice.go new file mode 100644 index 000000000..7dd196fe3 --- /dev/null +++ b/vendor/github.com/spf13/pflag/ip_slice.go @@ -0,0 +1,148 @@ +package pflag + +import ( + "fmt" + "io" + "net" + "strings" +) + +// -- ipSlice Value +type ipSliceValue struct { + value *[]net.IP + changed bool +} + +func newIPSliceValue(val []net.IP, p *[]net.IP) *ipSliceValue { + ipsv := new(ipSliceValue) + ipsv.value = p + *ipsv.value = val + return ipsv +} + +// Set converts, and assigns, the comma-separated IP argument string representation as the []net.IP value of this flag. +// If Set is called on a flag that already has a []net.IP assigned, the newly converted values will be appended. +func (s *ipSliceValue) Set(val string) error { + + // remove all quote characters + rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") + + // read flag arguments with CSV parser + ipStrSlice, err := readAsCSV(rmQuote.Replace(val)) + if err != nil && err != io.EOF { + return err + } + + // parse ip values into slice + out := make([]net.IP, 0, len(ipStrSlice)) + for _, ipStr := range ipStrSlice { + ip := net.ParseIP(strings.TrimSpace(ipStr)) + if ip == nil { + return fmt.Errorf("invalid string being converted to IP address: %s", ipStr) + } + out = append(out, ip) + } + + if !s.changed { + *s.value = out + } else { + *s.value = append(*s.value, out...) + } + + s.changed = true + + return nil +} + +// Type returns a string that uniquely represents this flag's type. +func (s *ipSliceValue) Type() string { + return "ipSlice" +} + +// String defines a "native" format for this net.IP slice flag value. +func (s *ipSliceValue) String() string { + + ipStrSlice := make([]string, len(*s.value)) + for i, ip := range *s.value { + ipStrSlice[i] = ip.String() + } + + out, _ := writeAsCSV(ipStrSlice) + + return "[" + out + "]" +} + +func ipSliceConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // Emtpy string would cause a slice with one (empty) entry + if len(val) == 0 { + return []net.IP{}, nil + } + ss := strings.Split(val, ",") + out := make([]net.IP, len(ss)) + for i, sval := range ss { + ip := net.ParseIP(strings.TrimSpace(sval)) + if ip == nil { + return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) + } + out[i] = ip + } + return out, nil +} + +// GetIPSlice returns the []net.IP value of a flag with the given name +func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error) { + val, err := f.getFlagType(name, "ipSlice", ipSliceConv) + if err != nil { + return []net.IP{}, err + } + return val.([]net.IP), nil +} + +// IPSliceVar defines a ipSlice flag with specified name, default value, and usage string. +// The argument p points to a []net.IP variable in which to store the value of the flag. +func (f *FlagSet) IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) { + f.VarP(newIPSliceValue(value, p), name, "", usage) +} + +// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) { + f.VarP(newIPSliceValue(value, p), name, shorthand, usage) +} + +// IPSliceVar defines a []net.IP flag with specified name, default value, and usage string. +// The argument p points to a []net.IP variable in which to store the value of the flag. +func IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) { + CommandLine.VarP(newIPSliceValue(value, p), name, "", usage) +} + +// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash. +func IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) { + CommandLine.VarP(newIPSliceValue(value, p), name, shorthand, usage) +} + +// IPSlice defines a []net.IP flag with specified name, default value, and usage string. +// The return value is the address of a []net.IP variable that stores the value of that flag. +func (f *FlagSet) IPSlice(name string, value []net.IP, usage string) *[]net.IP { + p := []net.IP{} + f.IPSliceVarP(&p, name, "", value, usage) + return &p +} + +// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP { + p := []net.IP{} + f.IPSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// IPSlice defines a []net.IP flag with specified name, default value, and usage string. +// The return value is the address of a []net.IP variable that stores the value of the flag. +func IPSlice(name string, value []net.IP, usage string) *[]net.IP { + return CommandLine.IPSliceP(name, "", value, usage) +} + +// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash. +func IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP { + return CommandLine.IPSliceP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/ipmask.go b/vendor/github.com/spf13/pflag/ipmask.go new file mode 100644 index 000000000..5bd44bd21 --- /dev/null +++ b/vendor/github.com/spf13/pflag/ipmask.go @@ -0,0 +1,122 @@ +package pflag + +import ( + "fmt" + "net" + "strconv" +) + +// -- net.IPMask value +type ipMaskValue net.IPMask + +func newIPMaskValue(val net.IPMask, p *net.IPMask) *ipMaskValue { + *p = val + return (*ipMaskValue)(p) +} + +func (i *ipMaskValue) String() string { return net.IPMask(*i).String() } +func (i *ipMaskValue) Set(s string) error { + ip := ParseIPv4Mask(s) + if ip == nil { + return fmt.Errorf("failed to parse IP mask: %q", s) + } + *i = ipMaskValue(ip) + return nil +} + +func (i *ipMaskValue) Type() string { + return "ipMask" +} + +// ParseIPv4Mask written in IP form (e.g. 255.255.255.0). +// This function should really belong to the net package. +func ParseIPv4Mask(s string) net.IPMask { + mask := net.ParseIP(s) + if mask == nil { + if len(s) != 8 { + return nil + } + // net.IPMask.String() actually outputs things like ffffff00 + // so write a horrible parser for that as well :-( + m := []int{} + for i := 0; i < 4; i++ { + b := "0x" + s[2*i:2*i+2] + d, err := strconv.ParseInt(b, 0, 0) + if err != nil { + return nil + } + m = append(m, int(d)) + } + s := fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3]) + mask = net.ParseIP(s) + if mask == nil { + return nil + } + } + return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15]) +} + +func parseIPv4Mask(sval string) (interface{}, error) { + mask := ParseIPv4Mask(sval) + if mask == nil { + return nil, fmt.Errorf("unable to parse %s as net.IPMask", sval) + } + return mask, nil +} + +// GetIPv4Mask return the net.IPv4Mask value of a flag with the given name +func (f *FlagSet) GetIPv4Mask(name string) (net.IPMask, error) { + val, err := f.getFlagType(name, "ipMask", parseIPv4Mask) + if err != nil { + return nil, err + } + return val.(net.IPMask), nil +} + +// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. +// The argument p points to an net.IPMask variable in which to store the value of the flag. +func (f *FlagSet) IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { + f.VarP(newIPMaskValue(value, p), name, "", usage) +} + +// IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { + f.VarP(newIPMaskValue(value, p), name, shorthand, usage) +} + +// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. +// The argument p points to an net.IPMask variable in which to store the value of the flag. +func IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { + CommandLine.VarP(newIPMaskValue(value, p), name, "", usage) +} + +// IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. +func IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { + CommandLine.VarP(newIPMaskValue(value, p), name, shorthand, usage) +} + +// IPMask defines an net.IPMask flag with specified name, default value, and usage string. +// The return value is the address of an net.IPMask variable that stores the value of the flag. +func (f *FlagSet) IPMask(name string, value net.IPMask, usage string) *net.IPMask { + p := new(net.IPMask) + f.IPMaskVarP(p, name, "", value, usage) + return p +} + +// IPMaskP is like IPMask, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { + p := new(net.IPMask) + f.IPMaskVarP(p, name, shorthand, value, usage) + return p +} + +// IPMask defines an net.IPMask flag with specified name, default value, and usage string. +// The return value is the address of an net.IPMask variable that stores the value of the flag. +func IPMask(name string, value net.IPMask, usage string) *net.IPMask { + return CommandLine.IPMaskP(name, "", value, usage) +} + +// IPMaskP is like IP, but accepts a shorthand letter that can be used after a single dash. +func IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { + return CommandLine.IPMaskP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/ipnet.go b/vendor/github.com/spf13/pflag/ipnet.go new file mode 100644 index 000000000..e2c1b8bcd --- /dev/null +++ b/vendor/github.com/spf13/pflag/ipnet.go @@ -0,0 +1,98 @@ +package pflag + +import ( + "fmt" + "net" + "strings" +) + +// IPNet adapts net.IPNet for use as a flag. +type ipNetValue net.IPNet + +func (ipnet ipNetValue) String() string { + n := net.IPNet(ipnet) + return n.String() +} + +func (ipnet *ipNetValue) Set(value string) error { + _, n, err := net.ParseCIDR(strings.TrimSpace(value)) + if err != nil { + return err + } + *ipnet = ipNetValue(*n) + return nil +} + +func (*ipNetValue) Type() string { + return "ipNet" +} + +func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue { + *p = val + return (*ipNetValue)(p) +} + +func ipNetConv(sval string) (interface{}, error) { + _, n, err := net.ParseCIDR(strings.TrimSpace(sval)) + if err == nil { + return *n, nil + } + return nil, fmt.Errorf("invalid string being converted to IPNet: %s", sval) +} + +// GetIPNet return the net.IPNet value of a flag with the given name +func (f *FlagSet) GetIPNet(name string) (net.IPNet, error) { + val, err := f.getFlagType(name, "ipNet", ipNetConv) + if err != nil { + return net.IPNet{}, err + } + return val.(net.IPNet), nil +} + +// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. +// The argument p points to an net.IPNet variable in which to store the value of the flag. +func (f *FlagSet) IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { + f.VarP(newIPNetValue(value, p), name, "", usage) +} + +// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { + f.VarP(newIPNetValue(value, p), name, shorthand, usage) +} + +// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. +// The argument p points to an net.IPNet variable in which to store the value of the flag. +func IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { + CommandLine.VarP(newIPNetValue(value, p), name, "", usage) +} + +// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. +func IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { + CommandLine.VarP(newIPNetValue(value, p), name, shorthand, usage) +} + +// IPNet defines an net.IPNet flag with specified name, default value, and usage string. +// The return value is the address of an net.IPNet variable that stores the value of the flag. +func (f *FlagSet) IPNet(name string, value net.IPNet, usage string) *net.IPNet { + p := new(net.IPNet) + f.IPNetVarP(p, name, "", value, usage) + return p +} + +// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { + p := new(net.IPNet) + f.IPNetVarP(p, name, shorthand, value, usage) + return p +} + +// IPNet defines an net.IPNet flag with specified name, default value, and usage string. +// The return value is the address of an net.IPNet variable that stores the value of the flag. +func IPNet(name string, value net.IPNet, usage string) *net.IPNet { + return CommandLine.IPNetP(name, "", value, usage) +} + +// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. +func IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { + return CommandLine.IPNetP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/string.go b/vendor/github.com/spf13/pflag/string.go new file mode 100644 index 000000000..04e0a26ff --- /dev/null +++ b/vendor/github.com/spf13/pflag/string.go @@ -0,0 +1,80 @@ +package pflag + +// -- string Value +type stringValue string + +func newStringValue(val string, p *string) *stringValue { + *p = val + return (*stringValue)(p) +} + +func (s *stringValue) Set(val string) error { + *s = stringValue(val) + return nil +} +func (s *stringValue) Type() string { + return "string" +} + +func (s *stringValue) String() string { return string(*s) } + +func stringConv(sval string) (interface{}, error) { + return sval, nil +} + +// GetString return the string value of a flag with the given name +func (f *FlagSet) GetString(name string) (string, error) { + val, err := f.getFlagType(name, "string", stringConv) + if err != nil { + return "", err + } + return val.(string), nil +} + +// StringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a string variable in which to store the value of the flag. +func (f *FlagSet) StringVar(p *string, name string, value string, usage string) { + f.VarP(newStringValue(value, p), name, "", usage) +} + +// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringVarP(p *string, name, shorthand string, value string, usage string) { + f.VarP(newStringValue(value, p), name, shorthand, usage) +} + +// StringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a string variable in which to store the value of the flag. +func StringVar(p *string, name string, value string, usage string) { + CommandLine.VarP(newStringValue(value, p), name, "", usage) +} + +// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. +func StringVarP(p *string, name, shorthand string, value string, usage string) { + CommandLine.VarP(newStringValue(value, p), name, shorthand, usage) +} + +// String defines a string flag with specified name, default value, and usage string. +// The return value is the address of a string variable that stores the value of the flag. +func (f *FlagSet) String(name string, value string, usage string) *string { + p := new(string) + f.StringVarP(p, name, "", value, usage) + return p +} + +// StringP is like String, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringP(name, shorthand string, value string, usage string) *string { + p := new(string) + f.StringVarP(p, name, shorthand, value, usage) + return p +} + +// String defines a string flag with specified name, default value, and usage string. +// The return value is the address of a string variable that stores the value of the flag. +func String(name string, value string, usage string) *string { + return CommandLine.StringP(name, "", value, usage) +} + +// StringP is like String, but accepts a shorthand letter that can be used after a single dash. +func StringP(name, shorthand string, value string, usage string) *string { + return CommandLine.StringP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/string_array.go b/vendor/github.com/spf13/pflag/string_array.go new file mode 100644 index 000000000..276b7ed49 --- /dev/null +++ b/vendor/github.com/spf13/pflag/string_array.go @@ -0,0 +1,103 @@ +package pflag + +// -- stringArray Value +type stringArrayValue struct { + value *[]string + changed bool +} + +func newStringArrayValue(val []string, p *[]string) *stringArrayValue { + ssv := new(stringArrayValue) + ssv.value = p + *ssv.value = val + return ssv +} + +func (s *stringArrayValue) Set(val string) error { + if !s.changed { + *s.value = []string{val} + s.changed = true + } else { + *s.value = append(*s.value, val) + } + return nil +} + +func (s *stringArrayValue) Type() string { + return "stringArray" +} + +func (s *stringArrayValue) String() string { + str, _ := writeAsCSV(*s.value) + return "[" + str + "]" +} + +func stringArrayConv(sval string) (interface{}, error) { + sval = sval[1 : len(sval)-1] + // An empty string would cause a array with one (empty) string + if len(sval) == 0 { + return []string{}, nil + } + return readAsCSV(sval) +} + +// GetStringArray return the []string value of a flag with the given name +func (f *FlagSet) GetStringArray(name string) ([]string, error) { + val, err := f.getFlagType(name, "stringArray", stringArrayConv) + if err != nil { + return []string{}, err + } + return val.([]string), nil +} + +// StringArrayVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a []string variable in which to store the values of the multiple flags. +// The value of each argument will not try to be separated by comma +func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) { + f.VarP(newStringArrayValue(value, p), name, "", usage) +} + +// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { + f.VarP(newStringArrayValue(value, p), name, shorthand, usage) +} + +// StringArrayVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a []string variable in which to store the value of the flag. +// The value of each argument will not try to be separated by comma +func StringArrayVar(p *[]string, name string, value []string, usage string) { + CommandLine.VarP(newStringArrayValue(value, p), name, "", usage) +} + +// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. +func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { + CommandLine.VarP(newStringArrayValue(value, p), name, shorthand, usage) +} + +// StringArray defines a string flag with specified name, default value, and usage string. +// The return value is the address of a []string variable that stores the value of the flag. +// The value of each argument will not try to be separated by comma +func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string { + p := []string{} + f.StringArrayVarP(&p, name, "", value, usage) + return &p +} + +// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage string) *[]string { + p := []string{} + f.StringArrayVarP(&p, name, shorthand, value, usage) + return &p +} + +// StringArray defines a string flag with specified name, default value, and usage string. +// The return value is the address of a []string variable that stores the value of the flag. +// The value of each argument will not try to be separated by comma +func StringArray(name string, value []string, usage string) *[]string { + return CommandLine.StringArrayP(name, "", value, usage) +} + +// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. +func StringArrayP(name, shorthand string, value []string, usage string) *[]string { + return CommandLine.StringArrayP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/string_slice.go b/vendor/github.com/spf13/pflag/string_slice.go new file mode 100644 index 000000000..05eee7543 --- /dev/null +++ b/vendor/github.com/spf13/pflag/string_slice.go @@ -0,0 +1,129 @@ +package pflag + +import ( + "bytes" + "encoding/csv" + "strings" +) + +// -- stringSlice Value +type stringSliceValue struct { + value *[]string + changed bool +} + +func newStringSliceValue(val []string, p *[]string) *stringSliceValue { + ssv := new(stringSliceValue) + ssv.value = p + *ssv.value = val + return ssv +} + +func readAsCSV(val string) ([]string, error) { + if val == "" { + return []string{}, nil + } + stringReader := strings.NewReader(val) + csvReader := csv.NewReader(stringReader) + return csvReader.Read() +} + +func writeAsCSV(vals []string) (string, error) { + b := &bytes.Buffer{} + w := csv.NewWriter(b) + err := w.Write(vals) + if err != nil { + return "", err + } + w.Flush() + return strings.TrimSuffix(b.String(), "\n"), nil +} + +func (s *stringSliceValue) Set(val string) error { + v, err := readAsCSV(val) + if err != nil { + return err + } + if !s.changed { + *s.value = v + } else { + *s.value = append(*s.value, v...) + } + s.changed = true + return nil +} + +func (s *stringSliceValue) Type() string { + return "stringSlice" +} + +func (s *stringSliceValue) String() string { + str, _ := writeAsCSV(*s.value) + return "[" + str + "]" +} + +func stringSliceConv(sval string) (interface{}, error) { + sval = sval[1 : len(sval)-1] + // An empty string would cause a slice with one (empty) string + if len(sval) == 0 { + return []string{}, nil + } + return readAsCSV(sval) +} + +// GetStringSlice return the []string value of a flag with the given name +func (f *FlagSet) GetStringSlice(name string) ([]string, error) { + val, err := f.getFlagType(name, "stringSlice", stringSliceConv) + if err != nil { + return []string{}, err + } + return val.([]string), nil +} + +// StringSliceVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a []string variable in which to store the value of the flag. +func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) { + f.VarP(newStringSliceValue(value, p), name, "", usage) +} + +// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { + f.VarP(newStringSliceValue(value, p), name, shorthand, usage) +} + +// StringSliceVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a []string variable in which to store the value of the flag. +func StringSliceVar(p *[]string, name string, value []string, usage string) { + CommandLine.VarP(newStringSliceValue(value, p), name, "", usage) +} + +// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. +func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { + CommandLine.VarP(newStringSliceValue(value, p), name, shorthand, usage) +} + +// StringSlice defines a string flag with specified name, default value, and usage string. +// The return value is the address of a []string variable that stores the value of the flag. +func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string { + p := []string{} + f.StringSliceVarP(&p, name, "", value, usage) + return &p +} + +// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage string) *[]string { + p := []string{} + f.StringSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// StringSlice defines a string flag with specified name, default value, and usage string. +// The return value is the address of a []string variable that stores the value of the flag. +func StringSlice(name string, value []string, usage string) *[]string { + return CommandLine.StringSliceP(name, "", value, usage) +} + +// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. +func StringSliceP(name, shorthand string, value []string, usage string) *[]string { + return CommandLine.StringSliceP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint.go b/vendor/github.com/spf13/pflag/uint.go new file mode 100644 index 000000000..dcbc2b758 --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- uint Value +type uintValue uint + +func newUintValue(val uint, p *uint) *uintValue { + *p = val + return (*uintValue)(p) +} + +func (i *uintValue) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 64) + *i = uintValue(v) + return err +} + +func (i *uintValue) Type() string { + return "uint" +} + +func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) } + +func uintConv(sval string) (interface{}, error) { + v, err := strconv.ParseUint(sval, 0, 0) + if err != nil { + return 0, err + } + return uint(v), nil +} + +// GetUint return the uint value of a flag with the given name +func (f *FlagSet) GetUint(name string) (uint, error) { + val, err := f.getFlagType(name, "uint", uintConv) + if err != nil { + return 0, err + } + return val.(uint), nil +} + +// UintVar defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) { + f.VarP(newUintValue(value, p), name, "", usage) +} + +// UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) UintVarP(p *uint, name, shorthand string, value uint, usage string) { + f.VarP(newUintValue(value, p), name, shorthand, usage) +} + +// UintVar defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func UintVar(p *uint, name string, value uint, usage string) { + CommandLine.VarP(newUintValue(value, p), name, "", usage) +} + +// UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. +func UintVarP(p *uint, name, shorthand string, value uint, usage string) { + CommandLine.VarP(newUintValue(value, p), name, shorthand, usage) +} + +// Uint defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func (f *FlagSet) Uint(name string, value uint, usage string) *uint { + p := new(uint) + f.UintVarP(p, name, "", value, usage) + return p +} + +// UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) UintP(name, shorthand string, value uint, usage string) *uint { + p := new(uint) + f.UintVarP(p, name, shorthand, value, usage) + return p +} + +// Uint defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func Uint(name string, value uint, usage string) *uint { + return CommandLine.UintP(name, "", value, usage) +} + +// UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. +func UintP(name, shorthand string, value uint, usage string) *uint { + return CommandLine.UintP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint16.go b/vendor/github.com/spf13/pflag/uint16.go new file mode 100644 index 000000000..7e9914edd --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint16.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- uint16 value +type uint16Value uint16 + +func newUint16Value(val uint16, p *uint16) *uint16Value { + *p = val + return (*uint16Value)(p) +} + +func (i *uint16Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 16) + *i = uint16Value(v) + return err +} + +func (i *uint16Value) Type() string { + return "uint16" +} + +func (i *uint16Value) String() string { return strconv.FormatUint(uint64(*i), 10) } + +func uint16Conv(sval string) (interface{}, error) { + v, err := strconv.ParseUint(sval, 0, 16) + if err != nil { + return 0, err + } + return uint16(v), nil +} + +// GetUint16 return the uint16 value of a flag with the given name +func (f *FlagSet) GetUint16(name string) (uint16, error) { + val, err := f.getFlagType(name, "uint16", uint16Conv) + if err != nil { + return 0, err + } + return val.(uint16), nil +} + +// Uint16Var defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func (f *FlagSet) Uint16Var(p *uint16, name string, value uint16, usage string) { + f.VarP(newUint16Value(value, p), name, "", usage) +} + +// Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { + f.VarP(newUint16Value(value, p), name, shorthand, usage) +} + +// Uint16Var defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func Uint16Var(p *uint16, name string, value uint16, usage string) { + CommandLine.VarP(newUint16Value(value, p), name, "", usage) +} + +// Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. +func Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { + CommandLine.VarP(newUint16Value(value, p), name, shorthand, usage) +} + +// Uint16 defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func (f *FlagSet) Uint16(name string, value uint16, usage string) *uint16 { + p := new(uint16) + f.Uint16VarP(p, name, "", value, usage) + return p +} + +// Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint16P(name, shorthand string, value uint16, usage string) *uint16 { + p := new(uint16) + f.Uint16VarP(p, name, shorthand, value, usage) + return p +} + +// Uint16 defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func Uint16(name string, value uint16, usage string) *uint16 { + return CommandLine.Uint16P(name, "", value, usage) +} + +// Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. +func Uint16P(name, shorthand string, value uint16, usage string) *uint16 { + return CommandLine.Uint16P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint32.go b/vendor/github.com/spf13/pflag/uint32.go new file mode 100644 index 000000000..d8024539b --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint32.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- uint32 value +type uint32Value uint32 + +func newUint32Value(val uint32, p *uint32) *uint32Value { + *p = val + return (*uint32Value)(p) +} + +func (i *uint32Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 32) + *i = uint32Value(v) + return err +} + +func (i *uint32Value) Type() string { + return "uint32" +} + +func (i *uint32Value) String() string { return strconv.FormatUint(uint64(*i), 10) } + +func uint32Conv(sval string) (interface{}, error) { + v, err := strconv.ParseUint(sval, 0, 32) + if err != nil { + return 0, err + } + return uint32(v), nil +} + +// GetUint32 return the uint32 value of a flag with the given name +func (f *FlagSet) GetUint32(name string) (uint32, error) { + val, err := f.getFlagType(name, "uint32", uint32Conv) + if err != nil { + return 0, err + } + return val.(uint32), nil +} + +// Uint32Var defines a uint32 flag with specified name, default value, and usage string. +// The argument p points to a uint32 variable in which to store the value of the flag. +func (f *FlagSet) Uint32Var(p *uint32, name string, value uint32, usage string) { + f.VarP(newUint32Value(value, p), name, "", usage) +} + +// Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { + f.VarP(newUint32Value(value, p), name, shorthand, usage) +} + +// Uint32Var defines a uint32 flag with specified name, default value, and usage string. +// The argument p points to a uint32 variable in which to store the value of the flag. +func Uint32Var(p *uint32, name string, value uint32, usage string) { + CommandLine.VarP(newUint32Value(value, p), name, "", usage) +} + +// Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. +func Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { + CommandLine.VarP(newUint32Value(value, p), name, shorthand, usage) +} + +// Uint32 defines a uint32 flag with specified name, default value, and usage string. +// The return value is the address of a uint32 variable that stores the value of the flag. +func (f *FlagSet) Uint32(name string, value uint32, usage string) *uint32 { + p := new(uint32) + f.Uint32VarP(p, name, "", value, usage) + return p +} + +// Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint32P(name, shorthand string, value uint32, usage string) *uint32 { + p := new(uint32) + f.Uint32VarP(p, name, shorthand, value, usage) + return p +} + +// Uint32 defines a uint32 flag with specified name, default value, and usage string. +// The return value is the address of a uint32 variable that stores the value of the flag. +func Uint32(name string, value uint32, usage string) *uint32 { + return CommandLine.Uint32P(name, "", value, usage) +} + +// Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. +func Uint32P(name, shorthand string, value uint32, usage string) *uint32 { + return CommandLine.Uint32P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint64.go b/vendor/github.com/spf13/pflag/uint64.go new file mode 100644 index 000000000..f62240f2c --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint64.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- uint64 Value +type uint64Value uint64 + +func newUint64Value(val uint64, p *uint64) *uint64Value { + *p = val + return (*uint64Value)(p) +} + +func (i *uint64Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 64) + *i = uint64Value(v) + return err +} + +func (i *uint64Value) Type() string { + return "uint64" +} + +func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) } + +func uint64Conv(sval string) (interface{}, error) { + v, err := strconv.ParseUint(sval, 0, 64) + if err != nil { + return 0, err + } + return uint64(v), nil +} + +// GetUint64 return the uint64 value of a flag with the given name +func (f *FlagSet) GetUint64(name string) (uint64, error) { + val, err := f.getFlagType(name, "uint64", uint64Conv) + if err != nil { + return 0, err + } + return val.(uint64), nil +} + +// Uint64Var defines a uint64 flag with specified name, default value, and usage string. +// The argument p points to a uint64 variable in which to store the value of the flag. +func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) { + f.VarP(newUint64Value(value, p), name, "", usage) +} + +// Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { + f.VarP(newUint64Value(value, p), name, shorthand, usage) +} + +// Uint64Var defines a uint64 flag with specified name, default value, and usage string. +// The argument p points to a uint64 variable in which to store the value of the flag. +func Uint64Var(p *uint64, name string, value uint64, usage string) { + CommandLine.VarP(newUint64Value(value, p), name, "", usage) +} + +// Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. +func Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { + CommandLine.VarP(newUint64Value(value, p), name, shorthand, usage) +} + +// Uint64 defines a uint64 flag with specified name, default value, and usage string. +// The return value is the address of a uint64 variable that stores the value of the flag. +func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 { + p := new(uint64) + f.Uint64VarP(p, name, "", value, usage) + return p +} + +// Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint64P(name, shorthand string, value uint64, usage string) *uint64 { + p := new(uint64) + f.Uint64VarP(p, name, shorthand, value, usage) + return p +} + +// Uint64 defines a uint64 flag with specified name, default value, and usage string. +// The return value is the address of a uint64 variable that stores the value of the flag. +func Uint64(name string, value uint64, usage string) *uint64 { + return CommandLine.Uint64P(name, "", value, usage) +} + +// Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. +func Uint64P(name, shorthand string, value uint64, usage string) *uint64 { + return CommandLine.Uint64P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint8.go b/vendor/github.com/spf13/pflag/uint8.go new file mode 100644 index 000000000..bb0e83c1f --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint8.go @@ -0,0 +1,88 @@ +package pflag + +import "strconv" + +// -- uint8 Value +type uint8Value uint8 + +func newUint8Value(val uint8, p *uint8) *uint8Value { + *p = val + return (*uint8Value)(p) +} + +func (i *uint8Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 8) + *i = uint8Value(v) + return err +} + +func (i *uint8Value) Type() string { + return "uint8" +} + +func (i *uint8Value) String() string { return strconv.FormatUint(uint64(*i), 10) } + +func uint8Conv(sval string) (interface{}, error) { + v, err := strconv.ParseUint(sval, 0, 8) + if err != nil { + return 0, err + } + return uint8(v), nil +} + +// GetUint8 return the uint8 value of a flag with the given name +func (f *FlagSet) GetUint8(name string) (uint8, error) { + val, err := f.getFlagType(name, "uint8", uint8Conv) + if err != nil { + return 0, err + } + return val.(uint8), nil +} + +// Uint8Var defines a uint8 flag with specified name, default value, and usage string. +// The argument p points to a uint8 variable in which to store the value of the flag. +func (f *FlagSet) Uint8Var(p *uint8, name string, value uint8, usage string) { + f.VarP(newUint8Value(value, p), name, "", usage) +} + +// Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { + f.VarP(newUint8Value(value, p), name, shorthand, usage) +} + +// Uint8Var defines a uint8 flag with specified name, default value, and usage string. +// The argument p points to a uint8 variable in which to store the value of the flag. +func Uint8Var(p *uint8, name string, value uint8, usage string) { + CommandLine.VarP(newUint8Value(value, p), name, "", usage) +} + +// Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. +func Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { + CommandLine.VarP(newUint8Value(value, p), name, shorthand, usage) +} + +// Uint8 defines a uint8 flag with specified name, default value, and usage string. +// The return value is the address of a uint8 variable that stores the value of the flag. +func (f *FlagSet) Uint8(name string, value uint8, usage string) *uint8 { + p := new(uint8) + f.Uint8VarP(p, name, "", value, usage) + return p +} + +// Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) Uint8P(name, shorthand string, value uint8, usage string) *uint8 { + p := new(uint8) + f.Uint8VarP(p, name, shorthand, value, usage) + return p +} + +// Uint8 defines a uint8 flag with specified name, default value, and usage string. +// The return value is the address of a uint8 variable that stores the value of the flag. +func Uint8(name string, value uint8, usage string) *uint8 { + return CommandLine.Uint8P(name, "", value, usage) +} + +// Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. +func Uint8P(name, shorthand string, value uint8, usage string) *uint8 { + return CommandLine.Uint8P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/uint_slice.go b/vendor/github.com/spf13/pflag/uint_slice.go new file mode 100644 index 000000000..edd94c600 --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint_slice.go @@ -0,0 +1,126 @@ +package pflag + +import ( + "fmt" + "strconv" + "strings" +) + +// -- uintSlice Value +type uintSliceValue struct { + value *[]uint + changed bool +} + +func newUintSliceValue(val []uint, p *[]uint) *uintSliceValue { + uisv := new(uintSliceValue) + uisv.value = p + *uisv.value = val + return uisv +} + +func (s *uintSliceValue) Set(val string) error { + ss := strings.Split(val, ",") + out := make([]uint, len(ss)) + for i, d := range ss { + u, err := strconv.ParseUint(d, 10, 0) + if err != nil { + return err + } + out[i] = uint(u) + } + if !s.changed { + *s.value = out + } else { + *s.value = append(*s.value, out...) + } + s.changed = true + return nil +} + +func (s *uintSliceValue) Type() string { + return "uintSlice" +} + +func (s *uintSliceValue) String() string { + out := make([]string, len(*s.value)) + for i, d := range *s.value { + out[i] = fmt.Sprintf("%d", d) + } + return "[" + strings.Join(out, ",") + "]" +} + +func uintSliceConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // Empty string would cause a slice with one (empty) entry + if len(val) == 0 { + return []uint{}, nil + } + ss := strings.Split(val, ",") + out := make([]uint, len(ss)) + for i, d := range ss { + u, err := strconv.ParseUint(d, 10, 0) + if err != nil { + return nil, err + } + out[i] = uint(u) + } + return out, nil +} + +// GetUintSlice returns the []uint value of a flag with the given name. +func (f *FlagSet) GetUintSlice(name string) ([]uint, error) { + val, err := f.getFlagType(name, "uintSlice", uintSliceConv) + if err != nil { + return []uint{}, err + } + return val.([]uint), nil +} + +// UintSliceVar defines a uintSlice flag with specified name, default value, and usage string. +// The argument p points to a []uint variable in which to store the value of the flag. +func (f *FlagSet) UintSliceVar(p *[]uint, name string, value []uint, usage string) { + f.VarP(newUintSliceValue(value, p), name, "", usage) +} + +// UintSliceVarP is like UintSliceVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { + f.VarP(newUintSliceValue(value, p), name, shorthand, usage) +} + +// UintSliceVar defines a uint[] flag with specified name, default value, and usage string. +// The argument p points to a uint[] variable in which to store the value of the flag. +func UintSliceVar(p *[]uint, name string, value []uint, usage string) { + CommandLine.VarP(newUintSliceValue(value, p), name, "", usage) +} + +// UintSliceVarP is like the UintSliceVar, but accepts a shorthand letter that can be used after a single dash. +func UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { + CommandLine.VarP(newUintSliceValue(value, p), name, shorthand, usage) +} + +// UintSlice defines a []uint flag with specified name, default value, and usage string. +// The return value is the address of a []uint variable that stores the value of the flag. +func (f *FlagSet) UintSlice(name string, value []uint, usage string) *[]uint { + p := []uint{} + f.UintSliceVarP(&p, name, "", value, usage) + return &p +} + +// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { + p := []uint{} + f.UintSliceVarP(&p, name, shorthand, value, usage) + return &p +} + +// UintSlice defines a []uint flag with specified name, default value, and usage string. +// The return value is the address of a []uint variable that stores the value of the flag. +func UintSlice(name string, value []uint, usage string) *[]uint { + return CommandLine.UintSliceP(name, "", value, usage) +} + +// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. +func UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { + return CommandLine.UintSliceP(name, shorthand, value, usage) +} diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/LICENSE b/vendor/golang.org/x/crypto/LICENSE similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/LICENSE rename to vendor/golang.org/x/crypto/LICENSE diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/PATENTS b/vendor/golang.org/x/crypto/PATENTS similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/PATENTS rename to vendor/golang.org/x/crypto/PATENTS diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/README b/vendor/golang.org/x/crypto/README similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/README rename to vendor/golang.org/x/crypto/README diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/const_amd64.h b/vendor/golang.org/x/crypto/curve25519/const_amd64.h similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/const_amd64.h rename to vendor/golang.org/x/crypto/curve25519/const_amd64.h diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/const_amd64.s b/vendor/golang.org/x/crypto/curve25519/const_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/const_amd64.s rename to vendor/golang.org/x/crypto/curve25519/const_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s b/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s rename to vendor/golang.org/x/crypto/curve25519/cswap_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/golang.org/x/crypto/curve25519/curve25519.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/curve25519.go rename to vendor/golang.org/x/crypto/curve25519/curve25519.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/doc.go b/vendor/golang.org/x/crypto/curve25519/doc.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/doc.go rename to vendor/golang.org/x/crypto/curve25519/doc.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s b/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s rename to vendor/golang.org/x/crypto/curve25519/freeze_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s b/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s rename to vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go b/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go rename to vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/mul_amd64.s b/vendor/golang.org/x/crypto/curve25519/mul_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/mul_amd64.s rename to vendor/golang.org/x/crypto/curve25519/mul_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/square_amd64.s b/vendor/golang.org/x/crypto/curve25519/square_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/curve25519/square_amd64.s rename to vendor/golang.org/x/crypto/curve25519/square_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go rename to vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/crypto/scrypt/scrypt.go rename to vendor/golang.org/x/crypto/scrypt/scrypt.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/LICENSE b/vendor/golang.org/x/sys/LICENSE similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/LICENSE rename to vendor/golang.org/x/sys/LICENSE diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/PATENTS b/vendor/golang.org/x/sys/PATENTS similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/PATENTS rename to vendor/golang.org/x/sys/PATENTS diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/README b/vendor/golang.org/x/sys/README similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/README rename to vendor/golang.org/x/sys/README diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_darwin_386.s b/vendor/golang.org/x/sys/unix/asm_darwin_386.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_darwin_386.s rename to vendor/golang.org/x/sys/unix/asm_darwin_386.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s b/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s rename to vendor/golang.org/x/sys/unix/asm_darwin_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_darwin_arm.s b/vendor/golang.org/x/sys/unix/asm_darwin_arm.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_darwin_arm.s rename to vendor/golang.org/x/sys/unix/asm_darwin_arm.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s b/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s rename to vendor/golang.org/x/sys/unix/asm_darwin_arm64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s b/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s rename to vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_freebsd_386.s b/vendor/golang.org/x/sys/unix/asm_freebsd_386.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_freebsd_386.s rename to vendor/golang.org/x/sys/unix/asm_freebsd_386.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s b/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s rename to vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s b/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s rename to vendor/golang.org/x/sys/unix/asm_freebsd_arm.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_386.s b/vendor/golang.org/x/sys/unix/asm_linux_386.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_386.s rename to vendor/golang.org/x/sys/unix/asm_linux_386.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_amd64.s b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_amd64.s rename to vendor/golang.org/x/sys/unix/asm_linux_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_arm.s b/vendor/golang.org/x/sys/unix/asm_linux_arm.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_arm.s rename to vendor/golang.org/x/sys/unix/asm_linux_arm.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_arm64.s b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_arm64.s rename to vendor/golang.org/x/sys/unix/asm_linux_arm64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s rename to vendor/golang.org/x/sys/unix/asm_linux_mips64x.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s rename to vendor/golang.org/x/sys/unix/asm_linux_mipsx.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s rename to vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_s390x.s b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_linux_s390x.s rename to vendor/golang.org/x/sys/unix/asm_linux_s390x.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_netbsd_386.s b/vendor/golang.org/x/sys/unix/asm_netbsd_386.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_netbsd_386.s rename to vendor/golang.org/x/sys/unix/asm_netbsd_386.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s b/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s rename to vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s b/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s rename to vendor/golang.org/x/sys/unix/asm_netbsd_arm.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_openbsd_386.s b/vendor/golang.org/x/sys/unix/asm_openbsd_386.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_openbsd_386.s rename to vendor/golang.org/x/sys/unix/asm_openbsd_386.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s b/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s rename to vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s b/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s rename to vendor/golang.org/x/sys/unix/asm_solaris_amd64.s diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/bluetooth_linux.go b/vendor/golang.org/x/sys/unix/bluetooth_linux.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/bluetooth_linux.go rename to vendor/golang.org/x/sys/unix/bluetooth_linux.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/constants.go b/vendor/golang.org/x/sys/unix/constants.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/constants.go rename to vendor/golang.org/x/sys/unix/constants.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/env_unix.go b/vendor/golang.org/x/sys/unix/env_unix.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/env_unix.go rename to vendor/golang.org/x/sys/unix/env_unix.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/env_unset.go b/vendor/golang.org/x/sys/unix/env_unset.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/env_unset.go rename to vendor/golang.org/x/sys/unix/env_unset.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/flock.go b/vendor/golang.org/x/sys/unix/flock.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/flock.go rename to vendor/golang.org/x/sys/unix/flock.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/flock_linux_32bit.go b/vendor/golang.org/x/sys/unix/flock_linux_32bit.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/flock_linux_32bit.go rename to vendor/golang.org/x/sys/unix/flock_linux_32bit.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/gccgo.go b/vendor/golang.org/x/sys/unix/gccgo.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/gccgo.go rename to vendor/golang.org/x/sys/unix/gccgo.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/gccgo_c.c b/vendor/golang.org/x/sys/unix/gccgo_c.c similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/gccgo_c.c rename to vendor/golang.org/x/sys/unix/gccgo_c.c diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go b/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go rename to vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/gccgo_linux_sparc64.go b/vendor/golang.org/x/sys/unix/gccgo_linux_sparc64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/gccgo_linux_sparc64.go rename to vendor/golang.org/x/sys/unix/gccgo_linux_sparc64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/mkpost.go b/vendor/golang.org/x/sys/unix/mkpost.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/mkpost.go rename to vendor/golang.org/x/sys/unix/mkpost.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/race.go b/vendor/golang.org/x/sys/unix/race.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/race.go rename to vendor/golang.org/x/sys/unix/race.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/race0.go b/vendor/golang.org/x/sys/unix/race0.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/race0.go rename to vendor/golang.org/x/sys/unix/race0.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/sockcmsg_linux.go b/vendor/golang.org/x/sys/unix/sockcmsg_linux.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/sockcmsg_linux.go rename to vendor/golang.org/x/sys/unix/sockcmsg_linux.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/sockcmsg_unix.go b/vendor/golang.org/x/sys/unix/sockcmsg_unix.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/sockcmsg_unix.go rename to vendor/golang.org/x/sys/unix/sockcmsg_unix.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/str.go b/vendor/golang.org/x/sys/unix/str.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/str.go rename to vendor/golang.org/x/sys/unix/str.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall.go b/vendor/golang.org/x/sys/unix/syscall.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall.go rename to vendor/golang.org/x/sys/unix/syscall.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_bsd.go b/vendor/golang.org/x/sys/unix/syscall_bsd.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_bsd.go rename to vendor/golang.org/x/sys/unix/syscall_bsd.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_darwin.go rename to vendor/golang.org/x/sys/unix/syscall_darwin.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_darwin_386.go b/vendor/golang.org/x/sys/unix/syscall_darwin_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_darwin_386.go rename to vendor/golang.org/x/sys/unix/syscall_darwin_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go rename to vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go b/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go rename to vendor/golang.org/x/sys/unix/syscall_darwin_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go rename to vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_dragonfly.go b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_dragonfly.go rename to vendor/golang.org/x/sys/unix/syscall_dragonfly.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go rename to vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_freebsd.go b/vendor/golang.org/x/sys/unix/syscall_freebsd.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_freebsd.go rename to vendor/golang.org/x/sys/unix/syscall_freebsd.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go rename to vendor/golang.org/x/sys/unix/syscall_freebsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go rename to vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go rename to vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux.go rename to vendor/golang.org/x/sys/unix/syscall_linux.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_386.go rename to vendor/golang.org/x/sys/unix/syscall_linux_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go rename to vendor/golang.org/x/sys/unix/syscall_linux_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go rename to vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_arm.go rename to vendor/golang.org/x/sys/unix/syscall_linux_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go rename to vendor/golang.org/x/sys/unix/syscall_linux_arm64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go rename to vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go rename to vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go rename to vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go rename to vendor/golang.org/x/sys/unix/syscall_linux_s390x.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go rename to vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_netbsd.go b/vendor/golang.org/x/sys/unix/syscall_netbsd.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_netbsd.go rename to vendor/golang.org/x/sys/unix/syscall_netbsd.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_netbsd_386.go b/vendor/golang.org/x/sys/unix/syscall_netbsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_netbsd_386.go rename to vendor/golang.org/x/sys/unix/syscall_netbsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go rename to vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go b/vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go rename to vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_no_getwd.go b/vendor/golang.org/x/sys/unix/syscall_no_getwd.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_no_getwd.go rename to vendor/golang.org/x/sys/unix/syscall_no_getwd.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_openbsd.go b/vendor/golang.org/x/sys/unix/syscall_openbsd.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_openbsd.go rename to vendor/golang.org/x/sys/unix/syscall_openbsd.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go rename to vendor/golang.org/x/sys/unix/syscall_openbsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go rename to vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_solaris.go b/vendor/golang.org/x/sys/unix/syscall_solaris.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_solaris.go rename to vendor/golang.org/x/sys/unix/syscall_solaris.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go b/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go rename to vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_unix.go b/vendor/golang.org/x/sys/unix/syscall_unix.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_unix.go rename to vendor/golang.org/x/sys/unix/syscall_unix.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_unix_gc.go b/vendor/golang.org/x/sys/unix/syscall_unix_gc.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/syscall_unix_gc.go rename to vendor/golang.org/x/sys/unix/syscall_unix_gc.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_darwin.go b/vendor/golang.org/x/sys/unix/types_darwin.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_darwin.go rename to vendor/golang.org/x/sys/unix/types_darwin.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_dragonfly.go b/vendor/golang.org/x/sys/unix/types_dragonfly.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_dragonfly.go rename to vendor/golang.org/x/sys/unix/types_dragonfly.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_freebsd.go b/vendor/golang.org/x/sys/unix/types_freebsd.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_freebsd.go rename to vendor/golang.org/x/sys/unix/types_freebsd.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_linux.go b/vendor/golang.org/x/sys/unix/types_linux.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_linux.go rename to vendor/golang.org/x/sys/unix/types_linux.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_netbsd.go b/vendor/golang.org/x/sys/unix/types_netbsd.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_netbsd.go rename to vendor/golang.org/x/sys/unix/types_netbsd.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_openbsd.go b/vendor/golang.org/x/sys/unix/types_openbsd.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_openbsd.go rename to vendor/golang.org/x/sys/unix/types_openbsd.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_solaris.go b/vendor/golang.org/x/sys/unix/types_solaris.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/types_solaris.go rename to vendor/golang.org/x/sys/unix/types_solaris.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go rename to vendor/golang.org/x/sys/unix/zerrors_darwin_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go rename to vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go rename to vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go rename to vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go rename to vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go rename to vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go rename to vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go rename to vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_386.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_mips.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go rename to vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go rename to vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go rename to vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go rename to vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go rename to vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go rename to vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go rename to vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go rename to vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go rename to vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go rename to vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go rename to vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go rename to vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go rename to vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go rename to vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go rename to vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go rename to vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go rename to vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go rename to vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go rename to vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go rename to vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go rename to vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go rename to vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysctl_openbsd.go b/vendor/golang.org/x/sys/unix/zsysctl_openbsd.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysctl_openbsd.go rename to vendor/golang.org/x/sys/unix/zsysctl_openbsd.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go b/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go rename to vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go rename to vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go rename to vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go rename to vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go rename to vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go rename to vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go rename to vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go rename to vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go rename to vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go rename to vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go rename to vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go rename to vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go rename to vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go rename to vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_solaris_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_solaris_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/zsysnum_solaris_amd64.go rename to vendor/golang.org/x/sys/unix/zsysnum_solaris_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go rename to vendor/golang.org/x/sys/unix/ztypes_darwin_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go rename to vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go rename to vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go rename to vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go rename to vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go rename to vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go rename to vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go rename to vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_386.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_mips.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go rename to vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go rename to vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go rename to vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go rename to vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go rename to vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go rename to vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go rename to vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go diff --git a/tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/LICENSE b/vendor/gopkg.in/tylerb/graceful.v1/LICENSE similarity index 100% rename from tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/LICENSE rename to vendor/gopkg.in/tylerb/graceful.v1/LICENSE diff --git a/tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/README.md b/vendor/gopkg.in/tylerb/graceful.v1/README.md similarity index 100% rename from tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/README.md rename to vendor/gopkg.in/tylerb/graceful.v1/README.md diff --git a/tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/graceful.go b/vendor/gopkg.in/tylerb/graceful.v1/graceful.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/graceful.go rename to vendor/gopkg.in/tylerb/graceful.v1/graceful.go diff --git a/tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/keepalive_listener.go b/vendor/gopkg.in/tylerb/graceful.v1/keepalive_listener.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/keepalive_listener.go rename to vendor/gopkg.in/tylerb/graceful.v1/keepalive_listener.go diff --git a/tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/limit_listen.go b/vendor/gopkg.in/tylerb/graceful.v1/limit_listen.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/limit_listen.go rename to vendor/gopkg.in/tylerb/graceful.v1/limit_listen.go diff --git a/tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/signal.go b/vendor/gopkg.in/tylerb/graceful.v1/signal.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/signal.go rename to vendor/gopkg.in/tylerb/graceful.v1/signal.go diff --git a/tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/signal_appengine.go b/vendor/gopkg.in/tylerb/graceful.v1/signal_appengine.go similarity index 100% rename from tools/infrakit.hyperkit/vendor/gopkg.in/tylerb/graceful.v1/signal_appengine.go rename to vendor/gopkg.in/tylerb/graceful.v1/signal_appengine.go