mirror of
https://github.com/asciinema/asciinema.git
synced 2025-12-16 19:58:03 +01:00
Use docopt for command arg parsing
This commit is contained in:
8
Godeps/Godeps.json
generated
8
Godeps/Godeps.json
generated
@@ -1,9 +1,6 @@
|
||||
{
|
||||
"ImportPath": "github.com/asciinema/asciinema-cli",
|
||||
"GoVersion": "go1.4",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "code.google.com/p/gcfg",
|
||||
@@ -14,6 +11,11 @@
|
||||
"Comment": "null-213",
|
||||
"Rev": "aa2644fe4aa50e3b38d75187b4799b1f0c9ddcef"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docopt/docopt-go",
|
||||
"Comment": "0.6.1-1-gc5dac53",
|
||||
"Rev": "c5dac536301992c0371c6115d998fb62944bfad3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/kr/pty",
|
||||
"Comment": "release.r56-19-g67e2db2",
|
||||
|
||||
25
Godeps/_workspace/src/github.com/docopt/docopt-go/.gitignore
generated
vendored
Normal file
25
Godeps/_workspace/src/github.com/docopt/docopt-go/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
|
||||
# coverage droppings
|
||||
profile.cov
|
||||
31
Godeps/_workspace/src/github.com/docopt/docopt-go/.travis.yml
generated
vendored
Normal file
31
Godeps/_workspace/src/github.com/docopt/docopt-go/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# Travis CI (http://travis-ci.org/) is a continuous integration
|
||||
# service for open source projects. This file configures it
|
||||
# to run unit tests for docopt-go.
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.2.2
|
||||
- 1.3
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
before_install:
|
||||
- go get code.google.com/p/go.tools/cmd/vet
|
||||
- go get -v github.com/golang/lint/golint
|
||||
- go get -v code.google.com/p/go.tools/cmd/cover
|
||||
- go get -v github.com/mattn/goveralls
|
||||
|
||||
install:
|
||||
- go get -d -v ./... && go build -v ./...
|
||||
|
||||
script:
|
||||
- go vet -x ./...
|
||||
- $HOME/gopath/bin/golint .
|
||||
- go test -v ./...
|
||||
- go test -covermode=count -coverprofile=profile.cov .
|
||||
|
||||
after_script:
|
||||
- $HOME/gopath/bin/goveralls -coverprofile=profile.cov -service=travis-ci
|
||||
20
Godeps/_workspace/src/github.com/docopt/docopt-go/LICENSE
generated
vendored
Normal file
20
Godeps/_workspace/src/github.com/docopt/docopt-go/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Keith Batten
|
||||
|
||||
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.
|
||||
88
Godeps/_workspace/src/github.com/docopt/docopt-go/README.md
generated
vendored
Normal file
88
Godeps/_workspace/src/github.com/docopt/docopt-go/README.md
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
docopt-go
|
||||
=========
|
||||
|
||||
[](https://travis-ci.org/docopt/docopt.go)
|
||||
[](https://coveralls.io/r/docopt/docopt.go)
|
||||
[](https://godoc.org/github.com/docopt/docopt.go)
|
||||
|
||||
An implementation of [docopt](http://docopt.org/) in the
|
||||
[Go](http://golang.org/) programming language.
|
||||
|
||||
**docopt** helps you create *beautiful* command-line interfaces easily:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `Naval Fate.
|
||||
|
||||
Usage:
|
||||
naval_fate ship new <name>...
|
||||
naval_fate ship <name> move <x> <y> [--speed=<kn>]
|
||||
naval_fate ship shoot <x> <y>
|
||||
naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
|
||||
naval_fate -h | --help
|
||||
naval_fate --version
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--version Show version.
|
||||
--speed=<kn> Speed in knots [default: 10].
|
||||
--moored Moored (anchored) mine.
|
||||
--drifting Drifting mine.`
|
||||
|
||||
arguments, _ := docopt.Parse(usage, nil, true, "Naval Fate 2.0", false)
|
||||
fmt.Println(arguments)
|
||||
}
|
||||
```
|
||||
|
||||
**docopt** parses command-line arguments based on a help message. Don't
|
||||
write parser code: a good help message already has all the necessary
|
||||
information in it.
|
||||
|
||||
## Installation
|
||||
|
||||
⚠ Use the alias “docopt-go”. To use docopt in your Go code:
|
||||
|
||||
```go
|
||||
import "github.com/docopt/docopt-go"
|
||||
```
|
||||
|
||||
To install docopt according to your `$GOPATH`:
|
||||
|
||||
```console
|
||||
$ go get github.com/docopt/docopt-go
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```go
|
||||
func Parse(doc string, argv []string, help bool, version string,
|
||||
optionsFirst bool, exit ...bool) (map[string]interface{}, error)
|
||||
```
|
||||
Parse `argv` based on the command-line interface described in `doc`.
|
||||
|
||||
Given a conventional command-line help message, docopt creates a parser and
|
||||
processes the arguments. See
|
||||
https://github.com/docopt/docopt#help-message-format for a description of the
|
||||
help message format. If `argv` is `nil`, `os.Args[1:]` is used.
|
||||
|
||||
docopt returns a map of option names to the values parsed from `argv`, and an
|
||||
error or `nil`.
|
||||
|
||||
More documentation for docopt is available at
|
||||
[GoDoc.org](https://godoc.org/github.com/docopt/docopt.go).
|
||||
|
||||
## Testing
|
||||
|
||||
All tests from the Python version are implemented and passing
|
||||
at [Travis CI](https://travis-ci.org/docopt/docopt.go). New
|
||||
language-agnostic tests have been added
|
||||
to [test_golang.docopt](test_golang.docopt).
|
||||
|
||||
To run tests for docopt-go, use `go test`.
|
||||
1239
Godeps/_workspace/src/github.com/docopt/docopt-go/docopt.go
generated
vendored
Normal file
1239
Godeps/_workspace/src/github.com/docopt/docopt-go/docopt.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1536
Godeps/_workspace/src/github.com/docopt/docopt-go/docopt_test.go
generated
vendored
Normal file
1536
Godeps/_workspace/src/github.com/docopt/docopt-go/docopt_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
37
Godeps/_workspace/src/github.com/docopt/docopt-go/example_test.go
generated
vendored
Normal file
37
Godeps/_workspace/src/github.com/docopt/docopt-go/example_test.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package docopt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func ExampleParse() {
|
||||
usage := `Usage:
|
||||
config_example tcp [<host>] [--force] [--timeout=<seconds>]
|
||||
config_example serial <port> [--baud=<rate>] [--timeout=<seconds>]
|
||||
config_example -h | --help | --version`
|
||||
// parse the command line `comfig_example tcp 127.0.0.1 --force`
|
||||
argv := []string{"tcp", "127.0.0.1", "--force"}
|
||||
arguments, _ := Parse(usage, argv, true, "0.1.1rc", false)
|
||||
// sort the keys of the arguments map
|
||||
var keys []string
|
||||
for k := range arguments {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
// print the argument keys and values
|
||||
for _, k := range keys {
|
||||
fmt.Printf("%9s %v\n", k, arguments[k])
|
||||
}
|
||||
// output:
|
||||
// --baud <nil>
|
||||
// --force true
|
||||
// --help false
|
||||
// --timeout <nil>
|
||||
// --version false
|
||||
// -h false
|
||||
// <host> 127.0.0.1
|
||||
// <port> <nil>
|
||||
// serial false
|
||||
// tcp true
|
||||
}
|
||||
29
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/arguments/arguments_example.go
generated
vendored
Normal file
29
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/arguments/arguments_example.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `Usage: arguments_example [-vqrh] [FILE] ...
|
||||
arguments_example (--left | --right) CORRECTION FILE
|
||||
|
||||
Process FILE and optionally apply correction to either left-hand side or
|
||||
right-hand side.
|
||||
|
||||
Arguments:
|
||||
FILE optional input file
|
||||
CORRECTION correction angle, needs FILE, --left or --right to be present
|
||||
|
||||
Options:
|
||||
-h --help
|
||||
-v verbose mode
|
||||
-q quiet mode
|
||||
-r make report
|
||||
--left use left-hand side
|
||||
--right use right-hand side`
|
||||
|
||||
arguments, _ := docopt.Parse(usage, nil, true, "", false)
|
||||
fmt.Println(arguments)
|
||||
}
|
||||
26
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/calculator/calculator_example.go
generated
vendored
Normal file
26
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/calculator/calculator_example.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `Not a serious example.
|
||||
|
||||
Usage:
|
||||
calculator_example <value> ( ( + | - | * | / ) <value> )...
|
||||
calculator_example <function> <value> [( , <value> )]...
|
||||
calculator_example (-h | --help)
|
||||
|
||||
Examples:
|
||||
calculator_example 1 + 2 + 3 + 4 + 5
|
||||
calculator_example 1 + 2 '*' 3 / 4 - 5 # note quotes around '*'
|
||||
calculator_example sum 10 , 20 , 30 , 40
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
`
|
||||
arguments, _ := docopt.Parse(usage, nil, true, "", false)
|
||||
fmt.Println(arguments)
|
||||
}
|
||||
76
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/config_file/config_file_example.go
generated
vendored
Normal file
76
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/config_file/config_file_example.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func loadJSONConfig() map[string]interface{} {
|
||||
var result map[string]interface{}
|
||||
jsonData := []byte(`{"--force": true, "--timeout": "10", "--baud": "9600"}`)
|
||||
json.Unmarshal(jsonData, &result)
|
||||
return result
|
||||
}
|
||||
|
||||
func loadIniConfig() map[string]interface{} {
|
||||
iniData := `
|
||||
[default-arguments]
|
||||
--force
|
||||
--baud=19200
|
||||
<host>=localhost`
|
||||
// trivial ini parser
|
||||
// default value for an item is bool: true (for --force)
|
||||
// otherwise the value is a string
|
||||
iniParsed := make(map[string]map[string]interface{})
|
||||
var section string
|
||||
for _, line := range strings.Split(iniData, "\n") {
|
||||
if strings.HasPrefix(line, "[") {
|
||||
section = line
|
||||
iniParsed[section] = make(map[string]interface{})
|
||||
} else if section != "" {
|
||||
kv := strings.SplitN(line, "=", 2)
|
||||
if len(kv) == 1 {
|
||||
iniParsed[section][kv[0]] = true
|
||||
} else if len(kv) == 2 {
|
||||
iniParsed[section][kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return iniParsed["[default-arguments]"]
|
||||
}
|
||||
|
||||
// merge combines two maps.
|
||||
// truthiness takes priority over falsiness
|
||||
// mapA takes priority over mapB
|
||||
func merge(mapA, mapB map[string]interface{}) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
for k, v := range mapA {
|
||||
result[k] = v
|
||||
}
|
||||
for k, v := range mapB {
|
||||
if _, ok := result[k]; !ok || result[k] == nil || result[k] == false {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func main() {
|
||||
usage := `Usage:
|
||||
config_file_example tcp [<host>] [--force] [--timeout=<seconds>]
|
||||
config_file_example serial <port> [--baud=<rate>] [--timeout=<seconds>]
|
||||
config_file_example -h | --help | --version`
|
||||
|
||||
jsonConfig := loadJSONConfig()
|
||||
iniConfig := loadIniConfig()
|
||||
arguments, _ := docopt.Parse(usage, nil, true, "0.1.1rc", false)
|
||||
|
||||
// Arguments take priority over INI, INI takes priority over JSON
|
||||
result := merge(arguments, merge(iniConfig, jsonConfig))
|
||||
|
||||
fmt.Println("JSON config: ", jsonConfig)
|
||||
fmt.Println("INI config: ", iniConfig)
|
||||
fmt.Println("Result: ", result)
|
||||
}
|
||||
22
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/counted/counted_example.go
generated
vendored
Normal file
22
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/counted/counted_example.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `Usage: counted_example --help
|
||||
counted_example -v...
|
||||
counted_example go [go]
|
||||
counted_example (--path=<path>)...
|
||||
counted_example <file> <file>
|
||||
|
||||
Try: counted_example -vvvvvvvvvv
|
||||
counted_example go go
|
||||
counted_example --path ./here --path ./there
|
||||
counted_example this.txt that.txt`
|
||||
|
||||
arguments, _ := docopt.Parse(usage, nil, true, "", false)
|
||||
fmt.Println(arguments)
|
||||
}
|
||||
38
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/branch/git_branch.go
generated
vendored
Normal file
38
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/branch/git_branch.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `usage: git branch [options] [-r | -a] [--merged=<commit> | --no-merged=<commit>]
|
||||
git branch [options] [-l] [-f] <branchname> [<start-point>]
|
||||
git branch [options] [-r] (-d | -D) <branchname>
|
||||
git branch [options] (-m | -M) [<oldbranch>] <newbranch>
|
||||
|
||||
Generic options:
|
||||
-h, --help
|
||||
-v, --verbose show hash and subject, give twice for upstream branch
|
||||
-t, --track set up tracking mode (see git-pull(1))
|
||||
--set-upstream change upstream info
|
||||
--color=<when> use colored output
|
||||
-r act on remote-tracking branches
|
||||
--contains=<commit> print only branches that contain the commit
|
||||
--abbrev=<n> use <n> digits to display SHA-1s
|
||||
|
||||
Specific git-branch actions:
|
||||
-a list both remote-tracking and local branches
|
||||
-d delete fully merged branch
|
||||
-D delete branch (even if not merged)
|
||||
-m move/rename a branch and its reflog
|
||||
-M move/rename a branch, even if target exists
|
||||
-l create the branch's reflog
|
||||
-f, --force force creation (when already exists)
|
||||
--no-merged=<commit> print only not merged branches
|
||||
--merged=<commit> print only merged branches
|
||||
`
|
||||
|
||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
||||
fmt.Println(args)
|
||||
}
|
||||
30
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/checkout/git_checkout.go
generated
vendored
Normal file
30
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/checkout/git_checkout.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `usage: git checkout [options] <branch>
|
||||
git checkout [options] <branch> -- <file>...
|
||||
|
||||
options:
|
||||
-q, --quiet suppress progress reporting
|
||||
-b <branch> create and checkout a new branch
|
||||
-B <branch> create/reset and checkout a branch
|
||||
-l create reflog for new branch
|
||||
-t, --track set upstream info for new branch
|
||||
--orphan <new branch>
|
||||
new unparented branch
|
||||
-2, --ours checkout our version for unmerged files
|
||||
-3, --theirs checkout their version for unmerged files
|
||||
-f, --force force checkout (throw away local modifications)
|
||||
-m, --merge perform a 3-way merge with the new branch
|
||||
--conflict <style> conflict style (merge or diff3)
|
||||
-p, --patch select hunks interactively
|
||||
`
|
||||
|
||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
||||
fmt.Println(args)
|
||||
}
|
||||
37
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/clone/git_clone.go
generated
vendored
Normal file
37
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/clone/git_clone.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `usage: git clone [options] [--] <repo> [<dir>]
|
||||
|
||||
options:
|
||||
-v, --verbose be more verbose
|
||||
-q, --quiet be more quiet
|
||||
--progress force progress reporting
|
||||
-n, --no-checkout don't create a checkout
|
||||
--bare create a bare repository
|
||||
--mirror create a mirror repository (implies bare)
|
||||
-l, --local to clone from a local repository
|
||||
--no-hardlinks don't use local hardlinks, always copy
|
||||
-s, --shared setup as shared repository
|
||||
--recursive initialize submodules in the clone
|
||||
--recurse-submodules initialize submodules in the clone
|
||||
--template <template-directory>
|
||||
directory from which templates will be used
|
||||
--reference <repo> reference repository
|
||||
-o, --origin <branch>
|
||||
use <branch> instead of 'origin' to track upstream
|
||||
-b, --branch <branch>
|
||||
checkout <branch> instead of the remote's HEAD
|
||||
-u, --upload-pack <path>
|
||||
path to git-upload-pack on the remote
|
||||
--depth <depth> create a shallow clone of that depth
|
||||
`
|
||||
|
||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
||||
fmt.Println(args)
|
||||
}
|
||||
108
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/git.go
generated
vendored
Normal file
108
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/git.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `usage: git [--version] [--exec-path=<path>] [--html-path]
|
||||
[-p|--paginate|--no-pager] [--no-replace-objects]
|
||||
[--bare] [--git-dir=<path>] [--work-tree=<path>]
|
||||
[-c <name>=<value>] [--help]
|
||||
<command> [<args>...]
|
||||
|
||||
options:
|
||||
-c <name=value>
|
||||
-h, --help
|
||||
-p, --paginate
|
||||
|
||||
The most commonly used git commands are:
|
||||
add Add file contents to the index
|
||||
branch List, create, or delete branches
|
||||
checkout Checkout a branch or paths to the working tree
|
||||
clone Clone a repository into a new directory
|
||||
commit Record changes to the repository
|
||||
push Update remote refs along with associated objects
|
||||
remote Manage set of tracked repositories
|
||||
|
||||
See 'git help <command>' for more information on a specific command.
|
||||
`
|
||||
args, _ := docopt.Parse(usage, nil, true, "git version 1.7.4.4", true)
|
||||
|
||||
fmt.Println("global arguments:")
|
||||
fmt.Println(args)
|
||||
|
||||
fmt.Println("command arguments:")
|
||||
cmd := args["<command>"].(string)
|
||||
cmdArgs := args["<args>"].([]string)
|
||||
|
||||
err := runCommand(cmd, cmdArgs)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func goRun(scriptName string, args []string) (err error) {
|
||||
cmdArgs := make([]string, 2)
|
||||
cmdArgs[0] = "run"
|
||||
cmdArgs[1] = scriptName
|
||||
cmdArgs = append(cmdArgs, args...)
|
||||
osCmd := exec.Command("go", cmdArgs...)
|
||||
var out []byte
|
||||
out, err = osCmd.Output()
|
||||
fmt.Println(string(out))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func runCommand(cmd string, args []string) (err error) {
|
||||
argv := make([]string, 1)
|
||||
argv[0] = cmd
|
||||
argv = append(argv, args...)
|
||||
switch cmd {
|
||||
case "add":
|
||||
// subcommand is a function call
|
||||
return cmdAdd(argv)
|
||||
case "branch":
|
||||
// subcommand is a script
|
||||
return goRun("branch/git_branch.go", argv)
|
||||
case "checkout", "clone", "commit", "push", "remote":
|
||||
// subcommand is a script
|
||||
scriptName := fmt.Sprintf("%s/git_%s.go", cmd, cmd)
|
||||
return goRun(scriptName, argv)
|
||||
case "help", "":
|
||||
return goRun("git.go", []string{"git_add.go", "--help"})
|
||||
}
|
||||
|
||||
return fmt.Errorf("%s is not a git command. See 'git help'", cmd)
|
||||
}
|
||||
|
||||
func cmdAdd(argv []string) (err error) {
|
||||
usage := `usage: git add [options] [--] [<filepattern>...]
|
||||
|
||||
options:
|
||||
-h, --help
|
||||
-n, --dry-run dry run
|
||||
-v, --verbose be verbose
|
||||
-i, --interactive interactive picking
|
||||
-p, --patch select hunks interactively
|
||||
-e, --edit edit current diff and apply
|
||||
-f, --force allow adding otherwise ignored files
|
||||
-u, --update update tracked files
|
||||
-N, --intent-to-add record only the fact that the path will be added later
|
||||
-A, --all add all, noticing removal of tracked files
|
||||
--refresh don't add, only refresh the index
|
||||
--ignore-errors just skip files which cannot be added because of errors
|
||||
--ignore-missing check if - even missing - files are ignored in dry run
|
||||
`
|
||||
|
||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
||||
fmt.Println(args)
|
||||
return
|
||||
}
|
||||
34
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/push/git_push.go
generated
vendored
Normal file
34
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/push/git_push.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `usage: git push [options] [<repository> [<refspec>...]]
|
||||
|
||||
options:
|
||||
-h, --help
|
||||
-v, --verbose be more verbose
|
||||
-q, --quiet be more quiet
|
||||
--repo <repository> repository
|
||||
--all push all refs
|
||||
--mirror mirror all refs
|
||||
--delete delete refs
|
||||
--tags push tags (can't be used with --all or --mirror)
|
||||
-n, --dry-run dry run
|
||||
--porcelain machine-readable output
|
||||
-f, --force force updates
|
||||
--thin use thin pack
|
||||
--receive-pack <receive-pack>
|
||||
receive pack program
|
||||
--exec <receive-pack>
|
||||
receive pack program
|
||||
-u, --set-upstream set upstream for git pull/status
|
||||
--progress force progress reporting
|
||||
`
|
||||
|
||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
||||
fmt.Println(args)
|
||||
}
|
||||
28
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/remote/git_remote.go
generated
vendored
Normal file
28
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/git/remote/git_remote.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `usage: git remote [-v | --verbose]
|
||||
git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
|
||||
git remote rename <old> <new>
|
||||
git remote rm <name>
|
||||
git remote set-head <name> (-a | -d | <branch>)
|
||||
git remote [-v | --verbose] show [-n] <name>
|
||||
git remote prune [-n | --dry-run] <name>
|
||||
git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]
|
||||
git remote set-branches <name> [--add] <branch>...
|
||||
git remote set-url <name> <newurl> [<oldurl>]
|
||||
git remote set-url --add <name> <newurl>
|
||||
git remote set-url --delete <name> <url>
|
||||
|
||||
options:
|
||||
-v, --verbose be verbose; must be placed before a subcommand
|
||||
`
|
||||
|
||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
||||
fmt.Println(args)
|
||||
}
|
||||
28
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/naval_fate/naval_fate.go
generated
vendored
Normal file
28
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/naval_fate/naval_fate.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `Naval Fate.
|
||||
|
||||
Usage:
|
||||
naval_fate ship new <name>...
|
||||
naval_fate ship <name> move <x> <y> [--speed=<kn>]
|
||||
naval_fate ship shoot <x> <y>
|
||||
naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
|
||||
naval_fate -h | --help
|
||||
naval_fate --version
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--version Show version.
|
||||
--speed=<kn> Speed in knots [default: 10].
|
||||
--moored Moored (anchored) mine.
|
||||
--drifting Drifting mine.`
|
||||
|
||||
arguments, _ := docopt.Parse(usage, nil, true, "Naval Fate 2.0", false)
|
||||
fmt.Println(arguments)
|
||||
}
|
||||
19
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/odd_even/odd_even_example.go
generated
vendored
Normal file
19
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/odd_even/odd_even_example.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `Usage: odd_even_example [-h | --help] (ODD EVEN)...
|
||||
|
||||
Example, try:
|
||||
odd_even_example 1 2 3 4
|
||||
|
||||
Options:
|
||||
-h, --help`
|
||||
|
||||
arguments, _ := docopt.Parse(usage, nil, true, "", false)
|
||||
fmt.Println(arguments)
|
||||
}
|
||||
43
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/options/options_example.go
generated
vendored
Normal file
43
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/options/options_example.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `Example of program with many options using docopt.
|
||||
|
||||
Usage:
|
||||
options_example [-hvqrf NAME] [--exclude=PATTERNS]
|
||||
[--select=ERRORS | --ignore=ERRORS] [--show-source]
|
||||
[--statistics] [--count] [--benchmark] PATH...
|
||||
options_example (--doctest | --testsuite=DIR)
|
||||
options_example --version
|
||||
|
||||
Arguments:
|
||||
PATH destination path
|
||||
|
||||
Options:
|
||||
-h --help show this help message and exit
|
||||
--version show version and exit
|
||||
-v --verbose print status messages
|
||||
-q --quiet report only file names
|
||||
-r --repeat show all occurrences of the same error
|
||||
--exclude=PATTERNS exclude files or directories which match these comma
|
||||
separated patterns [default: .svn,CVS,.bzr,.hg,.git]
|
||||
-f NAME --file=NAME when parsing directories, only check filenames matching
|
||||
these comma separated patterns [default: *.go]
|
||||
--select=ERRORS select errors and warnings (e.g. E,W6)
|
||||
--ignore=ERRORS skip errors and warnings (e.g. E4,W)
|
||||
--show-source show source code for each error
|
||||
--statistics count errors and warnings
|
||||
--count print total number of errors and warnings to standard
|
||||
error and set exit code to 1 if total is not null
|
||||
--benchmark measure processing speed
|
||||
--testsuite=DIR run regression tests from dir
|
||||
--doctest run doctest on myself`
|
||||
|
||||
arguments, _ := docopt.Parse(usage, nil, true, "1.0.0rc2", false)
|
||||
fmt.Println(arguments)
|
||||
}
|
||||
24
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/options_shortcut/options_shortcut_example.go
generated
vendored
Normal file
24
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/options_shortcut/options_shortcut_example.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `Example of program which uses [options] shortcut in pattern.
|
||||
|
||||
Usage:
|
||||
options_shortcut_example [options] <port>
|
||||
|
||||
Options:
|
||||
-h --help show this help message and exit
|
||||
--version show version and exit
|
||||
-n, --number N use N as a number
|
||||
-t, --timeout TIMEOUT set timeout TIMEOUT seconds
|
||||
--apply apply changes to database
|
||||
-q operate in quiet mode`
|
||||
|
||||
arguments, _ := docopt.Parse(usage, nil, true, "1.0.0rc2", false)
|
||||
fmt.Println(arguments)
|
||||
}
|
||||
16
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/quick/quick_example.go
generated
vendored
Normal file
16
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/quick/quick_example.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `Usage:
|
||||
quick_example tcp <host> <port> [--timeout=<seconds>]
|
||||
quick_example serial <port> [--baud=9600] [--timeout=<seconds>]
|
||||
quick_example -h | --help | --version`
|
||||
|
||||
arguments, _ := docopt.Parse(usage, nil, true, "0.1.1rc", false)
|
||||
fmt.Println(arguments)
|
||||
}
|
||||
31
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/type_assert/type_assert_example.go
generated
vendored
Normal file
31
Godeps/_workspace/src/github.com/docopt/docopt-go/examples/type_assert/type_assert_example.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
usage := `usage: foo [-x] [-y]`
|
||||
|
||||
arguments, err := docopt.Parse(usage, nil, true, "", false)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
fmt.Println(arguments)
|
||||
|
||||
var x = arguments["-x"].(bool) // type assertion required
|
||||
if x == true {
|
||||
fmt.Println("x is true")
|
||||
}
|
||||
|
||||
y := arguments["-y"] // no type assertion needed
|
||||
if y == true {
|
||||
fmt.Println("y is true")
|
||||
}
|
||||
y2 := arguments["-y"]
|
||||
if y2 == 10 { // this will never be true, a type assertion would have produced a build error
|
||||
fmt.Println("y is 10")
|
||||
}
|
||||
}
|
||||
9
Godeps/_workspace/src/github.com/docopt/docopt-go/test_golang.docopt
generated
vendored
Normal file
9
Godeps/_workspace/src/github.com/docopt/docopt-go/test_golang.docopt
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
r"""usage: prog [NAME_-2]..."""
|
||||
$ prog 10 20
|
||||
{"NAME_-2": ["10", "20"]}
|
||||
|
||||
$ prog 10
|
||||
{"NAME_-2": ["10"]}
|
||||
|
||||
$ prog
|
||||
{"NAME_-2": []}
|
||||
957
Godeps/_workspace/src/github.com/docopt/docopt-go/testcases.docopt
generated
vendored
Normal file
957
Godeps/_workspace/src/github.com/docopt/docopt-go/testcases.docopt
generated
vendored
Normal file
@@ -0,0 +1,957 @@
|
||||
r"""Usage: prog
|
||||
|
||||
"""
|
||||
$ prog
|
||||
{}
|
||||
|
||||
$ prog --xxx
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""Usage: prog [options]
|
||||
|
||||
Options: -a All.
|
||||
|
||||
"""
|
||||
$ prog
|
||||
{"-a": false}
|
||||
|
||||
$ prog -a
|
||||
{"-a": true}
|
||||
|
||||
$ prog -x
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""Usage: prog [options]
|
||||
|
||||
Options: --all All.
|
||||
|
||||
"""
|
||||
$ prog
|
||||
{"--all": false}
|
||||
|
||||
$ prog --all
|
||||
{"--all": true}
|
||||
|
||||
$ prog --xxx
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""Usage: prog [options]
|
||||
|
||||
Options: -v, --verbose Verbose.
|
||||
|
||||
"""
|
||||
$ prog --verbose
|
||||
{"--verbose": true}
|
||||
|
||||
$ prog --ver
|
||||
{"--verbose": true}
|
||||
|
||||
$ prog -v
|
||||
{"--verbose": true}
|
||||
|
||||
|
||||
r"""Usage: prog [options]
|
||||
|
||||
Options: -p PATH
|
||||
|
||||
"""
|
||||
$ prog -p home/
|
||||
{"-p": "home/"}
|
||||
|
||||
$ prog -phome/
|
||||
{"-p": "home/"}
|
||||
|
||||
$ prog -p
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""Usage: prog [options]
|
||||
|
||||
Options: --path <path>
|
||||
|
||||
"""
|
||||
$ prog --path home/
|
||||
{"--path": "home/"}
|
||||
|
||||
$ prog --path=home/
|
||||
{"--path": "home/"}
|
||||
|
||||
$ prog --pa home/
|
||||
{"--path": "home/"}
|
||||
|
||||
$ prog --pa=home/
|
||||
{"--path": "home/"}
|
||||
|
||||
$ prog --path
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""Usage: prog [options]
|
||||
|
||||
Options: -p PATH, --path=<path> Path to files.
|
||||
|
||||
"""
|
||||
$ prog -proot
|
||||
{"--path": "root"}
|
||||
|
||||
|
||||
r"""Usage: prog [options]
|
||||
|
||||
Options: -p --path PATH Path to files.
|
||||
|
||||
"""
|
||||
$ prog -p root
|
||||
{"--path": "root"}
|
||||
|
||||
$ prog --path root
|
||||
{"--path": "root"}
|
||||
|
||||
|
||||
r"""Usage: prog [options]
|
||||
|
||||
Options:
|
||||
-p PATH Path to files [default: ./]
|
||||
|
||||
"""
|
||||
$ prog
|
||||
{"-p": "./"}
|
||||
|
||||
$ prog -phome
|
||||
{"-p": "home"}
|
||||
|
||||
|
||||
r"""UsAgE: prog [options]
|
||||
|
||||
OpTiOnS: --path=<files> Path to files
|
||||
[dEfAuLt: /root]
|
||||
|
||||
"""
|
||||
$ prog
|
||||
{"--path": "/root"}
|
||||
|
||||
$ prog --path=home
|
||||
{"--path": "home"}
|
||||
|
||||
|
||||
r"""usage: prog [options]
|
||||
|
||||
options:
|
||||
-a Add
|
||||
-r Remote
|
||||
-m <msg> Message
|
||||
|
||||
"""
|
||||
$ prog -a -r -m Hello
|
||||
{"-a": true,
|
||||
"-r": true,
|
||||
"-m": "Hello"}
|
||||
|
||||
$ prog -armyourass
|
||||
{"-a": true,
|
||||
"-r": true,
|
||||
"-m": "yourass"}
|
||||
|
||||
$ prog -a -r
|
||||
{"-a": true,
|
||||
"-r": true,
|
||||
"-m": null}
|
||||
|
||||
|
||||
r"""Usage: prog [options]
|
||||
|
||||
Options: --version
|
||||
--verbose
|
||||
|
||||
"""
|
||||
$ prog --version
|
||||
{"--version": true,
|
||||
"--verbose": false}
|
||||
|
||||
$ prog --verbose
|
||||
{"--version": false,
|
||||
"--verbose": true}
|
||||
|
||||
$ prog --ver
|
||||
"user-error"
|
||||
|
||||
$ prog --verb
|
||||
{"--version": false,
|
||||
"--verbose": true}
|
||||
|
||||
|
||||
r"""usage: prog [-a -r -m <msg>]
|
||||
|
||||
options:
|
||||
-a Add
|
||||
-r Remote
|
||||
-m <msg> Message
|
||||
|
||||
"""
|
||||
$ prog -armyourass
|
||||
{"-a": true,
|
||||
"-r": true,
|
||||
"-m": "yourass"}
|
||||
|
||||
|
||||
r"""usage: prog [-armmsg]
|
||||
|
||||
options: -a Add
|
||||
-r Remote
|
||||
-m <msg> Message
|
||||
|
||||
"""
|
||||
$ prog -a -r -m Hello
|
||||
{"-a": true,
|
||||
"-r": true,
|
||||
"-m": "Hello"}
|
||||
|
||||
|
||||
r"""usage: prog -a -b
|
||||
|
||||
options:
|
||||
-a
|
||||
-b
|
||||
|
||||
"""
|
||||
$ prog -a -b
|
||||
{"-a": true, "-b": true}
|
||||
|
||||
$ prog -b -a
|
||||
{"-a": true, "-b": true}
|
||||
|
||||
$ prog -a
|
||||
"user-error"
|
||||
|
||||
$ prog
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""usage: prog (-a -b)
|
||||
|
||||
options: -a
|
||||
-b
|
||||
|
||||
"""
|
||||
$ prog -a -b
|
||||
{"-a": true, "-b": true}
|
||||
|
||||
$ prog -b -a
|
||||
{"-a": true, "-b": true}
|
||||
|
||||
$ prog -a
|
||||
"user-error"
|
||||
|
||||
$ prog
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""usage: prog [-a] -b
|
||||
|
||||
options: -a
|
||||
-b
|
||||
|
||||
"""
|
||||
$ prog -a -b
|
||||
{"-a": true, "-b": true}
|
||||
|
||||
$ prog -b -a
|
||||
{"-a": true, "-b": true}
|
||||
|
||||
$ prog -a
|
||||
"user-error"
|
||||
|
||||
$ prog -b
|
||||
{"-a": false, "-b": true}
|
||||
|
||||
$ prog
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""usage: prog [(-a -b)]
|
||||
|
||||
options: -a
|
||||
-b
|
||||
|
||||
"""
|
||||
$ prog -a -b
|
||||
{"-a": true, "-b": true}
|
||||
|
||||
$ prog -b -a
|
||||
{"-a": true, "-b": true}
|
||||
|
||||
$ prog -a
|
||||
"user-error"
|
||||
|
||||
$ prog -b
|
||||
"user-error"
|
||||
|
||||
$ prog
|
||||
{"-a": false, "-b": false}
|
||||
|
||||
|
||||
r"""usage: prog (-a|-b)
|
||||
|
||||
options: -a
|
||||
-b
|
||||
|
||||
"""
|
||||
$ prog -a -b
|
||||
"user-error"
|
||||
|
||||
$ prog
|
||||
"user-error"
|
||||
|
||||
$ prog -a
|
||||
{"-a": true, "-b": false}
|
||||
|
||||
$ prog -b
|
||||
{"-a": false, "-b": true}
|
||||
|
||||
|
||||
r"""usage: prog [ -a | -b ]
|
||||
|
||||
options: -a
|
||||
-b
|
||||
|
||||
"""
|
||||
$ prog -a -b
|
||||
"user-error"
|
||||
|
||||
$ prog
|
||||
{"-a": false, "-b": false}
|
||||
|
||||
$ prog -a
|
||||
{"-a": true, "-b": false}
|
||||
|
||||
$ prog -b
|
||||
{"-a": false, "-b": true}
|
||||
|
||||
|
||||
r"""usage: prog <arg>"""
|
||||
$ prog 10
|
||||
{"<arg>": "10"}
|
||||
|
||||
$ prog 10 20
|
||||
"user-error"
|
||||
|
||||
$ prog
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""usage: prog [<arg>]"""
|
||||
$ prog 10
|
||||
{"<arg>": "10"}
|
||||
|
||||
$ prog 10 20
|
||||
"user-error"
|
||||
|
||||
$ prog
|
||||
{"<arg>": null}
|
||||
|
||||
|
||||
r"""usage: prog <kind> <name> <type>"""
|
||||
$ prog 10 20 40
|
||||
{"<kind>": "10", "<name>": "20", "<type>": "40"}
|
||||
|
||||
$ prog 10 20
|
||||
"user-error"
|
||||
|
||||
$ prog
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""usage: prog <kind> [<name> <type>]"""
|
||||
$ prog 10 20 40
|
||||
{"<kind>": "10", "<name>": "20", "<type>": "40"}
|
||||
|
||||
$ prog 10 20
|
||||
{"<kind>": "10", "<name>": "20", "<type>": null}
|
||||
|
||||
$ prog
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""usage: prog [<kind> | <name> <type>]"""
|
||||
$ prog 10 20 40
|
||||
"user-error"
|
||||
|
||||
$ prog 20 40
|
||||
{"<kind>": null, "<name>": "20", "<type>": "40"}
|
||||
|
||||
$ prog
|
||||
{"<kind>": null, "<name>": null, "<type>": null}
|
||||
|
||||
|
||||
r"""usage: prog (<kind> --all | <name>)
|
||||
|
||||
options:
|
||||
--all
|
||||
|
||||
"""
|
||||
$ prog 10 --all
|
||||
{"<kind>": "10", "--all": true, "<name>": null}
|
||||
|
||||
$ prog 10
|
||||
{"<kind>": null, "--all": false, "<name>": "10"}
|
||||
|
||||
$ prog
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""usage: prog [<name> <name>]"""
|
||||
$ prog 10 20
|
||||
{"<name>": ["10", "20"]}
|
||||
|
||||
$ prog 10
|
||||
{"<name>": ["10"]}
|
||||
|
||||
$ prog
|
||||
{"<name>": []}
|
||||
|
||||
|
||||
r"""usage: prog [(<name> <name>)]"""
|
||||
$ prog 10 20
|
||||
{"<name>": ["10", "20"]}
|
||||
|
||||
$ prog 10
|
||||
"user-error"
|
||||
|
||||
$ prog
|
||||
{"<name>": []}
|
||||
|
||||
|
||||
r"""usage: prog NAME..."""
|
||||
$ prog 10 20
|
||||
{"NAME": ["10", "20"]}
|
||||
|
||||
$ prog 10
|
||||
{"NAME": ["10"]}
|
||||
|
||||
$ prog
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""usage: prog [NAME]..."""
|
||||
$ prog 10 20
|
||||
{"NAME": ["10", "20"]}
|
||||
|
||||
$ prog 10
|
||||
{"NAME": ["10"]}
|
||||
|
||||
$ prog
|
||||
{"NAME": []}
|
||||
|
||||
|
||||
r"""usage: prog [NAME...]"""
|
||||
$ prog 10 20
|
||||
{"NAME": ["10", "20"]}
|
||||
|
||||
$ prog 10
|
||||
{"NAME": ["10"]}
|
||||
|
||||
$ prog
|
||||
{"NAME": []}
|
||||
|
||||
|
||||
r"""usage: prog [NAME [NAME ...]]"""
|
||||
$ prog 10 20
|
||||
{"NAME": ["10", "20"]}
|
||||
|
||||
$ prog 10
|
||||
{"NAME": ["10"]}
|
||||
|
||||
$ prog
|
||||
{"NAME": []}
|
||||
|
||||
|
||||
r"""usage: prog (NAME | --foo NAME)
|
||||
|
||||
options: --foo
|
||||
|
||||
"""
|
||||
$ prog 10
|
||||
{"NAME": "10", "--foo": false}
|
||||
|
||||
$ prog --foo 10
|
||||
{"NAME": "10", "--foo": true}
|
||||
|
||||
$ prog --foo=10
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""usage: prog (NAME | --foo) [--bar | NAME]
|
||||
|
||||
options: --foo
|
||||
options: --bar
|
||||
|
||||
"""
|
||||
$ prog 10
|
||||
{"NAME": ["10"], "--foo": false, "--bar": false}
|
||||
|
||||
$ prog 10 20
|
||||
{"NAME": ["10", "20"], "--foo": false, "--bar": false}
|
||||
|
||||
$ prog --foo --bar
|
||||
{"NAME": [], "--foo": true, "--bar": true}
|
||||
|
||||
|
||||
r"""Naval Fate.
|
||||
|
||||
Usage:
|
||||
prog ship new <name>...
|
||||
prog ship [<name>] move <x> <y> [--speed=<kn>]
|
||||
prog ship shoot <x> <y>
|
||||
prog mine (set|remove) <x> <y> [--moored|--drifting]
|
||||
prog -h | --help
|
||||
prog --version
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--version Show version.
|
||||
--speed=<kn> Speed in knots [default: 10].
|
||||
--moored Mored (anchored) mine.
|
||||
--drifting Drifting mine.
|
||||
|
||||
"""
|
||||
$ prog ship Guardian move 150 300 --speed=20
|
||||
{"--drifting": false,
|
||||
"--help": false,
|
||||
"--moored": false,
|
||||
"--speed": "20",
|
||||
"--version": false,
|
||||
"<name>": ["Guardian"],
|
||||
"<x>": "150",
|
||||
"<y>": "300",
|
||||
"mine": false,
|
||||
"move": true,
|
||||
"new": false,
|
||||
"remove": false,
|
||||
"set": false,
|
||||
"ship": true,
|
||||
"shoot": false}
|
||||
|
||||
|
||||
r"""usage: prog --hello"""
|
||||
$ prog --hello
|
||||
{"--hello": true}
|
||||
|
||||
|
||||
r"""usage: prog [--hello=<world>]"""
|
||||
$ prog
|
||||
{"--hello": null}
|
||||
|
||||
$ prog --hello wrld
|
||||
{"--hello": "wrld"}
|
||||
|
||||
|
||||
r"""usage: prog [-o]"""
|
||||
$ prog
|
||||
{"-o": false}
|
||||
|
||||
$ prog -o
|
||||
{"-o": true}
|
||||
|
||||
|
||||
r"""usage: prog [-opr]"""
|
||||
$ prog -op
|
||||
{"-o": true, "-p": true, "-r": false}
|
||||
|
||||
|
||||
r"""usage: prog --aabb | --aa"""
|
||||
$ prog --aa
|
||||
{"--aabb": false, "--aa": true}
|
||||
|
||||
$ prog --a
|
||||
"user-error" # not a unique prefix
|
||||
|
||||
#
|
||||
# Counting number of flags
|
||||
#
|
||||
|
||||
r"""Usage: prog -v"""
|
||||
$ prog -v
|
||||
{"-v": true}
|
||||
|
||||
|
||||
r"""Usage: prog [-v -v]"""
|
||||
$ prog
|
||||
{"-v": 0}
|
||||
|
||||
$ prog -v
|
||||
{"-v": 1}
|
||||
|
||||
$ prog -vv
|
||||
{"-v": 2}
|
||||
|
||||
|
||||
r"""Usage: prog -v ..."""
|
||||
$ prog
|
||||
"user-error"
|
||||
|
||||
$ prog -v
|
||||
{"-v": 1}
|
||||
|
||||
$ prog -vv
|
||||
{"-v": 2}
|
||||
|
||||
$ prog -vvvvvv
|
||||
{"-v": 6}
|
||||
|
||||
|
||||
r"""Usage: prog [-v | -vv | -vvv]
|
||||
|
||||
This one is probably most readable user-friednly variant.
|
||||
|
||||
"""
|
||||
$ prog
|
||||
{"-v": 0}
|
||||
|
||||
$ prog -v
|
||||
{"-v": 1}
|
||||
|
||||
$ prog -vv
|
||||
{"-v": 2}
|
||||
|
||||
$ prog -vvvv
|
||||
"user-error"
|
||||
|
||||
|
||||
r"""usage: prog [--ver --ver]"""
|
||||
$ prog --ver --ver
|
||||
{"--ver": 2}
|
||||
|
||||
|
||||
#
|
||||
# Counting commands
|
||||
#
|
||||
|
||||
r"""usage: prog [go]"""
|
||||
$ prog go
|
||||
{"go": true}
|
||||
|
||||
|
||||
r"""usage: prog [go go]"""
|
||||
$ prog
|
||||
{"go": 0}
|
||||
|
||||
$ prog go
|
||||
{"go": 1}
|
||||
|
||||
$ prog go go
|
||||
{"go": 2}
|
||||
|
||||
$ prog go go go
|
||||
"user-error"
|
||||
|
||||
r"""usage: prog go..."""
|
||||
$ prog go go go go go
|
||||
{"go": 5}
|
||||
|
||||
#
|
||||
# [options] does not include options from usage-pattern
|
||||
#
|
||||
r"""usage: prog [options] [-a]
|
||||
|
||||
options: -a
|
||||
-b
|
||||
"""
|
||||
$ prog -a
|
||||
{"-a": true, "-b": false}
|
||||
|
||||
$ prog -aa
|
||||
"user-error"
|
||||
|
||||
#
|
||||
# Test [options] shourtcut
|
||||
#
|
||||
|
||||
r"""Usage: prog [options] A
|
||||
Options:
|
||||
-q Be quiet
|
||||
-v Be verbose.
|
||||
|
||||
"""
|
||||
$ prog arg
|
||||
{"A": "arg", "-v": false, "-q": false}
|
||||
|
||||
$ prog -v arg
|
||||
{"A": "arg", "-v": true, "-q": false}
|
||||
|
||||
$ prog -q arg
|
||||
{"A": "arg", "-v": false, "-q": true}
|
||||
|
||||
#
|
||||
# Test single dash
|
||||
#
|
||||
|
||||
r"""usage: prog [-]"""
|
||||
|
||||
$ prog -
|
||||
{"-": true}
|
||||
|
||||
$ prog
|
||||
{"-": false}
|
||||
|
||||
#
|
||||
# If argument is repeated, its value should always be a list
|
||||
#
|
||||
|
||||
r"""usage: prog [NAME [NAME ...]]"""
|
||||
|
||||
$ prog a b
|
||||
{"NAME": ["a", "b"]}
|
||||
|
||||
$ prog
|
||||
{"NAME": []}
|
||||
|
||||
#
|
||||
# Option's argument defaults to null/None
|
||||
#
|
||||
|
||||
r"""usage: prog [options]
|
||||
options:
|
||||
-a Add
|
||||
-m <msg> Message
|
||||
|
||||
"""
|
||||
$ prog -a
|
||||
{"-m": null, "-a": true}
|
||||
|
||||
#
|
||||
# Test options without description
|
||||
#
|
||||
|
||||
r"""usage: prog --hello"""
|
||||
$ prog --hello
|
||||
{"--hello": true}
|
||||
|
||||
r"""usage: prog [--hello=<world>]"""
|
||||
$ prog
|
||||
{"--hello": null}
|
||||
|
||||
$ prog --hello wrld
|
||||
{"--hello": "wrld"}
|
||||
|
||||
r"""usage: prog [-o]"""
|
||||
$ prog
|
||||
{"-o": false}
|
||||
|
||||
$ prog -o
|
||||
{"-o": true}
|
||||
|
||||
r"""usage: prog [-opr]"""
|
||||
$ prog -op
|
||||
{"-o": true, "-p": true, "-r": false}
|
||||
|
||||
r"""usage: git [-v | --verbose]"""
|
||||
$ prog -v
|
||||
{"-v": true, "--verbose": false}
|
||||
|
||||
r"""usage: git remote [-v | --verbose]"""
|
||||
$ prog remote -v
|
||||
{"remote": true, "-v": true, "--verbose": false}
|
||||
|
||||
#
|
||||
# Test empty usage pattern
|
||||
#
|
||||
|
||||
r"""usage: prog"""
|
||||
$ prog
|
||||
{}
|
||||
|
||||
r"""usage: prog
|
||||
prog <a> <b>
|
||||
"""
|
||||
$ prog 1 2
|
||||
{"<a>": "1", "<b>": "2"}
|
||||
|
||||
$ prog
|
||||
{"<a>": null, "<b>": null}
|
||||
|
||||
r"""usage: prog <a> <b>
|
||||
prog
|
||||
"""
|
||||
$ prog
|
||||
{"<a>": null, "<b>": null}
|
||||
|
||||
#
|
||||
# Option's argument should not capture default value from usage pattern
|
||||
#
|
||||
|
||||
r"""usage: prog [--file=<f>]"""
|
||||
$ prog
|
||||
{"--file": null}
|
||||
|
||||
r"""usage: prog [--file=<f>]
|
||||
|
||||
options: --file <a>
|
||||
|
||||
"""
|
||||
$ prog
|
||||
{"--file": null}
|
||||
|
||||
r"""Usage: prog [-a <host:port>]
|
||||
|
||||
Options: -a, --address <host:port> TCP address [default: localhost:6283].
|
||||
|
||||
"""
|
||||
$ prog
|
||||
{"--address": "localhost:6283"}
|
||||
|
||||
#
|
||||
# If option with argument could be repeated,
|
||||
# its arguments should be accumulated into a list
|
||||
#
|
||||
|
||||
r"""usage: prog --long=<arg> ..."""
|
||||
|
||||
$ prog --long one
|
||||
{"--long": ["one"]}
|
||||
|
||||
$ prog --long one --long two
|
||||
{"--long": ["one", "two"]}
|
||||
|
||||
#
|
||||
# Test multiple elements repeated at once
|
||||
#
|
||||
|
||||
r"""usage: prog (go <direction> --speed=<km/h>)..."""
|
||||
$ prog go left --speed=5 go right --speed=9
|
||||
{"go": 2, "<direction>": ["left", "right"], "--speed": ["5", "9"]}
|
||||
|
||||
#
|
||||
# Required options should work with option shortcut
|
||||
#
|
||||
|
||||
r"""usage: prog [options] -a
|
||||
|
||||
options: -a
|
||||
|
||||
"""
|
||||
$ prog -a
|
||||
{"-a": true}
|
||||
|
||||
#
|
||||
# If option could be repeated its defaults should be split into a list
|
||||
#
|
||||
|
||||
r"""usage: prog [-o <o>]...
|
||||
|
||||
options: -o <o> [default: x]
|
||||
|
||||
"""
|
||||
$ prog -o this -o that
|
||||
{"-o": ["this", "that"]}
|
||||
|
||||
$ prog
|
||||
{"-o": ["x"]}
|
||||
|
||||
r"""usage: prog [-o <o>]...
|
||||
|
||||
options: -o <o> [default: x y]
|
||||
|
||||
"""
|
||||
$ prog -o this
|
||||
{"-o": ["this"]}
|
||||
|
||||
$ prog
|
||||
{"-o": ["x", "y"]}
|
||||
|
||||
#
|
||||
# Test stacked option's argument
|
||||
#
|
||||
|
||||
r"""usage: prog -pPATH
|
||||
|
||||
options: -p PATH
|
||||
|
||||
"""
|
||||
$ prog -pHOME
|
||||
{"-p": "HOME"}
|
||||
|
||||
#
|
||||
# Issue 56: Repeated mutually exclusive args give nested lists sometimes
|
||||
#
|
||||
|
||||
r"""Usage: foo (--xx=x|--yy=y)..."""
|
||||
$ prog --xx=1 --yy=2
|
||||
{"--xx": ["1"], "--yy": ["2"]}
|
||||
|
||||
#
|
||||
# POSIXly correct tokenization
|
||||
#
|
||||
|
||||
r"""usage: prog [<input file>]"""
|
||||
$ prog f.txt
|
||||
{"<input file>": "f.txt"}
|
||||
|
||||
r"""usage: prog [--input=<file name>]..."""
|
||||
$ prog --input a.txt --input=b.txt
|
||||
{"--input": ["a.txt", "b.txt"]}
|
||||
|
||||
#
|
||||
# Issue 85: `[options]` shourtcut with multiple subcommands
|
||||
#
|
||||
|
||||
r"""usage: prog good [options]
|
||||
prog fail [options]
|
||||
|
||||
options: --loglevel=N
|
||||
|
||||
"""
|
||||
$ prog fail --loglevel 5
|
||||
{"--loglevel": "5", "fail": true, "good": false}
|
||||
|
||||
#
|
||||
# Usage-section syntax
|
||||
#
|
||||
|
||||
r"""usage:prog --foo"""
|
||||
$ prog --foo
|
||||
{"--foo": true}
|
||||
|
||||
r"""PROGRAM USAGE: prog --foo"""
|
||||
$ prog --foo
|
||||
{"--foo": true}
|
||||
|
||||
r"""Usage: prog --foo
|
||||
prog --bar
|
||||
NOT PART OF SECTION"""
|
||||
$ prog --foo
|
||||
{"--foo": true, "--bar": false}
|
||||
|
||||
r"""Usage:
|
||||
prog --foo
|
||||
prog --bar
|
||||
|
||||
NOT PART OF SECTION"""
|
||||
$ prog --foo
|
||||
{"--foo": true, "--bar": false}
|
||||
|
||||
r"""Usage:
|
||||
prog --foo
|
||||
prog --bar
|
||||
NOT PART OF SECTION"""
|
||||
$ prog --foo
|
||||
{"--foo": true, "--bar": false}
|
||||
|
||||
#
|
||||
# Options-section syntax
|
||||
#
|
||||
|
||||
r"""Usage: prog [options]
|
||||
|
||||
global options: --foo
|
||||
local options: --baz
|
||||
--bar
|
||||
other options:
|
||||
--egg
|
||||
--spam
|
||||
-not-an-option-
|
||||
|
||||
"""
|
||||
$ prog --baz --egg
|
||||
{"--foo": false, "--baz": true, "--bar": false, "--egg": true, "--spam": false}
|
||||
61
cli/cli.go
61
cli/cli.go
@@ -1,61 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type CLI struct {
|
||||
Commands map[string]Command
|
||||
HelpFunc func()
|
||||
}
|
||||
|
||||
func (c *CLI) Run(args []string) int {
|
||||
commandName, args := parseArgs(args)
|
||||
|
||||
if commandName == "help" {
|
||||
c.HelpFunc()
|
||||
return 0
|
||||
}
|
||||
|
||||
command := c.Commands[commandName]
|
||||
if command == nil {
|
||||
c.HelpFunc()
|
||||
return 1
|
||||
}
|
||||
|
||||
flags := flag.NewFlagSet(commandName, flag.ExitOnError)
|
||||
|
||||
command.RegisterFlags(flags)
|
||||
flags.Parse(args)
|
||||
|
||||
err := command.Execute(flags.Args())
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return 2
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func parseArgs(args []string) (string, []string) {
|
||||
command := ""
|
||||
|
||||
for _, arg := range args {
|
||||
if arg == "-v" || arg == "--version" {
|
||||
args = []string{"version"}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
command = args[0]
|
||||
args = args[1:]
|
||||
|
||||
if command == "-h" || command == "--help" {
|
||||
command = "help"
|
||||
}
|
||||
}
|
||||
|
||||
return command, args
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"testing"
|
||||
|
||||
"github.com/asciinema/asciinema-cli/cli"
|
||||
)
|
||||
|
||||
type testCommand struct {
|
||||
err error
|
||||
called bool
|
||||
}
|
||||
|
||||
func (c *testCommand) Execute(args []string) error {
|
||||
c.called = true
|
||||
return c.err
|
||||
}
|
||||
|
||||
func (c *testCommand) RegisterFlags(flags *flag.FlagSet) {
|
||||
}
|
||||
|
||||
func (c *testCommand) reset() {
|
||||
c.called = false
|
||||
}
|
||||
|
||||
func TestCLI_Run(t *testing.T) {
|
||||
helpCmd := &testCommand{}
|
||||
verCmd := &testCommand{}
|
||||
fooCmd := &testCommand{}
|
||||
barCmd := &testCommand{err: errors.New("oops")}
|
||||
|
||||
commands := map[string]cli.Command{
|
||||
"version": verCmd,
|
||||
"foo": fooCmd,
|
||||
"bar": barCmd,
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
args []string
|
||||
expectedExitCode int
|
||||
expectedCommand *testCommand
|
||||
}{
|
||||
{[]string{}, 1, helpCmd},
|
||||
{[]string{"-h"}, 0, helpCmd},
|
||||
{[]string{"--help"}, 0, helpCmd},
|
||||
{[]string{"wow", "-v"}, 0, verCmd},
|
||||
{[]string{"version"}, 0, verCmd},
|
||||
{[]string{"foo"}, 0, fooCmd},
|
||||
{[]string{"bar"}, 2, barCmd},
|
||||
{[]string{"nope"}, 1, helpCmd},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
helpCmd.reset()
|
||||
verCmd.reset()
|
||||
fooCmd.reset()
|
||||
barCmd.reset()
|
||||
|
||||
cli := &cli.CLI{
|
||||
Commands: commands,
|
||||
HelpFunc: func() { helpCmd.Execute(nil) },
|
||||
}
|
||||
|
||||
exitCode := cli.Run(test.args)
|
||||
|
||||
if exitCode != test.expectedExitCode {
|
||||
t.Errorf("expected exit code %v for %v, got %v", test.expectedExitCode, test, exitCode)
|
||||
}
|
||||
|
||||
if !test.expectedCommand.called {
|
||||
t.Errorf("expected command %v to be called", test.expectedCommand)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package cli
|
||||
|
||||
import "flag"
|
||||
|
||||
type Command interface {
|
||||
Execute([]string) error
|
||||
RegisterFlags(*flag.FlagSet)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"github.com/asciinema/asciinema-cli/cli"
|
||||
"github.com/asciinema/asciinema-cli/util"
|
||||
)
|
||||
|
||||
@@ -13,17 +11,14 @@ type AuthCommand struct {
|
||||
apiToken string
|
||||
}
|
||||
|
||||
func NewAuthCommand(cfg *util.Config) cli.Command {
|
||||
func NewAuthCommand(cfg *util.Config) *AuthCommand {
|
||||
return &AuthCommand{
|
||||
apiURL: cfg.API.URL,
|
||||
apiToken: cfg.API.Token,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *AuthCommand) RegisterFlags(flags *flag.FlagSet) {
|
||||
}
|
||||
|
||||
func (c *AuthCommand) Execute(args []string) error {
|
||||
func (c *AuthCommand) Execute() error {
|
||||
fmt.Println("Open the following URL in your browser to register your API token and assign any recorded asciicasts to your profile:")
|
||||
fmt.Printf("%v/connect/%v\n", c.apiURL, c.apiToken)
|
||||
|
||||
|
||||
@@ -1,35 +1,17 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
|
||||
"github.com/asciinema/asciinema-cli/asciicast"
|
||||
"github.com/asciinema/asciinema-cli/cli"
|
||||
)
|
||||
import "github.com/asciinema/asciinema-cli/asciicast"
|
||||
|
||||
type PlayCommand struct {
|
||||
Player asciicast.Player
|
||||
}
|
||||
|
||||
func NewPlayCommand() cli.Command {
|
||||
func NewPlayCommand() *PlayCommand {
|
||||
return &PlayCommand{
|
||||
Player: asciicast.NewPlayer(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *PlayCommand) RegisterFlags(flags *flag.FlagSet) {
|
||||
}
|
||||
|
||||
func (c *PlayCommand) Execute(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("filename required. Usage: asciinema play <file>")
|
||||
}
|
||||
|
||||
err := c.Player.Play(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
func (c *PlayCommand) Execute(filename string) error {
|
||||
return c.Player.Play(filename)
|
||||
}
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/asciinema/asciinema-cli/api"
|
||||
"github.com/asciinema/asciinema-cli/asciicast"
|
||||
"github.com/asciinema/asciinema-cli/cli"
|
||||
"github.com/asciinema/asciinema-cli/util"
|
||||
)
|
||||
|
||||
type RecordCommand struct {
|
||||
Cfg *util.Config
|
||||
API api.API
|
||||
Recorder asciicast.Recorder
|
||||
Command string
|
||||
Title string
|
||||
NoConfirm bool
|
||||
MaxWait uint
|
||||
Cfg *util.Config
|
||||
API api.API
|
||||
Recorder asciicast.Recorder
|
||||
}
|
||||
|
||||
func NewRecordCommand(api api.API, cfg *util.Config) cli.Command {
|
||||
func NewRecordCommand(api api.API, cfg *util.Config) *RecordCommand {
|
||||
return &RecordCommand{
|
||||
API: api,
|
||||
Cfg: cfg,
|
||||
@@ -30,89 +24,45 @@ func NewRecordCommand(api api.API, cfg *util.Config) cli.Command {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RecordCommand) RegisterFlags(flags *flag.FlagSet) {
|
||||
flags.StringVar(
|
||||
&c.Command,
|
||||
"c",
|
||||
defaultRecCommand(c.Cfg.Record.Command),
|
||||
"command to record",
|
||||
)
|
||||
|
||||
flags.StringVar(
|
||||
&c.Title,
|
||||
"t",
|
||||
"",
|
||||
"set asciicast title",
|
||||
)
|
||||
|
||||
flags.BoolVar(
|
||||
&c.NoConfirm,
|
||||
"y",
|
||||
false,
|
||||
"upload without asking for confirmation",
|
||||
)
|
||||
|
||||
flags.UintVar(
|
||||
&c.MaxWait,
|
||||
"max-wait",
|
||||
0,
|
||||
"reduce recorded terminal inactivity to maximum of <max-wait> seconds (0 turns off)",
|
||||
)
|
||||
}
|
||||
|
||||
func (c *RecordCommand) Execute(args []string) error {
|
||||
var path string
|
||||
func (c *RecordCommand) Execute(command, title string, assumeYes bool, maxWait uint, filename string) error {
|
||||
var upload bool
|
||||
var err error
|
||||
|
||||
if len(args) > 0 {
|
||||
path = args[0]
|
||||
if filename != "" {
|
||||
upload = false
|
||||
} else {
|
||||
path, err = tmpPath()
|
||||
filename, err = tmpPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
upload = true
|
||||
}
|
||||
|
||||
err = c.Recorder.Record(path, c.Command, c.Title, c.MaxWait)
|
||||
err = c.Recorder.Record(filename, command, title, maxWait)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if upload {
|
||||
if !c.NoConfirm {
|
||||
if !assumeYes {
|
||||
util.Printf("Press <Enter> to upload, <Ctrl-C> to cancel.")
|
||||
util.ReadLine()
|
||||
}
|
||||
|
||||
url, err := c.API.UploadAsciicast(path)
|
||||
url, err := c.API.UploadAsciicast(filename)
|
||||
if err != nil {
|
||||
util.Warningf("Upload failed, asciicast saved at %v", path)
|
||||
util.Warningf("Retry later by executing: asciinema upload %v", path)
|
||||
util.Warningf("Upload failed, asciicast saved at %v", filename)
|
||||
util.Warningf("Retry later by executing: asciinema upload %v", filename)
|
||||
return err
|
||||
}
|
||||
|
||||
os.Remove(path)
|
||||
os.Remove(filename)
|
||||
fmt.Println(url)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func defaultRecCommand(recCommand string) string {
|
||||
if recCommand == "" {
|
||||
recCommand = os.Getenv("SHELL")
|
||||
|
||||
if recCommand == "" {
|
||||
recCommand = "/bin/sh"
|
||||
}
|
||||
}
|
||||
|
||||
return recCommand
|
||||
}
|
||||
|
||||
func tmpPath() (string, error) {
|
||||
file, err := ioutil.TempFile("", "asciicast-")
|
||||
if err != nil {
|
||||
|
||||
@@ -47,14 +47,11 @@ func TestRecordCommand_Execute(t *testing.T) {
|
||||
api := &testAPI{err: test.apiError, t: t}
|
||||
|
||||
command := &commands.RecordCommand{
|
||||
Command: "ls",
|
||||
Title: "listing",
|
||||
MaxWait: 5,
|
||||
Recorder: recorder,
|
||||
API: api,
|
||||
}
|
||||
|
||||
err := command.Execute(nil)
|
||||
err := command.Execute("ls", "listing", false, 5, "")
|
||||
if err != test.expectedError {
|
||||
t.Errorf("expected error %v, got %v", test.expectedError, err)
|
||||
}
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"github.com/asciinema/asciinema-cli/api"
|
||||
"github.com/asciinema/asciinema-cli/cli"
|
||||
)
|
||||
|
||||
type UploadCommand struct {
|
||||
API api.API
|
||||
}
|
||||
|
||||
func NewUploadCommand(api api.API) cli.Command {
|
||||
func NewUploadCommand(api api.API) *UploadCommand {
|
||||
return &UploadCommand{
|
||||
API: api,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *UploadCommand) RegisterFlags(flags *flag.FlagSet) {
|
||||
}
|
||||
|
||||
func (c *UploadCommand) Execute(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("filename required. Usage: asciinema upload <file>")
|
||||
}
|
||||
|
||||
url, err := c.API.UploadAsciicast(args[0])
|
||||
func (c *UploadCommand) Execute(filename string) error {
|
||||
url, err := c.API.UploadAsciicast(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"github.com/asciinema/asciinema-cli/cli"
|
||||
)
|
||||
|
||||
type VersionCommand struct {
|
||||
version string
|
||||
gitCommit string
|
||||
}
|
||||
|
||||
func NewVersionCommand(version, gitCommit string) cli.Command {
|
||||
return &VersionCommand{
|
||||
version: version,
|
||||
gitCommit: gitCommit,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *VersionCommand) RegisterFlags(flags *flag.FlagSet) {
|
||||
}
|
||||
|
||||
func (c *VersionCommand) Execute(args []string) error {
|
||||
var commitInfo string
|
||||
|
||||
if c.gitCommit != "" {
|
||||
commitInfo = fmt.Sprintf("-%v", c.gitCommit)
|
||||
}
|
||||
|
||||
fmt.Printf("asciinema %v%v\n", c.version, commitInfo)
|
||||
|
||||
return nil
|
||||
}
|
||||
141
main.go
141
main.go
@@ -3,13 +3,96 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/asciinema/asciinema-cli/Godeps/_workspace/src/github.com/docopt/docopt-go"
|
||||
"github.com/asciinema/asciinema-cli/api"
|
||||
"github.com/asciinema/asciinema-cli/cli"
|
||||
"github.com/asciinema/asciinema-cli/commands"
|
||||
"github.com/asciinema/asciinema-cli/util"
|
||||
)
|
||||
|
||||
var usage = `Record and share your terminal sessions, the right way.
|
||||
|
||||
Usage:
|
||||
asciinema rec [-c <command>] [-t <title>] [-w <sec>] [-y] [<filename>]
|
||||
asciinema play <filename>
|
||||
asciinema upload <filename>
|
||||
asciinema auth
|
||||
asciinema -h | --help
|
||||
asciinema --version
|
||||
|
||||
Commands:
|
||||
rec Record terminal session
|
||||
play Replay terminal session
|
||||
upload Upload locally saved terminal session to asciinema.org
|
||||
auth Assign local API token to asciinema.org account
|
||||
|
||||
Options:
|
||||
-c, --command=<command> Specify command to record, defaults to $SHELL
|
||||
-t, --title=<title> Specify title of the asciicast
|
||||
-w, --max-wait=<sec> Reduce recorded terminal inactivity to max <sec> seconds
|
||||
-y, --yes Answer yes to all prompts (e.g. upload confirmation)
|
||||
-h, --help Show this message
|
||||
--version Show version`
|
||||
|
||||
func cmdName(args map[string]interface{}) string {
|
||||
for _, cmd := range []string{"rec", "play", "upload", "auth"} {
|
||||
if args[cmd].(bool) {
|
||||
return cmd
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func stringArg(args map[string]interface{}, name string) string {
|
||||
val := args[name]
|
||||
|
||||
if val != nil {
|
||||
return val.(string)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func boolArg(args map[string]interface{}, name string) bool {
|
||||
return args[name].(bool)
|
||||
}
|
||||
|
||||
func uintArg(args map[string]interface{}, name string) uint {
|
||||
val := args[name]
|
||||
|
||||
if val != nil {
|
||||
number, err := strconv.ParseUint(val.(string), 10, 0)
|
||||
|
||||
if err == nil {
|
||||
return uint(number)
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func firstNonBlank(candidates ...string) string {
|
||||
for _, candidate := range candidates {
|
||||
if candidate != "" {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func formatVersion() string {
|
||||
var commitInfo string
|
||||
|
||||
if GitCommit != "" {
|
||||
commitInfo = "-" + GitCommit
|
||||
}
|
||||
|
||||
return fmt.Sprintf("asciinema %v%v\n", Version, commitInfo)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if !util.IsUtf8Locale() {
|
||||
fmt.Println("asciinema needs a UTF-8 native locale to run. Check the output of `locale` command.")
|
||||
@@ -23,35 +106,35 @@ func main() {
|
||||
}
|
||||
|
||||
api := api.New(cfg.API.URL, cfg.API.Token, Version)
|
||||
args, _ := docopt.Parse(usage, nil, true, formatVersion(), false)
|
||||
|
||||
cli := &cli.CLI{
|
||||
Commands: map[string]cli.Command{
|
||||
"rec": commands.NewRecordCommand(api, cfg),
|
||||
"play": commands.NewPlayCommand(),
|
||||
"upload": commands.NewUploadCommand(api),
|
||||
"auth": commands.NewAuthCommand(cfg),
|
||||
"version": commands.NewVersionCommand(Version, GitCommit),
|
||||
},
|
||||
HelpFunc: help,
|
||||
switch cmdName(args) {
|
||||
case "rec":
|
||||
command := firstNonBlank(stringArg(args, "--command"), cfg.Record.Command, os.Getenv("SHELL"), "/bin/sh")
|
||||
title := stringArg(args, "--title")
|
||||
assumeYes := boolArg(args, "--yes")
|
||||
maxWait := uintArg(args, "--max-wait")
|
||||
filename := stringArg(args, "<filename>")
|
||||
cmd := commands.NewRecordCommand(api, cfg)
|
||||
err = cmd.Execute(command, title, assumeYes, maxWait, filename)
|
||||
|
||||
case "play":
|
||||
filename := stringArg(args, "<filename>")
|
||||
cmd := commands.NewPlayCommand()
|
||||
err = cmd.Execute(filename)
|
||||
|
||||
case "upload":
|
||||
filename := stringArg(args, "<filename>")
|
||||
cmd := commands.NewUploadCommand(api)
|
||||
err = cmd.Execute(filename)
|
||||
|
||||
case "auth":
|
||||
cmd := commands.NewAuthCommand(cfg)
|
||||
err = cmd.Execute()
|
||||
}
|
||||
|
||||
os.Exit(cli.Run(os.Args[1:]))
|
||||
}
|
||||
|
||||
func help() {
|
||||
fmt.Println(`usage: asciinema [-h] [-v] <command> [command-options]
|
||||
|
||||
Record and share your terminal sessions, the right way.
|
||||
|
||||
Commands:
|
||||
rec [filename] Record terminal session
|
||||
play <filename> Replay terminal session
|
||||
upload <filename> Upload locally saved terminal session
|
||||
auth Assign local API token to asciinema.org account
|
||||
|
||||
Options:
|
||||
-h, --help Display help message
|
||||
-v, --version Display version information
|
||||
|
||||
Run "asciinema <command> -h" to see the options available for the given command.`)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user