Skip to content

Commit 9ac2806

Browse files
committed
Merge go-ipfs-cmdkit into merge/cmdkit
2 parents 6a7c2ca + 9585892 commit 9ac2806

File tree

6 files changed

+641
-0
lines changed

6 files changed

+641
-0
lines changed

argument.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package cmdkit
2+
3+
type ArgumentType int
4+
5+
const (
6+
ArgString ArgumentType = iota
7+
ArgFile
8+
)
9+
10+
type Argument struct {
11+
Name string
12+
Type ArgumentType
13+
Required bool // error if no value is specified
14+
Variadic bool // unlimited values can be specfied
15+
SupportsStdin bool // can accept stdin as a value
16+
Recursive bool // supports recursive file adding (with '-r' flag)
17+
Description string
18+
}
19+
20+
func StringArg(name string, required, variadic bool, description string) Argument {
21+
return Argument{
22+
Name: name,
23+
Type: ArgString,
24+
Required: required,
25+
Variadic: variadic,
26+
Description: description,
27+
}
28+
}
29+
30+
func FileArg(name string, required, variadic bool, description string) Argument {
31+
return Argument{
32+
Name: name,
33+
Type: ArgFile,
34+
Required: required,
35+
Variadic: variadic,
36+
Description: description,
37+
}
38+
}
39+
40+
// TODO: modifiers might need a different API?
41+
// e.g. passing enum values into arg constructors variadically
42+
// (`FileArg("file", ArgRequired, ArgStdin, ArgRecursive)`)
43+
44+
func (a Argument) EnableStdin() Argument {
45+
a.SupportsStdin = true
46+
return a
47+
}
48+
49+
func (a Argument) EnableRecursive() Argument {
50+
if a.Type != ArgFile {
51+
panic("Only FileArgs can enable recursive")
52+
}
53+
54+
a.Recursive = true
55+
return a
56+
}

error.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package cmdkit
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
)
8+
9+
// ErrorType signfies a category of errors
10+
type ErrorType uint
11+
12+
// ErrorTypes convey what category of error ocurred
13+
const (
14+
ErrNormal ErrorType = iota // general errors
15+
ErrClient // error was caused by the client, (e.g. invalid CLI usage)
16+
ErrImplementation // programmer error in the server
17+
ErrNotFound // == HTTP 404
18+
ErrFatal // abort instantly
19+
// TODO: add more types of errors for better error-specific handling
20+
)
21+
22+
// Error is a struct for marshalling errors
23+
type Error struct {
24+
Message string
25+
Code ErrorType
26+
}
27+
28+
// Errorf returns an Error with the given code and format specification
29+
func Errorf(code ErrorType, format string, args ...interface{}) Error {
30+
return Error{
31+
Code: code,
32+
Message: fmt.Sprintf(format, args...),
33+
}
34+
}
35+
36+
func (e Error) Error() string {
37+
return e.Message
38+
}
39+
40+
func (e Error) MarshalJSON() ([]byte, error) {
41+
return json.Marshal(struct {
42+
Message string
43+
Code ErrorType
44+
Type string
45+
}{
46+
Message: e.Message,
47+
Code: e.Code,
48+
Type: "error",
49+
})
50+
}
51+
52+
func (e *Error) UnmarshalJSON(data []byte) error {
53+
var w struct {
54+
Message string
55+
Code ErrorType
56+
Type string
57+
}
58+
59+
err := json.Unmarshal(data, &w)
60+
if err != nil {
61+
return err
62+
}
63+
64+
if w.Type != "error" {
65+
return errors.New("not of type error")
66+
}
67+
68+
e.Message = w.Message
69+
e.Code = w.Code
70+
71+
return nil
72+
}

helptext.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package cmdkit
2+
3+
// HelpText is a set of strings used to generate command help text. The help
4+
// text follows formats similar to man pages, but not exactly the same.
5+
type HelpText struct {
6+
// required
7+
Tagline string // used in <cmd usage>
8+
ShortDescription string // used in DESCRIPTION
9+
SynopsisOptionsValues map[string]string // mappings for synopsis generator
10+
11+
// optional - whole section overrides
12+
Usage string // overrides USAGE section
13+
LongDescription string // overrides DESCRIPTION section
14+
Options string // overrides OPTIONS section
15+
Arguments string // overrides ARGUMENTS section
16+
Subcommands string // overrides SUBCOMMANDS section
17+
Synopsis string // overrides SYNOPSIS field
18+
}

json_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package cmdkit
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
)
7+
8+
func TestMarshal(t *testing.T) {
9+
type testcase struct {
10+
msg string
11+
code ErrorType
12+
}
13+
14+
tcs := []testcase{
15+
{msg: "error msg", code: 0},
16+
{msg: "error msg", code: 1},
17+
{msg: "some other error msg", code: 1},
18+
}
19+
20+
for _, tc := range tcs {
21+
e := Error{
22+
Message: tc.msg,
23+
Code: tc.code,
24+
}
25+
26+
buf, err := json.Marshal(e)
27+
if err != nil {
28+
t.Fatal(err)
29+
}
30+
31+
m := make(map[string]interface{})
32+
33+
err = json.Unmarshal(buf, &m)
34+
if err != nil {
35+
t.Fatal(err)
36+
}
37+
38+
if len(m) != 3 {
39+
t.Errorf("expected three map elements, got %d", len(m))
40+
}
41+
42+
if m["Message"].(string) != tc.msg {
43+
t.Errorf(`expected m["Message"] to be %q, got %q`, tc.msg, m["Message"])
44+
}
45+
46+
icode := ErrorType(m["Code"].(float64))
47+
if icode != tc.code {
48+
t.Errorf(`expected m["Code"] to be %v, got %v`, tc.code, icode)
49+
}
50+
51+
if m["Type"].(string) != "error" {
52+
t.Errorf(`expected m["Type"] to be %q, got %q`, "error", m["Type"])
53+
}
54+
}
55+
}
56+
57+
func TestUnmarshal(t *testing.T) {
58+
type testcase struct {
59+
json string
60+
msg string
61+
code ErrorType
62+
63+
err string
64+
}
65+
66+
tcs := []testcase{
67+
{json: `{"Message":"error msg","Code":0}`, msg: "error msg", err: "not of type error"},
68+
{json: `{"Message":"error msg","Code":0,"Type":"error"}`, msg: "error msg"},
69+
{json: `{"Message":"error msg","Code":1,"Type":"error"}`, msg: "error msg", code: 1},
70+
{json: `{"Message":"some other error msg","Code":1,"Type":"error"}`, msg: "some other error msg", code: 1},
71+
}
72+
73+
for i, tc := range tcs {
74+
t.Log("at test case", i)
75+
var e Error
76+
err := json.Unmarshal([]byte(tc.json), &e)
77+
if err != nil && err.Error() != tc.err {
78+
t.Errorf("expected parse error %q but got %q", tc.err, err)
79+
} else if err == nil && tc.err != "" {
80+
t.Errorf("expected parse error %q but got %q", tc.err, err)
81+
}
82+
83+
if err != nil {
84+
continue
85+
}
86+
87+
if e.Message != tc.msg {
88+
t.Errorf("expected e.Message to be %q, got %q", tc.msg, e.Message)
89+
}
90+
91+
if e.Code != tc.code {
92+
t.Errorf("expected e.Code to be %q, got %q", tc.code, e.Code)
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)