Compare commits

..

10 Commits

Author SHA1 Message Date
Cory Bennett 052e038d73 version bump 2017-09-11 00:16:10 -07:00
Cory Bennett a7f1323f34 Updated Changelog 2017-09-11 00:16:10 -07:00
Cory Bennett 8d27b736ca track *.lock 2017-09-11 00:16:01 -07:00
Cory Bennett c3c008e53d running dep prune 2017-09-11 00:11:56 -07:00
Cory Bennett 608e586d1c use --gjq for GJson Query to filter json response data, remove --jq option 2017-09-10 22:48:40 -07:00
Cory Bennett 2c552ac530 fix field tag syntax 2017-09-09 19:13:58 -07:00
Cory Bennett 1d269183c3 add --jq option to run a json query against Jira service response json 2017-09-09 19:02:23 -07:00
Cory Bennett e0e1e5b941 use {{jira}} in custom-command docs 2017-09-09 17:44:56 -07:00
Cory Bennett 941824d7f8 add '{{jira}}' template macro to refer to path of currently running jira command 2017-09-09 17:40:26 -07:00
Cory Bennett c585244f3e add basic tests for custom-commands 2017-09-09 17:20:57 -07:00
443 changed files with 5145 additions and 69466 deletions
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## 1.0.5 - 2017-09-11
* use --gjq for GJson Query to filter json response data [Cory Bennett] [[608e586](https://github.com/Netflix-Skunkworks/go-jira/commit/608e586)]
* fix field tag syntax [Cory Bennett] [[2c552ac](https://github.com/Netflix-Skunkworks/go-jira/commit/2c552ac)]
* add '{{jira}}' template macro to refer to path of currently running jira command [Cory Bennett] [[941824d](https://github.com/Netflix-Skunkworks/go-jira/commit/941824d)]
## 1.0.4 - 2017-09-08
* update deps for kingpeon update use os.exec instead of syscall.exec for windows [Cory Bennett] [[86b963b](https://github.com/Netflix-Skunkworks/go-jira/commit/86b963b)]
Generated
+165
View File
@@ -0,0 +1,165 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/alecthomas/template"
packages = [".","parse"]
revision = "a0175ee3bccc567396460bf5acd36800cb10c49c"
[[projects]]
branch = "master"
name = "github.com/alecthomas/units"
packages = ["."]
revision = "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
[[projects]]
branch = "master"
name = "github.com/cheekybits/genny"
packages = ["generic"]
revision = "9127e812e1e9e501ce899a18121d316ecb52e4ba"
[[projects]]
branch = "master"
name = "github.com/coryb/figtree"
packages = ["."]
revision = "86e7c859d0326621c45ba7be2c32e3b3ae203213"
[[projects]]
branch = "master"
name = "github.com/coryb/kingpeon"
packages = ["."]
revision = "64b561ae2d0f895b94719c486bed798f4236a4b3"
[[projects]]
branch = "master"
name = "github.com/coryb/oreo"
packages = ["."]
revision = "95687d61c95ee1522c1140e2af59b0c1846abfc1"
[[projects]]
branch = "master"
name = "github.com/fatih/camelcase"
packages = ["."]
revision = "f6a740d52f961c60348ebb109adde9f4635d7540"
[[projects]]
branch = "master"
name = "github.com/guelfey/go.dbus"
packages = ["."]
revision = "f6a3a2366cc39b8479cadc499d3c735fb10fbdda"
[[projects]]
branch = "master"
name = "github.com/jinzhu/copier"
packages = ["."]
revision = "32e0d0db1dcd4373fb9eb0f9d727b1fe1a723e54"
[[projects]]
branch = "master"
name = "github.com/kballard/go-shellquote"
packages = ["."]
revision = "cd60e84ee657ff3dc51de0b4f55dd299a3e136f2"
[[projects]]
branch = "master"
name = "github.com/mattn/go-colorable"
packages = ["."]
revision = "ad5389df28cdac544c99bd7b9161a0b5b6ca9d1b"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
revision = "fc9e8d8ef48496124e79ae0df75490096eccf6fe"
version = "v0.0.2"
[[projects]]
branch = "master"
name = "github.com/mgutz/ansi"
packages = ["."]
revision = "9520e82c474b0a04dd04f8a40959027271bab992"
[[projects]]
branch = "master"
name = "github.com/pkg/browser"
packages = ["."]
revision = "c90ca0c84f15f81c982e32665bffd8d7aac8f097"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
branch = "master"
name = "github.com/sethgrid/pester"
packages = ["."]
revision = "a86a2d88f4dc3c7dbf3a6a6bbbfb095690b834b6"
[[projects]]
branch = "master"
name = "github.com/theckman/go-flock"
packages = ["."]
revision = "6de226b0d5f040ed85b88c82c381709b98277f3d"
[[projects]]
branch = "master"
name = "github.com/tidwall/gjson"
packages = ["."]
revision = "be96719f990978a867f52c48f29d43f6b591da28"
[[projects]]
branch = "master"
name = "github.com/tidwall/match"
packages = ["."]
revision = "173748da739a410c5b0b813b956f89ff94730b4c"
[[projects]]
branch = "master"
name = "github.com/tmc/keyring"
packages = ["."]
revision = "06e6283d50adc5f8fcdb3cdf33ee1244d4400ae1"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
revision = "9ba3862cf6a5452ae579de98f9364dd2e544844c"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix","windows"]
revision = "a5054c7c1385fd50d9394475365355a87a7873ec"
[[projects]]
name = "gopkg.in/AlecAivazis/survey.v1"
packages = [".","core","terminal"]
revision = "9d910423e24aa6d7c7950160658c295e0734c7e0"
version = "1.3.1"
[[projects]]
name = "gopkg.in/alecthomas/kingpin.v2"
packages = ["."]
revision = "1087e65c9441605df944fb12c33f0fe7072d18ca"
version = "v2.2.5"
[[projects]]
branch = "v2"
name = "gopkg.in/coryb/yaml.v2"
packages = ["."]
revision = "fb7cb9628c6e3bdd76c29fb91798d51a09832470"
[[projects]]
name = "gopkg.in/op/go-logging.v1"
packages = ["."]
revision = "b2cb9fa56473e98db8caba80237377e83fe44db5"
version = "v1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "1f4b97fcf898a5ef03af5e222686a09328b393e71797d21bf0c37b74d1e74a8e"
solver-name = "gps-cdcl"
solver-version = 1
+75
View File
@@ -0,0 +1,75 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "github.com/coryb/figtree"
[[constraint]]
name = "github.com/coryb/kingpeon"
[[constraint]]
name = "github.com/coryb/oreo"
[[constraint]]
name = "github.com/jinzhu/copier"
[[constraint]]
name = "github.com/kballard/go-shellquote"
[[constraint]]
name = "github.com/mgutz/ansi"
[[constraint]]
name = "github.com/pkg/browser"
[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"
[[constraint]]
name = "github.com/savaki/jq"
[[constraint]]
name = "github.com/tmc/keyring"
[[constraint]]
name = "golang.org/x/crypto"
[[constraint]]
name = "gopkg.in/AlecAivazis/survey.v1"
version = "1.3.1"
[[constraint]]
name = "gopkg.in/alecthomas/kingpin.v2"
version = "2.2.5"
[[constraint]]
name = "gopkg.in/coryb/yaml.v2"
[[constraint]]
name = "gopkg.in/op/go-logging.v1"
version = "1.0.0"
[[constraint]]
branch = "master"
name = "github.com/tidwall/gjson"
+1 -1
View File
@@ -50,7 +50,7 @@ NEWVER ?= $(shell echo $(CURVER) | awk -F. '{print $$1"."$$2"."$$3+1}')
TODAY := $(shell date +%Y-%m-%d)
changes:
@git log --pretty=format:"* %s [%cn] [%h]" --no-merges ^v$(CURVER) HEAD *.go jiracli/*.go jiradata/*.go jiracmd/*.go cmd/*/*.go glide.* | grep -vE 'gofmt|go fmt|version bump'
@git log --pretty=format:"* %s [%cn] [%h]" --no-merges ^v$(CURVER) HEAD *.go jiracli/*.go jiradata/*.go jiracmd/*.go cmd/*/*.go *.lock | grep -vE 'gofmt|go fmt|version bump'
update-changelog:
@echo "# Changelog" > CHANGELOG.md.new; \
+4 -4
View File
@@ -56,7 +56,7 @@ custom-commands:
- name: mine
help: display issues assigned to me
script: |-
jira list --query "resolution = unresolved and assignee=currentuser() ORDER BY created"
{{jira}} list --query "resolution = unresolved and assignee=currentuser() ORDER BY created"
```
Then the next time you run `jira help` you will see your usage:
```
@@ -273,10 +273,10 @@ custom-commands:
script: |-
if [ -n "$JIRA_PROJECT" ]; then
# if `project: ...` configured just list the issues for current project
jira list --template table --query "resolution = unresolved and assignee=currentuser() and project = $JIRA_PROJECT ORDER BY priority asc, created"
{{jira}} list --template table --query "resolution = unresolved and assignee=currentuser() and project = $JIRA_PROJECT ORDER BY priority asc, created"
else
# otherwise list issues for all project
jira list --template table --query "resolution = unresolved and assignee=currentuser() ORDER BY priority asc, created"
{{jira}} list --template table --query "resolution = unresolved and assignee=currentuser() ORDER BY priority asc, created"
fi
```
* `jira sprint` for listing issues in your current sprint
@@ -287,7 +287,7 @@ custom-commands:
script: |-
if [ -n "$JIRA_PROJECT" ]; then
# if `project: ...` configured just list the issues for current project
jira list --template table --query "sprint in openSprints() and type != epic and resolution = unresolved and project=$JIRA_PROJECT ORDER BY rank asc, created"
{{jira}} list --template table --query "sprint in openSprints() and type != epic and resolution = unresolved and project=$JIRA_PROJECT ORDER BY rank asc, created"
else
# otherwise list issues for all project
echo "\"project: ...\" configuration missing from .jira.d/config.yml"
Generated
-64
View File
@@ -1,64 +0,0 @@
hash: 4c3ae9c9421b17aae9987ea9566cac7d0a789750bb77c8d235b7be163aec8cae
updated: 2017-09-08T18:47:08.390962401-07:00
imports:
- name: github.com/alecthomas/template
version: a0175ee3bccc567396460bf5acd36800cb10c49c
subpackages:
- parse
- name: github.com/alecthomas/units
version: 2efee857e7cfd4f3d0138cc3cbb1b4966962b93a
- name: github.com/cheekybits/genny
version: 9127e812e1e9e501ce899a18121d316ecb52e4ba
subpackages:
- generic
- name: github.com/coryb/figtree
version: 4429db55820d818320f5af8971ef8401baaf3d21
- name: github.com/coryb/kingpeon
version: 64b561ae2d0f895b94719c486bed798f4236a4b3
- name: github.com/coryb/oreo
version: 95687d61c95ee1522c1140e2af59b0c1846abfc1
- name: github.com/fatih/camelcase
version: f6a740d52f961c60348ebb109adde9f4635d7540
- name: github.com/guelfey/go.dbus
version: f6a3a2366cc39b8479cadc499d3c735fb10fbdda
- name: github.com/jinzhu/copier
version: 32e0d0db1dcd4373fb9eb0f9d727b1fe1a723e54
- name: github.com/kballard/go-shellquote
version: cd60e84ee657ff3dc51de0b4f55dd299a3e136f2
- name: github.com/mattn/go-colorable
version: ad5389df28cdac544c99bd7b9161a0b5b6ca9d1b
- name: github.com/mattn/go-isatty
version: fc9e8d8ef48496124e79ae0df75490096eccf6fe
- name: github.com/mgutz/ansi
version: 9520e82c474b0a04dd04f8a40959027271bab992
- name: github.com/pkg/browser
version: c90ca0c84f15f81c982e32665bffd8d7aac8f097
- name: github.com/pkg/errors
version: 645ef00459ed84a119197bfb8d8205042c6df63d
- name: github.com/sethgrid/pester
version: a86a2d88f4dc3c7dbf3a6a6bbbfb095690b834b6
- name: github.com/theckman/go-flock
version: 6de226b0d5f040ed85b88c82c381709b98277f3d
- name: github.com/tmc/keyring
version: 06e6283d50adc5f8fcdb3cdf33ee1244d4400ae1
- name: golang.org/x/crypto
version: 81e90905daefcd6fd217b62423c0908922eadb30
subpackages:
- ssh/terminal
- name: golang.org/x/sys
version: 5513e650ab47a692d3a036d49be8fa52ddd09b65
subpackages:
- unix
- windows
- name: gopkg.in/AlecAivazis/survey.v1
version: 9d910423e24aa6d7c7950160658c295e0734c7e0
subpackages:
- core
- terminal
- name: gopkg.in/alecthomas/kingpin.v2
version: 1087e65c9441605df944fb12c33f0fe7072d18ca
- name: gopkg.in/coryb/yaml.v2
version: fb7cb9628c6e3bdd76c29fb91798d51a09832470
- name: gopkg.in/op/go-logging.v1
version: b2cb9fa56473e98db8caba80237377e83fe44db5
testImports: []
-22
View File
@@ -1,22 +0,0 @@
package: gopkg.in/Netflix-Skunkworks/go-jira.v1
import:
- package: github.com/coryb/figtree
- package: github.com/coryb/kingpeon
- package: github.com/coryb/oreo
- package: github.com/jinzhu/copier
- package: github.com/kballard/go-shellquote
- package: github.com/mgutz/ansi
- package: github.com/pkg/browser
- package: github.com/pkg/errors
version: ^0.8.0
- package: github.com/tmc/keyring
- package: golang.org/x/crypto
subpackages:
- ssh/terminal
- package: gopkg.in/AlecAivazis/survey.v1
version: ^1.3.1
- package: gopkg.in/alecthomas/kingpin.v2
version: ^2.2.5
- package: gopkg.in/coryb/yaml.v2
- package: gopkg.in/op/go-logging.v1
version: ^1.0.0
+1 -1
View File
@@ -7,7 +7,7 @@ import (
var log = logging.MustGetLogger("jira")
const VERSION = "1.0.4"
const VERSION = "1.0.5"
type Jira struct {
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
+18
View File
@@ -16,6 +16,7 @@ import (
"github.com/coryb/oreo"
"github.com/jinzhu/copier"
shellquote "github.com/kballard/go-shellquote"
"github.com/tidwall/gjson"
"gopkg.in/AlecAivazis/survey.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2"
yaml "gopkg.in/coryb/yaml.v2"
@@ -40,6 +41,7 @@ type GlobalOptions struct {
type CommonOptions struct {
Browse figtree.BoolOption `yaml:"browse,omitempty" json:"browse,omitempty"`
Editor figtree.StringOption `yaml:"editor,omitempty" json:"editor,omitempty"`
GJsonQuery figtree.StringOption `yaml:"gjq,omitempty" json:"gjq,omitempty"`
SkipEditing figtree.BoolOption `yaml:"noedit,omitempty" json:"noedit,omitempty"`
Template figtree.StringOption `yaml:"template,omitempty" json:"template,omitempty"`
}
@@ -169,6 +171,22 @@ func TemplateUsage(cmd *kingpin.CmdClause, opts *CommonOptions) {
cmd.Flag("template", "Template to use for output").Short('t').SetValue(&opts.Template)
}
func GJsonQueryUsage(cmd *kingpin.CmdClause, opts *CommonOptions) {
cmd.Flag("gjq", "GJSON Query to filter output, see https://goo.gl/iaYwJ5").SetValue(&opts.GJsonQuery)
}
func (o *CommonOptions) PrintTemplate(data interface{}) error {
if o.GJsonQuery.Value != "" {
buf := bytes.NewBufferString("")
RunTemplate("json", data, buf)
results := gjson.GetBytes(buf.Bytes(), o.GJsonQuery.Value)
_, err := os.Stdout.Write([]byte(results.String()))
os.Stdout.Write([]byte{'\n'})
return err
}
return RunTemplate(o.Template.Value, data, nil)
}
func (o *CommonOptions) editFile(fileName string) (changes bool, err error) {
var editor string
for _, ed := range []string{o.Editor.Value, os.Getenv("JIRA_EDITOR"), os.Getenv("EDITOR"), "vim"} {
+21 -17
View File
@@ -60,6 +60,9 @@ func tmpTemplate(templateName string, data interface{}) (string, error) {
func TemplateProcessor() *template.Template {
funcs := map[string]interface{}{
"jira": func() string {
return os.Args[0]
},
"toJson": func(content interface{}) (string, error) {
bytes, err := json.MarshalIndent(content, "", " ")
if err != nil {
@@ -194,25 +197,26 @@ func RunTemplate(templateName string, data interface{}, out io.Writer) error {
}
var AllTemplates = map[string]string{
"component-add": defaultComponentAddTemplate,
"debug": defaultDebugTemplate,
"fields": defaultDebugTemplate,
"editmeta": defaultDebugTemplate,
"transmeta": defaultDebugTemplate,
"createmeta": defaultDebugTemplate,
"issuelinktypes": defaultDebugTemplate,
"list": defaultListTemplate,
"table": defaultTableTemplate,
"view": defaultViewTemplate,
"edit": defaultEditTemplate,
"transitions": defaultTransitionsTemplate,
"components": defaultComponentsTemplate,
"issuetypes": defaultIssuetypesTemplate,
"create": defaultCreateTemplate,
"subtask": defaultSubtaskTemplate,
"comment": defaultCommentTemplate,
"transition": defaultTransitionTemplate,
"component-add": defaultComponentAddTemplate,
"components": defaultComponentsTemplate,
"create": defaultCreateTemplate,
"createmeta": defaultDebugTemplate,
"debug": defaultDebugTemplate,
"edit": defaultEditTemplate,
"editmeta": defaultDebugTemplate,
"fields": defaultDebugTemplate,
"issuelinktypes": defaultDebugTemplate,
"issuetypes": defaultIssuetypesTemplate,
"json": defaultDebugTemplate,
"list": defaultListTemplate,
"request": defaultDebugTemplate,
"subtask": defaultSubtaskTemplate,
"table": defaultTableTemplate,
"transition": defaultTransitionTemplate,
"transitions": defaultTransitionsTemplate,
"transmeta": defaultDebugTemplate,
"view": defaultViewTemplate,
"worklog": defaultWorklogTemplate,
"worklogs": defaultWorklogsTemplate,
}
+2 -1
View File
@@ -37,6 +37,7 @@ func CmdComponentsRegistry() *jiracli.CommandRegistryEntry {
func CmdComponentsUsage(cmd *kingpin.CmdClause, opts *ComponentsOptions) error {
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
jiracli.GJsonQueryUsage(cmd, &opts.CommonOptions)
cmd.Flag("project", "project to list components").Short('p').StringVar(&opts.Project)
return nil
@@ -51,5 +52,5 @@ func CmdComponents(o *oreo.Client, globals *jiracli.GlobalOptions, opts *Compone
if err != nil {
return err
}
return jiracli.RunTemplate(opts.Template.Value, data, nil)
return opts.PrintTemplate(data)
}
+2 -1
View File
@@ -35,6 +35,7 @@ func CmdCreateMetaRegistry() *jiracli.CommandRegistryEntry {
func CmdCreateMetaUsage(cmd *kingpin.CmdClause, opts *CreateMetaOptions) error {
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
jiracli.GJsonQueryUsage(cmd, &opts.CommonOptions)
cmd.Flag("project", "project to fetch create metadata").Short('p').StringVar(&opts.Project)
cmd.Flag("issuetype", "issuetype in project to fetch create metadata").Short('i').StringVar(&opts.IssueType)
return nil
@@ -49,5 +50,5 @@ func CmdCreateMeta(o *oreo.Client, globals *jiracli.GlobalOptions, opts *CreateM
if err != nil {
return err
}
return jiracli.RunTemplate(opts.Template.Value, createMeta, nil)
return opts.PrintTemplate(createMeta)
}
+2 -1
View File
@@ -36,6 +36,7 @@ func CmdEditMetaRegistry() *jiracli.CommandRegistryEntry {
func CmdEditMetaUsage(cmd *kingpin.CmdClause, opts *EditMetaOptions) error {
jiracli.BrowseUsage(cmd, &opts.CommonOptions)
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
jiracli.GJsonQueryUsage(cmd, &opts.CommonOptions)
cmd.Arg("ISSUE", "edit metadata for issue id").Required().StringVar(&opts.Issue)
return nil
}
@@ -46,7 +47,7 @@ func CmdEditMeta(o *oreo.Client, globals *jiracli.GlobalOptions, opts *EditMetaO
if err != nil {
return err
}
if err := jiracli.RunTemplate(opts.Template.Value, editMeta, nil); err != nil {
if err := opts.PrintTemplate(editMeta); err != nil {
return err
}
if opts.Browse.Value {
+2 -1
View File
@@ -17,6 +17,7 @@ func CmdFieldsRegistry() *jiracli.CommandRegistryEntry {
func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
jiracli.LoadConfigs(cmd, fig, &opts)
jiracli.TemplateUsage(cmd, &opts)
jiracli.GJsonQueryUsage(cmd, &opts)
return nil
},
func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
@@ -31,5 +32,5 @@ func CmdFields(o *oreo.Client, globals *jiracli.GlobalOptions, opts *jiracli.Com
if err != nil {
return err
}
return jiracli.RunTemplate(opts.Template.Value, data, nil)
return opts.PrintTemplate(data)
}
+2 -1
View File
@@ -27,6 +27,7 @@ func CmdIssueLinkTypesRegistry() *jiracli.CommandRegistryEntry {
func CmdIssueLinkTypesUsage(cmd *kingpin.CmdClause, opts *jiracli.CommonOptions) error {
jiracli.TemplateUsage(cmd, opts)
jiracli.GJsonQueryUsage(cmd, opts)
return nil
}
@@ -36,5 +37,5 @@ func CmdIssueLinkTypes(o *oreo.Client, globals *jiracli.GlobalOptions, opts *jir
if err != nil {
return err
}
return jiracli.RunTemplate(opts.Template.Value, data, nil)
return opts.PrintTemplate(data)
}
+2 -1
View File
@@ -37,6 +37,7 @@ func CmdIssueTypesRegistry() *jiracli.CommandRegistryEntry {
func CmdIssueTypesUsage(cmd *kingpin.CmdClause, opts *IssueTypesOptions) error {
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
jiracli.GJsonQueryUsage(cmd, &opts.CommonOptions)
cmd.Flag("project", "project to list issueTypes").Short('p').StringVar(&opts.Project)
return nil
@@ -51,5 +52,5 @@ func CmdIssueTypes(o *oreo.Client, globals *jiracli.GlobalOptions, opts *IssueTy
if err != nil {
return err
}
return jiracli.RunTemplate(opts.Template.Value, data, nil)
return opts.PrintTemplate(data)
}
+2 -1
View File
@@ -43,6 +43,7 @@ func CmdListRegistry() *jiracli.CommandRegistryEntry {
func CmdListUsage(cmd *kingpin.CmdClause, opts *ListOptions) error {
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
jiracli.GJsonQueryUsage(cmd, &opts.CommonOptions)
cmd.Flag("assignee", "User assigned the issue").Short('a').StringVar(&opts.Assignee)
cmd.Flag("component", "Component to search for").Short('c').StringVar(&opts.Component)
cmd.Flag("issuetype", "Issue type to search for").Short('i').StringVar(&opts.IssueType)
@@ -62,5 +63,5 @@ func CmdList(o *oreo.Client, globals *jiracli.GlobalOptions, opts *ListOptions)
if err != nil {
return err
}
return jiracli.RunTemplate(opts.Template.Value, data, nil)
return opts.PrintTemplate(data)
}
+3 -1
View File
@@ -35,6 +35,8 @@ func CmdRequestRegistry() *jiracli.CommandRegistryEntry {
if opts.Method == "" {
opts.Method = "GET"
}
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
jiracli.GJsonQueryUsage(cmd, &opts.CommonOptions)
return CmdRequestUsage(cmd, &opts)
},
func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
@@ -89,5 +91,5 @@ func CmdRequest(o *oreo.Client, globals *jiracli.GlobalOptions, opts *RequestOpt
return fmt.Errorf("JSON Parse Error: %s from %q", err, content)
}
return jiracli.RunTemplate(opts.Template.Value, &data, nil)
return opts.PrintTemplate(&data)
}
+2 -1
View File
@@ -35,6 +35,7 @@ func CmdTransitionsRegistry(defaultTemplate string) *jiracli.CommandRegistryEntr
func CmdTransitionsUsage(cmd *kingpin.CmdClause, opts *TransitionsOptions) error {
jiracli.BrowseUsage(cmd, &opts.CommonOptions)
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
jiracli.GJsonQueryUsage(cmd, &opts.CommonOptions)
cmd.Arg("ISSUE", "issue to list valid transitions").Required().StringVar(&opts.Issue)
return nil
}
@@ -45,7 +46,7 @@ func CmdTransitions(o *oreo.Client, globals *jiracli.GlobalOptions, opts *Transi
if err != nil {
return err
}
if err := jiracli.RunTemplate(opts.Template.Value, editMeta, nil); err != nil {
if err := opts.PrintTemplate(editMeta); err != nil {
return err
}
if opts.Browse.Value {
+2 -1
View File
@@ -36,6 +36,7 @@ func CmdViewRegistry() *jiracli.CommandRegistryEntry {
func CmdViewUsage(cmd *kingpin.CmdClause, opts *ViewOptions) error {
jiracli.BrowseUsage(cmd, &opts.CommonOptions)
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
jiracli.GJsonQueryUsage(cmd, &opts.CommonOptions)
cmd.Flag("expand", "field to expand for the issue").StringsVar(&opts.Expand)
cmd.Flag("field", "field to return for the issue").StringsVar(&opts.Fields)
cmd.Flag("property", "property to return for issue").StringsVar(&opts.Properties)
@@ -49,7 +50,7 @@ func CmdView(o *oreo.Client, globals *jiracli.GlobalOptions, opts *ViewOptions)
if err != nil {
return err
}
if err := jiracli.RunTemplate(opts.Template.Value, data, nil); err != nil {
if err := opts.PrintTemplate(data); err != nil {
return err
}
if opts.Browse.Value {
+3 -2
View File
@@ -35,6 +35,7 @@ func CmdWorklogListRegistry() *jiracli.CommandRegistryEntry {
func CmdWorklogListUsage(cmd *kingpin.CmdClause, opts *WorklogListOptions) error {
jiracli.BrowseUsage(cmd, &opts.CommonOptions)
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
jiracli.GJsonQueryUsage(cmd, &opts.CommonOptions)
cmd.Arg("ISSUE", "issue id to fetch worklogs").Required().StringVar(&opts.Issue)
return nil
}
@@ -45,9 +46,9 @@ func CmdWorklogList(o *oreo.Client, globals *jiracli.GlobalOptions, opts *Worklo
if err != nil {
return err
}
if err := jiracli.RunTemplate(opts.Template.Value, struct {
if err := opts.PrintTemplate(struct {
Worklogs *jiradata.Worklogs `json:"worklogs,omitempty" yaml:"worklogs,omitempty"`
}{data}, nil); err != nil {
}{data}); err != nil {
return err
}
if opts.Browse.Value {
+39
View File
@@ -3,3 +3,42 @@ config:
password-source: pass
endpoint: https://go-jira.atlassian.net
user: gojira
project: BASIC
custom-commands:
- name: env
help: print the JIRA environment variables available to custom commands
script: |-
env | sort | grep JIRA
- name: print-project
help: print the name of the configured project
script: "echo $JIRA_PROJECT"
- name: jira-path
help: print the path the jira command that is running this alias
script: |-
echo {{jira}}
- name: mine
help: display issues assigned to me
script: |-
if [ -n "$JIRA_PROJECT" ]; then
# if `project: ...` configured just list the issues for current project
{{jira}} list --template table --query "resolution = unresolved and assignee=currentuser() and project = $JIRA_PROJECT ORDER BY priority asc, created"
else
# otherwise list issues for all project
{{jira}} list --template table --query "resolution = unresolved and assignee=currentuser() ORDER BY priority asc, created"
fi
- name: argtest
help: testing passing args
script: |-
echo {{args.ARG}}
args:
- name: ARG
help: string to echo for testing
- name: opttest
help: testing passing option flags
script: |-
echo {{options.OPT}}
options:
- name: OPT
help: string to echo for testing
+88
View File
@@ -0,0 +1,88 @@
#!/bin/bash
eval "$(curl -q -s https://raw.githubusercontent.com/coryb/osht/master/osht.sh)"
cd $(dirname $0)
jira="../jira"
. env.sh
PLAN 16
# reset login
RUNS $jira logout
RUNS $jira login
# cleanup from previous failed test executions
($jira ls --project BASIC | awk -F: '{print $1}' | while read issue; do ../jira done $issue; done) | sed 's/^/# CLEANUP: /g'
###############################################################################
## Create an issue
###############################################################################
RUNS $jira create --project BASIC -o summary=summary -o description=description --noedit --saveFile issue.props
issue=$(awk '/issue/{print $2}' issue.props)
DIFF <<EOF
OK $issue $ENDPOINT/browse/$issue
EOF
###############################################################################
## Testing the example custom commands, print-project
###############################################################################
RUNS $jira print-project
DIFF <<EOF
BASIC
EOF
###############################################################################
## Testing the example custom commands, jira-path
###############################################################################
RUNS $jira jira-path
DIFF <<EOF
../jira
EOF
###############################################################################
## Testing the example custom commands, env
###############################################################################
RUNS $jira env
DIFF <<'EOF'
JIRACLOUD=1
JIRA_CUSTOM_COMMANDS=[{"name":"env","script":"env | sort | grep JIRA","help":"print the JIRA environment variables available to custom commands"},{"name":"print-project","script":"echo $JIRA_PROJECT","help":"print the name of the configured project"},{"name":"jira-path","script":"echo {{jira}}","help":"print the path the jira command that is running this alias"},{"name":"mine","script":"if [ -n \"$JIRA_PROJECT\" ]; then\n # if `project: ...` configured just list the issues for current project\n {{jira}} list --template table --query \"resolution = unresolved and assignee=currentuser() and project = $JIRA_PROJECT ORDER BY priority asc, created\"\nelse\n # otherwise list issues for all project\n {{jira}} list --template table --query \"resolution = unresolved and assignee=currentuser() ORDER BY priority asc, created\"\nfi","help":"display issues assigned to me"},{"name":"argtest","args":[{"name":"ARG","help":"string to echo for testing"}],"script":"echo {{args.ARG}}","help":"testing passing args"},{"name":"opttest","options":[{"name":"OPT","help":"string to echo for testing"}],"script":"echo {{options.OPT}}","help":"testing passing option flags"}]
JIRA_ENDPOINT=https://go-jira.atlassian.net
JIRA_LOG_FORMAT=%{level:-5s} %{message}
JIRA_PASSWORD_SOURCE=pass
JIRA_PROJECT=BASIC
JIRA_USER=gojira
EOF
###############################################################################
## Testing the example custom commands, argtest
###############################################################################
RUNS $jira argtest TEST
DIFF <<EOF
TEST
EOF
###############################################################################
## Testing the example custom commands, opttest
###############################################################################
RUNS $jira opttest --OPT TEST
DIFF <<EOF
TEST
EOF
###############################################################################
## Use the "mine" alias to list issues assigned to self
###############################################################################
RUNS $jira mine
DIFF <<EOF
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
| Issue | Summary | Priority | Status | Age | Reporter | Assignee |
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
| $(printf %-14s $issue) | summary | Medium | To Do | a minute | gojira | gojira |
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
EOF
-2
View File
@@ -1,2 +0,0 @@
{{define "x"}}TEXT{{end}}
{{define "dotV"}}{{.V}}{{end}}
-2
View File
@@ -1,2 +0,0 @@
{{define "dot"}}{{.}}{{end}}
{{define "nested"}}{{template "dot" .}}{{end}}
-3
View File
@@ -1,3 +0,0 @@
template1
{{define "x"}}x{{end}}
{{template "y"}}
-3
View File
@@ -1,3 +0,0 @@
template2
{{define "y"}}y{{end}}
{{template "x"}}
-12
View File
@@ -1,12 +0,0 @@
package math
import "github.com/cheekybits/genny/generic"
type ThisNumberType generic.Number
func ThisNumberTypeMax(fn func(a, b ThisNumberType) bool, a, b ThisNumberType) ThisNumberType {
if fn(a, b) {
return a
}
return b
}
-3
View File
@@ -1,3 +0,0 @@
#!/bin/bash
cat ./generic_max.go | ../../genny gen "NumberType=NUMBERS" > numbers_max_get.go
cat ./func_thing.go | ../../genny gen "ThisNumberType=NUMBERS" > numbers_func_thing.go
-14
View File
@@ -1,14 +0,0 @@
package math
import "github.com/cheekybits/genny/generic"
type NumberType generic.Number
// NumberTypeMax gets the maximum number from the
// two specified.
func NumberTypeMax(a, b NumberType) NumberType {
if a > b {
return a
}
return b
}
-27
View File
@@ -1,27 +0,0 @@
package math_test
import (
"testing"
"github.com/cheekybits/genny/examples/davechaney"
)
func TestNumberTypeMax(t *testing.T) {
var v math.NumberType
v = math.NumberTypeMax(10, 20)
if v != 20 {
t.Errorf("Max of 10 and 20 is 20")
}
v = math.NumberTypeMax(20, 20)
if v != 20 {
t.Errorf("Max of 20 and 20 is 20")
}
v = math.NumberTypeMax(25, 20)
if v != 25 {
t.Errorf("Max of 25 and 20 is 25")
}
}
@@ -1,89 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package math
func Float32Max(fn func(a, b float32) bool, a, b float32) float32 {
if fn(a, b) {
return a
}
return b
}
func Float64Max(fn func(a, b float64) bool, a, b float64) float64 {
if fn(a, b) {
return a
}
return b
}
func IntMax(fn func(a, b int) bool, a, b int) int {
if fn(a, b) {
return a
}
return b
}
func Int16Max(fn func(a, b int16) bool, a, b int16) int16 {
if fn(a, b) {
return a
}
return b
}
func Int32Max(fn func(a, b int32) bool, a, b int32) int32 {
if fn(a, b) {
return a
}
return b
}
func Int64Max(fn func(a, b int64) bool, a, b int64) int64 {
if fn(a, b) {
return a
}
return b
}
func Int8Max(fn func(a, b int8) bool, a, b int8) int8 {
if fn(a, b) {
return a
}
return b
}
func UintMax(fn func(a, b uint) bool, a, b uint) uint {
if fn(a, b) {
return a
}
return b
}
func Uint16Max(fn func(a, b uint16) bool, a, b uint16) uint16 {
if fn(a, b) {
return a
}
return b
}
func Uint32Max(fn func(a, b uint32) bool, a, b uint32) uint32 {
if fn(a, b) {
return a
}
return b
}
func Uint64Max(fn func(a, b uint64) bool, a, b uint64) uint64 {
if fn(a, b) {
return a
}
return b
}
func Uint8Max(fn func(a, b uint8) bool, a, b uint8) uint8 {
if fn(a, b) {
return a
}
return b
}
@@ -1,29 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package gogenerate
type StringStringMap map[string]string
func NewStringStringMap() map[string]string {
return make(map[string]string)
}
type StringIntMap map[string]int
func NewStringIntMap() map[string]int {
return make(map[string]int)
}
type IntStringMap map[int]string
func NewIntStringMap() map[int]string {
return make(map[int]string)
}
type IntIntMap map[int]int
func NewIntIntMap() map[int]int {
return make(map[int]int)
}
-14
View File
@@ -1,14 +0,0 @@
package gogenerate
import "github.com/cheekybits/genny/generic"
//go:generate genny -in=$GOFILE -out=gen-$GOFILE gen "KeyType=string,int ValueType=string,int"
type KeyType generic.Type
type ValueType generic.Type
type KeyTypeValueTypeMap map[KeyType]ValueType
func NewKeyTypeValueTypeMap() map[KeyType]ValueType {
return make(map[KeyType]ValueType)
}
-2
View File
@@ -1,2 +0,0 @@
#!/bin/bash
cat ./queue_generic.go | ../../genny gen "Generic=string,int" > queue_generic_gen.go
-33
View File
@@ -1,33 +0,0 @@
package example
import "github.com/cheekybits/genny/generic"
type Generic generic.Type
// GenericQueue represents a queue of Generic types.
type GenericQueue struct {
items []Generic
}
// NewGenericQueue makes a new empty Generic queue.
func NewGenericQueue() *GenericQueue {
return &GenericQueue{items: make([]Generic, 0)}
}
// Enq adds an item to the queue.
func (q *GenericQueue) Enq(obj Generic) *GenericQueue {
q.items = append(q.items, obj)
return q
}
// Deq removes and returns the next item in the queue.
func (q *GenericQueue) Deq() Generic {
obj := q.items[0]
q.items = q.items[1:]
return obj
}
// Len gets the current number of Generic items in the queue.
func (q *GenericQueue) Len() int {
return len(q.items)
}
@@ -1,32 +0,0 @@
package example
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNew(t *testing.T) {
q := NewGenericQueue()
assert.NotNil(t, q)
}
func TestEnqueueAndDequeue(t *testing.T) {
item1 := new(Generic)
item2 := new(Generic)
q := NewGenericQueue()
assert.Equal(t, q, q.Enq(item1), "Enq should return the queue")
assert.Equal(t, 1, q.Len())
assert.Equal(t, q, q.Enq(item2), "Enq should return the queue")
assert.Equal(t, 2, q.Len())
assert.Equal(t, item1, q.Deq())
assert.Equal(t, 1, q.Len())
assert.Equal(t, item2, q.Deq())
assert.Equal(t, 0, q.Len())
}
-41
View File
@@ -1,41 +0,0 @@
package parse
// Builtins contains a slice of all built-in Go types.
var Builtins = []string{
"bool",
"byte",
"complex128",
"complex64",
"error",
"float32",
"float64",
"int",
"int16",
"int32",
"int64",
"int8",
"rune",
"string",
"uint",
"uint16",
"uint32",
"uint64",
"uint8",
"uintptr",
}
// Numbers contains a slice of all built-in number types.
var Numbers = []string{
"float32",
"float64",
"int",
"int16",
"int32",
"int64",
"int8",
"uint",
"uint16",
"uint32",
"uint64",
"uint8",
}
-14
View File
@@ -1,14 +0,0 @@
// Package parse contains the generic code generation capabilities
// that power genny.
//
// genny gen "{types}"
//
// gen - generates type specific code (to stdout) from generic code (via stdin)
//
// {types} - (required) Specific types for each generic type in the source
// {types} format: {generic}={specific}[,another][ {generic2}={specific2}]
// Examples:
// Generic=Specific
// Generic1=Specific1 Generic2=Specific2
// Generic1=Specific1,Specific2 Generic2=Specific3,Specific4
package parse
-47
View File
@@ -1,47 +0,0 @@
package parse
import (
"errors"
)
// errMissingSpecificType represents an error when a generic type is not
// satisfied by a specific type.
type errMissingSpecificType struct {
GenericType string
}
// Error gets a human readable string describing this error.
func (e errMissingSpecificType) Error() string {
return "Missing specific type for '" + e.GenericType + "' generic type"
}
// errImports represents an error from goimports.
type errImports struct {
Err error
}
// Error gets a human readable string describing this error.
func (e errImports) Error() string {
return "Failed to goimports the generated code: " + e.Err.Error()
}
// errSource represents an error with the source file.
type errSource struct {
Err error
}
// Error gets a human readable string describing this error.
func (e errSource) Error() string {
return "Failed to parse source file: " + e.Err.Error()
}
type errBadTypeArgs struct {
Message string
Arg string
}
func (e errBadTypeArgs) Error() string {
return "\"" + e.Arg + "\" is bad: " + e.Message
}
var errMissingTypeInformation = errors.New("No type arguments were specified and no \"// +gogen\" tag was found in the source.")
-271
View File
@@ -1,271 +0,0 @@
package parse
import (
"bufio"
"bytes"
"fmt"
"go/ast"
"go/parser"
"go/token"
"io"
"os"
"strings"
"unicode"
"golang.org/x/tools/imports"
)
type isExported bool
var header = []byte(`
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
`)
var (
packageKeyword = []byte("package")
importKeyword = []byte("import")
openBrace = []byte("(")
closeBrace = []byte(")")
space = " "
genericPackage = "generic"
genericType = "generic.Type"
genericNumber = "generic.Number"
linefeed = "\r\n"
)
var unwantedLinePrefixes = [][]byte{
[]byte("//go:generate genny "),
}
func generateSpecific(filename string, in io.ReadSeeker, typeSet map[string]string) ([]byte, error) {
// ensure we are at the beginning of the file
in.Seek(0, os.SEEK_SET)
// parse the source file
fs := token.NewFileSet()
file, err := parser.ParseFile(fs, filename, in, 0)
if err != nil {
return nil, &errSource{Err: err}
}
// make sure every generic.Type is represented in the types
// argument.
for _, decl := range file.Decls {
switch it := decl.(type) {
case *ast.GenDecl:
for _, spec := range it.Specs {
ts, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
switch tt := ts.Type.(type) {
case *ast.SelectorExpr:
if name, ok := tt.X.(*ast.Ident); ok {
if name.Name == genericPackage {
if _, ok := typeSet[ts.Name.Name]; !ok {
return nil, &errMissingSpecificType{GenericType: ts.Name.Name}
}
}
}
}
}
}
}
// go back to the start of the file
in.Seek(0, os.SEEK_SET)
var buf bytes.Buffer
comment := ""
scanner := bufio.NewScanner(in)
for scanner.Scan() {
l := scanner.Text()
// does this line contain generic.Type?
if strings.Contains(l, genericType) || strings.Contains(l, genericNumber) {
comment = ""
continue
}
for t, specificType := range typeSet {
// does the line contain our type
if strings.Contains(l, t) {
var newLine string
// check each word
for _, word := range strings.Fields(l) {
i := 0
for {
i = strings.Index(word[i:], t) // find out where
if i > -1 {
// if this isn't an exact match
if i > 0 && isAlphaNumeric(rune(word[i-1])) || i < len(word)-len(t) && isAlphaNumeric(rune(word[i+len(t)])) {
// replace the word with a capitolized version
word = strings.Replace(word, t, wordify(specificType, unicode.IsUpper(rune(strings.TrimLeft(word, "*&")[0]))), 1)
} else {
// replace the word as is
word = strings.Replace(word, t, specificType, 1)
}
} else {
newLine = newLine + word + space
break
}
}
}
l = newLine
}
}
if comment != "" {
buf.WriteString(line(comment))
comment = ""
}
// is this line a comment?
// TODO: should we handle /* */ comments?
if strings.HasPrefix(l, "//") {
// record this line to print later
comment = l
continue
}
// write the line
buf.WriteString(line(l))
}
// write it out
return buf.Bytes(), nil
}
// Generics parses the source file and generates the bytes replacing the
// generic types for the keys map with the specific types (its value).
func Generics(filename, pkgName string, in io.ReadSeeker, typeSets []map[string]string) ([]byte, error) {
totalOutput := header
for _, typeSet := range typeSets {
// generate the specifics
parsed, err := generateSpecific(filename, in, typeSet)
if err != nil {
return nil, err
}
totalOutput = append(totalOutput, parsed...)
}
// clean up the code line by line
packageFound := false
insideImportBlock := false
var cleanOutputLines []string
scanner := bufio.NewScanner(bytes.NewReader(totalOutput))
for scanner.Scan() {
// end of imports block?
if insideImportBlock {
if bytes.HasSuffix(scanner.Bytes(), closeBrace) {
insideImportBlock = false
}
continue
}
if bytes.HasPrefix(scanner.Bytes(), packageKeyword) {
if packageFound {
continue
} else {
packageFound = true
}
} else if bytes.HasPrefix(scanner.Bytes(), importKeyword) {
if bytes.HasSuffix(scanner.Bytes(), openBrace) {
insideImportBlock = true
}
continue
}
// check all unwantedLinePrefixes - and skip them
skipline := false
for _, prefix := range unwantedLinePrefixes {
if bytes.HasPrefix(scanner.Bytes(), prefix) {
skipline = true
continue
}
}
if skipline {
continue
}
cleanOutputLines = append(cleanOutputLines, line(scanner.Text()))
}
cleanOutput := strings.Join(cleanOutputLines, "")
output := []byte(cleanOutput)
var err error
// change package name
if pkgName != "" {
output = changePackage(bytes.NewReader([]byte(output)), pkgName)
}
// fix the imports
output, err = imports.Process(filename, output, nil)
if err != nil {
return nil, &errImports{Err: err}
}
return output, nil
}
func line(s string) string {
return fmt.Sprintln(strings.TrimRight(s, linefeed))
}
// isAlphaNumeric gets whether the rune is alphanumeric or _.
func isAlphaNumeric(r rune) bool {
return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
}
// wordify turns a type into a nice word for function and type
// names etc.
func wordify(s string, exported bool) string {
s = strings.TrimRight(s, "{}")
s = strings.TrimLeft(s, "*&")
s = strings.Replace(s, ".", "", -1)
if !exported {
return s
}
return strings.ToUpper(string(s[0])) + s[1:]
}
func changePackage(r io.Reader, pkgName string) []byte {
var out bytes.Buffer
sc := bufio.NewScanner(r)
done := false
for sc.Scan() {
s := sc.Text()
if !done && strings.HasPrefix(s, "package") {
parts := strings.Split(s, " ")
parts[1] = pkgName
s = strings.Join(parts, " ")
done = true
}
fmt.Fprintln(&out, s)
}
return out.Bytes()
}
-35
View File
@@ -1,35 +0,0 @@
package parse
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestIsAlphaNumeric(t *testing.T) {
for _, r := range []rune{'a', '1', '_', 'A', 'Z'} {
assert.True(t, isAlphaNumeric(r))
}
for _, r := range []rune{' ', '[', ']', '!', '"'} {
assert.False(t, isAlphaNumeric(r))
}
}
func TestWordify(t *testing.T) {
for word, wordified := range map[string]string{
"int": "Int",
"*int": "Int",
"string": "String",
"*MyType": "MyType",
"*myType": "MyType",
"interface{}": "Interface",
"pack.type": "Packtype",
"*pack.type": "Packtype",
} {
assert.Equal(t, wordified, wordify(word, true))
}
}
-126
View File
@@ -1,126 +0,0 @@
package parse_test
import (
"io/ioutil"
"log"
"strings"
"testing"
"github.com/cheekybits/genny/parse"
"github.com/stretchr/testify/assert"
)
var tests = []struct {
// input
filename string
pkgName string
in string
types []map[string]string
// expectations
expectedOut string
expectedErr error
}{
{
filename: "generic_queue.go",
in: `test/queue/generic_queue.go`,
types: []map[string]string{{"Something": "int"}},
expectedOut: `test/queue/int_queue.go`,
},
{
filename: "generic_queue.go",
pkgName: "changed",
in: `test/queue/generic_queue.go`,
types: []map[string]string{{"Something": "int"}},
expectedOut: `test/queue/changed/int_queue.go`,
},
{
filename: "generic_queue.go",
in: `test/queue/generic_queue.go`,
types: []map[string]string{{"Something": "float32"}},
expectedOut: `test/queue/float32_queue.go`,
},
{
filename: "generic_simplemap.go",
in: `test/multipletypes/generic_simplemap.go`,
types: []map[string]string{{"KeyType": "string", "ValueType": "int"}},
expectedOut: `test/multipletypes/string_int_simplemap.go`,
},
{
filename: "generic_simplemap.go",
in: `test/multipletypes/generic_simplemap.go`,
types: []map[string]string{{"KeyType": "interface{}", "ValueType": "int"}},
expectedOut: `test/multipletypes/interface_int_simplemap.go`,
},
{
filename: "generic_simplemap.go",
in: `test/multipletypes/generic_simplemap.go`,
types: []map[string]string{{"KeyType": "*MyType1", "ValueType": "*MyOtherType"}},
expectedOut: `test/multipletypes/custom_types_simplemap.go`,
},
{
filename: "generic_internal.go",
in: `test/unexported/generic_internal.go`,
types: []map[string]string{{"secret": "*myType"}},
expectedOut: `test/unexported/mytype_internal.go`,
},
{
filename: "generic_simplemap.go",
in: `test/multipletypesets/generic_simplemap.go`,
types: []map[string]string{
{"KeyType": "int", "ValueType": "string"},
{"KeyType": "float64", "ValueType": "bool"},
},
expectedOut: `test/multipletypesets/many_simplemaps.go`,
},
{
filename: "generic_number.go",
in: `test/numbers/generic_number.go`,
types: []map[string]string{{"NumberType": "int"}},
expectedOut: `test/numbers/int_number.go`,
},
{
filename: "generic_digraph.go",
in: `test/bugreports/generic_digraph.go`,
types: []map[string]string{{"Node": "int"}},
expectedOut: `test/bugreports/int_digraph.go`,
},
}
func TestParse(t *testing.T) {
for _, test := range tests {
test.in = contents(test.in)
test.expectedOut = contents(test.expectedOut)
bytes, err := parse.Generics(test.filename, test.pkgName, strings.NewReader(test.in), test.types)
// check the error
if test.expectedErr == nil {
assert.NoError(t, err, "(%s) No error was expected but got: %s", test.filename, err)
} else {
assert.NotNil(t, err, "(%s) No error was returned by one was expected: %s", test.filename, test.expectedErr)
assert.IsType(t, test.expectedErr, err, "(%s) Generate should return object of type %v", test.filename, test.expectedErr)
}
// assert the response
if !assert.Equal(t, string(bytes), test.expectedOut, "Parse didn't generate the expected output.") {
log.Println("EXPECTED: " + test.expectedOut)
log.Println("ACTUAL: " + string(bytes))
}
}
}
func contents(s string) string {
if strings.HasSuffix(s, "go") {
file, err := ioutil.ReadFile(s)
if err != nil {
panic(err)
}
return string(file)
}
return s
}
@@ -1,30 +0,0 @@
package bugreports
import "github.com/cheekybits/genny/generic"
type Node generic.Type
type DigraphNode struct {
nodes map[Node][]Node
}
func NewDigraphNode() *DigraphNode {
return &DigraphNode{
nodes: make(map[Node][]Node),
}
}
func (dig *DigraphNode) Add(n Node) {
if _, exists := dig.nodes[n]; exists {
return
}
dig.nodes[n] = nil
}
func (dig *DigraphNode) Connect(a, b Node) {
dig.Add(a)
dig.Add(b)
dig.nodes[a] = append(dig.nodes[a], b)
}
@@ -1,30 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package bugreports
type DigraphInt struct {
nodes map[int][]int
}
func NewDigraphInt() *DigraphInt {
return &DigraphInt{
nodes: make(map[int][]int),
}
}
func (dig *DigraphInt) Add(n int) {
if _, exists := dig.nodes[n]; exists {
return
}
dig.nodes[n] = nil
}
func (dig *DigraphInt) Connect(a, b int) {
dig.Add(a)
dig.Add(b)
dig.nodes[a] = append(dig.nodes[a], b)
}
@@ -1,5 +0,0 @@
package multipletypes
type MyType1 struct{}
type MyOtherType struct{}
@@ -1,21 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package multipletypes
type MyType1MyOtherTypeMap map[*MyType1]*MyOtherType
func (m MyType1MyOtherTypeMap) Has(key *MyType1) bool {
_, ok := m[key]
return ok
}
func (m MyType1MyOtherTypeMap) Get(key *MyType1) *MyOtherType {
return m[key]
}
func (m MyType1MyOtherTypeMap) Set(key *MyType1, value *MyOtherType) MyType1MyOtherTypeMap {
m[key] = value
return m
}
@@ -1,22 +0,0 @@
package multipletypes
import "github.com/cheekybits/genny/generic"
type KeyType generic.Type
type ValueType generic.Type
type KeyTypeValueTypeMap map[KeyType]ValueType
func (m KeyTypeValueTypeMap) Has(key KeyType) bool {
_, ok := m[key]
return ok
}
func (m KeyTypeValueTypeMap) Get(key KeyType) ValueType {
return m[key]
}
func (m KeyTypeValueTypeMap) Set(key KeyType, value ValueType) KeyTypeValueTypeMap {
m[key] = value
return m
}
@@ -1,35 +0,0 @@
package multipletypes
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSimpleMap(t *testing.T) {
key1 := new(KeyType)
key2 := new(KeyType)
value1 := new(ValueType)
m := make(KeyTypeValueTypeMap)
assert.Equal(t, m, m.Set(key1, value1))
assert.True(t, m.Has(key1))
assert.False(t, m.Has(key2))
assert.Equal(t, value1, m.Get(key1))
}
func TestCustomTypesMap(t *testing.T) {
key1 := new(MyType1)
key2 := new(MyType1)
value1 := new(MyOtherType)
m := make(MyType1MyOtherTypeMap)
assert.Equal(t, m, m.Set(key1, value1))
assert.True(t, m.Has(key1))
assert.False(t, m.Has(key2))
assert.Equal(t, value1, m.Get(key1))
}
@@ -1,21 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package multipletypes
type InterfaceIntMap map[interface{}]int
func (m InterfaceIntMap) Has(key interface{}) bool {
_, ok := m[key]
return ok
}
func (m InterfaceIntMap) Get(key interface{}) int {
return m[key]
}
func (m InterfaceIntMap) Set(key interface{}, value int) InterfaceIntMap {
m[key] = value
return m
}
@@ -1,21 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package multipletypes
type StringIntMap map[string]int
func (m StringIntMap) Has(key string) bool {
_, ok := m[key]
return ok
}
func (m StringIntMap) Get(key string) int {
return m[key]
}
func (m StringIntMap) Set(key string, value int) StringIntMap {
m[key] = value
return m
}
@@ -1,27 +0,0 @@
package multipletypesets
import (
"log"
"github.com/cheekybits/genny/generic"
)
type KeyType generic.Type
type ValueType generic.Type
type KeyTypeValueTypeMap map[KeyType]ValueType
func (m KeyTypeValueTypeMap) Has(key KeyType) bool {
_, ok := m[key]
return ok
}
func (m KeyTypeValueTypeMap) Get(key KeyType) ValueType {
return m[key]
}
func (m KeyTypeValueTypeMap) Set(key KeyType, value ValueType) KeyTypeValueTypeMap {
log.Println(value)
m[key] = value
return m
}
@@ -1,21 +0,0 @@
package multipletypesets
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSimpleMap(t *testing.T) {
key1 := new(KeyType)
key2 := new(KeyType)
value1 := new(ValueType)
m := make(KeyTypeValueTypeMap)
assert.Equal(t, m, m.Set(key1, value1))
assert.True(t, m.Has(key1))
assert.False(t, m.Has(key2))
assert.Equal(t, value1, m.Get(key1))
}
@@ -1,41 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package multipletypesets
import "log"
type IntStringMap map[int]string
func (m IntStringMap) Has(key int) bool {
_, ok := m[key]
return ok
}
func (m IntStringMap) Get(key int) string {
return m[key]
}
func (m IntStringMap) Set(key int, value string) IntStringMap {
log.Println(value)
m[key] = value
return m
}
type Float64BoolMap map[float64]bool
func (m Float64BoolMap) Has(key float64) bool {
_, ok := m[key]
return ok
}
func (m Float64BoolMap) Get(key float64) bool {
return m[key]
}
func (m Float64BoolMap) Set(key float64, value bool) Float64BoolMap {
log.Println(value)
m[key] = value
return m
}
@@ -1,12 +0,0 @@
package numbers
import "github.com/cheekybits/genny/generic"
type NumberType generic.Number
func NumberTypeMax(a, b NumberType) NumberType {
if a > b {
return a
}
return b
}
-12
View File
@@ -1,12 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package numbers
func IntMax(a, b int) int {
if a > b {
return a
}
return b
}
@@ -1,22 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package changed
// IntQueue is a queue of Ints.
type IntQueue struct {
items []int
}
func NewIntQueue() *IntQueue {
return &IntQueue{items: make([]int, 0)}
}
func (q *IntQueue) Push(item int) {
q.items = append(q.items, item)
}
func (q *IntQueue) Pop() int {
item := q.items[0]
q.items = q.items[1:]
return item
}
-22
View File
@@ -1,22 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package queue
// Float32Queue is a queue of Float32s.
type Float32Queue struct {
items []float32
}
func NewFloat32Queue() *Float32Queue {
return &Float32Queue{items: make([]float32, 0)}
}
func (q *Float32Queue) Push(item float32) {
q.items = append(q.items, item)
}
func (q *Float32Queue) Pop() float32 {
item := q.items[0]
q.items = q.items[1:]
return item
}
-23
View File
@@ -1,23 +0,0 @@
package queue
import "github.com/cheekybits/genny/generic"
// Something is a type that does something
type Something generic.Type
// SomethingQueue is a queue of Somethings.
type SomethingQueue struct {
items []Something
}
func NewSomethingQueue() *SomethingQueue {
return &SomethingQueue{items: make([]Something, 0)}
}
func (q *SomethingQueue) Push(item Something) {
q.items = append(q.items, item)
}
func (q *SomethingQueue) Pop() Something {
item := q.items[0]
q.items = q.items[1:]
return item
}
@@ -1,87 +0,0 @@
package queue
import "testing"
func TestSomethingQueue(t *testing.T) {
var item1 *Something = new(Something)
var item2 *Something = new(Something)
var item3 *Something = new(Something)
q := NewSomethingQueue()
q.Push(item1)
if len(q.items) != 1 {
t.Error("Push should add the item")
}
q.Push(item2)
if len(q.items) != 2 {
t.Error("Push should add the item")
}
q.Push(item3)
if len(q.items) != 3 {
t.Error("Push should add the item")
}
if q.Pop() != item1 {
t.Error("Pop should return items in the order in which they were added")
}
if len(q.items) != 2 {
t.Error("Pop should remove the item")
}
if q.Pop() != item2 {
t.Error("Pop should return items in the order in which they were added")
}
if len(q.items) != 1 {
t.Error("Pop should remove the item")
}
if q.Pop() != item3 {
t.Error("Pop should return items in the order in which they were added")
}
if len(q.items) != 0 {
t.Error("Pop should remove the item")
}
}
func TestIntQueue(t *testing.T) {
var item1 int = 1
var item2 int = 2
var item3 int = 3
q := NewIntQueue()
q.Push(item1)
if len(q.items) != 1 {
t.Error("Push should add the item")
}
q.Push(item2)
if len(q.items) != 2 {
t.Error("Push should add the item")
}
q.Push(item3)
if len(q.items) != 3 {
t.Error("Push should add the item")
}
if q.Pop() != item1 {
t.Error("Pop should return items in the order in which they were added")
}
if len(q.items) != 2 {
t.Error("Pop should remove the item")
}
if q.Pop() != item2 {
t.Error("Pop should return items in the order in which they were added")
}
if len(q.items) != 1 {
t.Error("Pop should remove the item")
}
if q.Pop() != item3 {
t.Error("Pop should return items in the order in which they were added")
}
if len(q.items) != 0 {
t.Error("Pop should remove the item")
}
}
-22
View File
@@ -1,22 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package queue
// IntQueue is a queue of Ints.
type IntQueue struct {
items []int
}
func NewIntQueue() *IntQueue {
return &IntQueue{items: make([]int, 0)}
}
func (q *IntQueue) Push(item int) {
q.items = append(q.items, item)
}
func (q *IntQueue) Pop() int {
item := q.items[0]
q.items = q.items[1:]
return item
}
-24
View File
@@ -1,24 +0,0 @@
package slice
import (
"log"
"reflect"
"github.com/cheekybits/genny/generic"
)
type MyType generic.Type
func EnsureSlice(objectOrSlice interface{}) []MyType {
log.Printf("%v", reflect.TypeOf(objectOrSlice))
switch obj := objectOrSlice.(type) {
case []MyType:
log.Println(" returning it untouched")
return obj
case MyType, *MyType:
log.Println(" wrapping in slice")
return []MyType{obj}
default:
panic("ensure slice needs MyType or []MyType")
}
}
@@ -1,24 +0,0 @@
package slice
import (
"log"
"testing"
"github.com/stretchr/testify/assert"
)
func TestEnsureSlice(t *testing.T) {
myType := new(MyType)
slice := EnsureSlice(myType)
if assert.NotNil(t, slice) {
assert.Equal(t, slice[0], myType)
}
slice = EnsureSlice(slice)
log.Printf("%#v", slice[0])
if assert.NotNil(t, slice) {
assert.Equal(t, slice[0], myType)
}
}
@@ -1,3 +0,0 @@
package unexported
type myType struct{}
@@ -1,13 +0,0 @@
package unexported
import (
"fmt"
"github.com/cheekybits/genny/generic"
)
type secret generic.Type
func secretInspect(s secret) string {
return fmt.Sprintf("%#v", s)
}
@@ -1,11 +0,0 @@
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
package unexported
import "fmt"
func myTypeInspect(s *myType) string {
return fmt.Sprintf("%#v", s)
}
-89
View File
@@ -1,89 +0,0 @@
package parse
import "strings"
const (
typeSep = " "
keyValueSep = "="
valuesSep = ","
builtins = "BUILTINS"
numbers = "NUMBERS"
)
// TypeSet turns a type string into a []map[string]string
// that can be given to parse.Generics for it to do its magic.
//
// Acceptable args are:
//
// Person=man
// Person=man Animal=dog
// Person=man Animal=dog Animal2=cat
// Person=man,woman Animal=dog,cat
// Person=man,woman,child Animal=dog,cat Place=london,paris
func TypeSet(arg string) ([]map[string]string, error) {
types := make(map[string][]string)
var keys []string
for _, pair := range strings.Split(arg, typeSep) {
segs := strings.Split(pair, keyValueSep)
if len(segs) != 2 {
return nil, &errBadTypeArgs{Arg: arg, Message: "Generic=Specific expected"}
}
key := segs[0]
keys = append(keys, key)
types[key] = make([]string, 0)
for _, t := range strings.Split(segs[1], valuesSep) {
if t == builtins {
types[key] = append(types[key], Builtins...)
} else if t == numbers {
types[key] = append(types[key], Numbers...)
} else {
types[key] = append(types[key], t)
}
}
}
cursors := make(map[string]int)
for _, key := range keys {
cursors[key] = 0
}
outChan := make(chan map[string]string)
go func() {
buildTypeSet(keys, 0, cursors, types, outChan)
close(outChan)
}()
var typeSets []map[string]string
for typeSet := range outChan {
typeSets = append(typeSets, typeSet)
}
return typeSets, nil
}
func buildTypeSet(keys []string, keyI int, cursors map[string]int, types map[string][]string, out chan<- map[string]string) {
key := keys[keyI]
for cursors[key] < len(types[key]) {
if keyI < len(keys)-1 {
buildTypeSet(keys, keyI+1, copycursors(cursors), types, out)
} else {
// build the typeset for this combination
ts := make(map[string]string)
for k, vals := range types {
ts[k] = vals[cursors[k]]
}
out <- ts
}
cursors[key]++
}
}
func copycursors(source map[string]int) map[string]int {
copy := make(map[string]int)
for k, v := range source {
copy[k] = v
}
return copy
}
-74
View File
@@ -1,74 +0,0 @@
package parse_test
import (
"testing"
"github.com/cheekybits/genny/parse"
"github.com/stretchr/testify/assert"
)
func TestArgsToTypeset(t *testing.T) {
args := "Person=man,woman Animal=dog,cat Place=london,paris"
ts, err := parse.TypeSet(args)
if assert.NoError(t, err) {
if assert.Equal(t, 8, len(ts)) {
assert.Equal(t, ts[0]["Person"], "man")
assert.Equal(t, ts[0]["Animal"], "dog")
assert.Equal(t, ts[0]["Place"], "london")
assert.Equal(t, ts[1]["Person"], "man")
assert.Equal(t, ts[1]["Animal"], "dog")
assert.Equal(t, ts[1]["Place"], "paris")
assert.Equal(t, ts[2]["Person"], "man")
assert.Equal(t, ts[2]["Animal"], "cat")
assert.Equal(t, ts[2]["Place"], "london")
assert.Equal(t, ts[3]["Person"], "man")
assert.Equal(t, ts[3]["Animal"], "cat")
assert.Equal(t, ts[3]["Place"], "paris")
assert.Equal(t, ts[4]["Person"], "woman")
assert.Equal(t, ts[4]["Animal"], "dog")
assert.Equal(t, ts[4]["Place"], "london")
assert.Equal(t, ts[5]["Person"], "woman")
assert.Equal(t, ts[5]["Animal"], "dog")
assert.Equal(t, ts[5]["Place"], "paris")
assert.Equal(t, ts[6]["Person"], "woman")
assert.Equal(t, ts[6]["Animal"], "cat")
assert.Equal(t, ts[6]["Place"], "london")
assert.Equal(t, ts[7]["Person"], "woman")
assert.Equal(t, ts[7]["Animal"], "cat")
assert.Equal(t, ts[7]["Place"], "paris")
}
}
ts, err = parse.TypeSet("Person=man Animal=dog Place=london")
if assert.NoError(t, err) {
assert.Equal(t, 1, len(ts))
}
ts, err = parse.TypeSet("Person=1,2,3,4,5 Animal=1,2,3,4,5 Place=1,2,3,4,5")
if assert.NoError(t, err) {
assert.Equal(t, 125, len(ts))
}
ts, err = parse.TypeSet("Person=1 Animal=1,2,3,4,5 Place=1,2")
if assert.NoError(t, err) {
assert.Equal(t, 10, len(ts))
}
ts, err = parse.TypeSet("Person=interface{} Animal=interface{} Place=interface{}")
if assert.NoError(t, err) {
assert.Equal(t, 1, len(ts))
assert.Equal(t, ts[0]["Animal"], "interface{}")
assert.Equal(t, ts[0]["Person"], "interface{}")
assert.Equal(t, ts[0]["Place"], "interface{}")
}
}
-9
View File
@@ -1,9 +0,0 @@
str1:
foo: bar
arr1: strval1
map1:
- abc
- def
int1: true
float1: "strval2"
bool1: 123.45
-13
View File
@@ -1,13 +0,0 @@
#!/bin/sh
cat <<EOM
str1: d3str1val1
arr1:
- d3arr1val1
- d3arr1val2
map1:
key2: d3map1val2
key3: d3map1val3
int1: 333
float1: 3.33
bool1: true
EOM
-12
View File
@@ -1,12 +0,0 @@
str1: d3str1val1
arr1:
- d3arr1val1
- d3arr1val2
- dupval
map1:
key2: d3map1val2
key3: d3map1val3
dup: d3dupval
int1: 333
float1: 3.33
bool1: true
-10
View File
@@ -1,10 +0,0 @@
str1: d3str1val1
arr1:
- d3arr1val1
- d3arr1val2
map1:
key2: d3map1val2
key3: d3map1val3
int1: 333
float1: 3.33
bool1: true
-10
View File
@@ -1,10 +0,0 @@
str1: d3str1val1
arr1:
- d3arr1val1
- d3arr1val2
map1:
key2: d3map1val2
key3: d3map1val3
int1: 333
float1: 3.33
bool1: true
-13
View File
@@ -1,13 +0,0 @@
#!/bin/sh
cat <<EOM
str1: d2str1val1
arr1:
- d2arr1val1
- d2arr1val2
map1:
key1: d2map1val1
key2: d2map1val2
int1: 222
float1: 2.22
bool1: false
EOM
-12
View File
@@ -1,12 +0,0 @@
str1: d2str1val1
arr1:
- d2arr1val1
- d2arr1val2
- dupval
map1:
key1: d2map1val1
key2: d2map1val2
dup: d2dupval
int1: 222
float1: 2.22
bool1: false
-15
View File
@@ -1,15 +0,0 @@
config:
overwrite:
- str1
- arr1
- bool1
str1: d2str1val1
arr1:
- d2arr1val1
- d2arr1val2
map1:
key1: d2map1val1
key2: d2map1val2
int1: 222
float1: 2.22
bool1: false
-12
View File
@@ -1,12 +0,0 @@
config:
stop: true
str1: d2str1val1
arr1:
- d2arr1val1
- d2arr1val2
map1:
key1: d2map1val1
key2: d2map1val2
int1: 222
float1: 2.22
bool1: false
-13
View File
@@ -1,13 +0,0 @@
#!/bin/bash
cat <<EOM
str1: d1str1val1
arr1:
- d1arr1val1
- d1arr1val2
map1:
key0: d1map1val0
key1: d1map1val1
int1: 111
float1: 1.11
bool1: true
EOM
-12
View File
@@ -1,12 +0,0 @@
str1: d1str1val1
arr1:
- d1arr1val1
- d1arr1val2
- dupval
map1:
key0: d1map1val0
key1: d1map1val1
dup: d1dupval
int1: 111
float1: 1.11
bool1: true
-15
View File
@@ -1,15 +0,0 @@
config:
overwrite:
- map1
- int1
- float1
str1: d1str1val1
arr1:
- d1arr1val1
- d1arr1val2
map1:
key0: d1map1val0
key1: d1map1val1
int1: 111
float1: 1.11
bool1: true
-10
View File
@@ -1,10 +0,0 @@
str1: d1str1val1
arr1:
- d1arr1val1
- d1arr1val2
map1:
key0: d1map1val0
key1: d1map1val1
int1: 111
float1: 1.11
bool1: true
+64 -50
View File
@@ -104,11 +104,11 @@ func (f *FigTree) LoadConfigBytes(config []byte, source string, options interfac
reflect.ValueOf(options),
reflect.ValueOf(tmp),
)
f.populateEnv(options)
if m.Config.Stop {
f.stop = true
return nil
}
f.populateEnv(options)
return nil
}
@@ -350,6 +350,60 @@ Outer:
return ov
}
func (f *FigTree) formatEnvName(name string) string {
name = fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name))
return strings.Map(func(r rune) rune {
if unicode.IsDigit(r) || unicode.IsLetter(r) {
return r
}
return '_'
}, name)
}
func (f *FigTree) formatEnvValue(value reflect.Value) (string, bool) {
switch t := value.Interface().(type) {
case string:
return t, true
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool:
return fmt.Sprintf("%v", t), true
default:
switch value.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
if value.IsNil() {
return "", false
}
}
if t == nil {
return "", false
}
type definable interface {
IsDefined() bool
}
if def, ok := t.(definable); ok {
// skip fields that are not defined
if !def.IsDefined() {
return "", false
}
}
type gettable interface {
GetValue() interface{}
}
if get, ok := t.(gettable); ok {
return fmt.Sprintf("%v", get.GetValue()), true
} else {
if b, err := json.Marshal(t); err == nil {
val := strings.TrimSpace(string(b))
if val == "null" {
return "", true
}
return val, true
}
}
}
return "", false
}
func (f *FigTree) populateEnv(data interface{}) {
options := reflect.ValueOf(data)
if options.Kind() == reflect.Ptr {
@@ -370,8 +424,11 @@ func (f *FigTree) populateEnv(data interface{}) {
}
name := strings.Join(allParts, "_")
envName := fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name))
os.Setenv(envName, fmt.Sprintf("%v", options.MapIndex(key).Interface()))
envName := f.formatEnvName(name)
val, ok := f.formatEnvValue(options.MapIndex(key))
if ok {
os.Setenv(envName, val)
}
}
}
} else if options.Kind() == reflect.Struct {
@@ -400,54 +457,11 @@ func (f *FigTree) populateEnv(data interface{}) {
}
}
envName := fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name))
envName = strings.Map(func(r rune) rune {
if unicode.IsDigit(r) || unicode.IsLetter(r) {
return r
}
return '_'
}, envName)
var val string
switch t := options.Field(i).Interface().(type) {
case string:
val = t
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool:
val = fmt.Sprintf("%v", t)
default:
switch options.Field(i).Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
if options.Field(i).IsNil() {
continue
}
}
if t == nil {
continue
}
type definable interface {
IsDefined() bool
}
if def, ok := t.(definable); ok {
// skip fields that are not defined
if !def.IsDefined() {
continue
}
}
type gettable interface {
GetValue() interface{}
}
if get, ok := t.(gettable); ok {
val = fmt.Sprintf("%v", get.GetValue())
} else {
if b, err := json.Marshal(t); err == nil {
val = strings.TrimSpace(string(b))
if val == "null" {
val = ""
}
}
}
envName := f.formatEnvName(name)
val, ok := f.formatEnvValue(options.Field(i))
if ok {
os.Setenv(envName, val)
}
os.Setenv(envName, val)
}
}
}
-30
View File
@@ -1,30 +0,0 @@
package main
import (
"fmt"
"github.com/guelfey/go.dbus"
"os"
)
func main() {
conn, err := dbus.SessionBus()
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
os.Exit(1)
}
for _, v := range []string{"method_call", "method_return", "error", "signal"} {
call := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
"eavesdrop='true',type='"+v+"'")
if call.Err != nil {
fmt.Fprintln(os.Stderr, "Failed to add match:", call.Err)
os.Exit(1)
}
}
c := make(chan *dbus.Message, 10)
conn.Eavesdrop(c)
fmt.Println("Listening for everything")
for v := range c {
fmt.Println(v)
}
}
-21
View File
@@ -1,21 +0,0 @@
package main
import (
"encoding/json"
"github.com/guelfey/go.dbus"
"github.com/guelfey/go.dbus/introspect"
"os"
)
func main() {
conn, err := dbus.SessionBus()
if err != nil {
panic(err)
}
node, err := introspect.Call(conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus"))
if err != nil {
panic(err)
}
data, _ := json.MarshalIndent(node, "", " ")
os.Stdout.Write(data)
}
-27
View File
@@ -1,27 +0,0 @@
package main
import (
"fmt"
"github.com/guelfey/go.dbus"
"os"
)
func main() {
conn, err := dbus.SessionBus()
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
os.Exit(1)
}
var s []string
err = conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&s)
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to get list of owned names:", err)
os.Exit(1)
}
fmt.Println("Currently owned names on the session bus:")
for _, v := range s {
fmt.Println(v)
}
}
-17
View File
@@ -1,17 +0,0 @@
package main
import "github.com/guelfey/go.dbus"
func main() {
conn, err := dbus.SessionBus()
if err != nil {
panic(err)
}
obj := conn.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
call := obj.Call("org.freedesktop.Notifications.Notify", 0, "", uint32(0),
"", "Test", "This is a test of the DBus bindings for go.", []string{},
map[string]dbus.Variant{}, int32(5000))
if call.Err != nil {
panic(call.Err)
}
}
-68
View File
@@ -1,68 +0,0 @@
package main
import (
"fmt"
"github.com/guelfey/go.dbus"
"github.com/guelfey/go.dbus/introspect"
"github.com/guelfey/go.dbus/prop"
"os"
)
type foo string
func (f foo) Foo() (string, *dbus.Error) {
fmt.Println(f)
return string(f), nil
}
func main() {
conn, err := dbus.SessionBus()
if err != nil {
panic(err)
}
reply, err := conn.RequestName("com.github.guelfey.Demo",
dbus.NameFlagDoNotQueue)
if err != nil {
panic(err)
}
if reply != dbus.RequestNameReplyPrimaryOwner {
fmt.Fprintln(os.Stderr, "name already taken")
os.Exit(1)
}
propsSpec := map[string]map[string]*prop.Prop{
"com.github.guelfey.Demo": {
"SomeInt": {
int32(0),
true,
prop.EmitTrue,
func(c *prop.Change) *dbus.Error {
fmt.Println(c.Name, "changed to", c.Value)
return nil
},
},
},
}
f := foo("Bar")
conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
props := prop.New(conn, "/com/github/guelfey/Demo", propsSpec)
n := &introspect.Node{
Name: "/com/github/guelfey/Demo",
Interfaces: []introspect.Interface{
introspect.IntrospectData,
prop.IntrospectData,
{
Name: "com.github.guelfey.Demo",
Methods: introspect.Methods(f),
Properties: props.Introspection("com.github.guelfey.Demo"),
},
},
}
conn.Export(introspect.NewIntrospectable(n), "/com/github/guelfey/Demo",
"org.freedesktop.DBus.Introspectable")
fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")
c := make(chan *dbus.Signal)
conn.Signal(c)
for _ = range c {
}
}
-45
View File
@@ -1,45 +0,0 @@
package main
import (
"fmt"
"github.com/guelfey/go.dbus"
"github.com/guelfey/go.dbus/introspect"
"os"
)
const intro = `
<node>
<interface name="com.github.guelfey.Demo">
<method name="Foo">
<arg direction="out" type="s"/>
</method>
</interface>` + introspect.IntrospectDataString + `</node> `
type foo string
func (f foo) Foo() (string, *dbus.Error) {
fmt.Println(f)
return string(f), nil
}
func main() {
conn, err := dbus.SessionBus()
if err != nil {
panic(err)
}
reply, err := conn.RequestName("com.github.guelfey.Demo",
dbus.NameFlagDoNotQueue)
if err != nil {
panic(err)
}
if reply != dbus.RequestNameReplyPrimaryOwner {
fmt.Fprintln(os.Stderr, "name already taken")
os.Exit(1)
}
f := foo("Bar!")
conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
conn.Export(introspect.Introspectable(intro), "/com/github/guelfey/Demo",
"org.freedesktop.DBus.Introspectable")
fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")
select {}
}
-24
View File
@@ -1,24 +0,0 @@
package main
import (
"fmt"
"github.com/guelfey/go.dbus"
"os"
)
func main() {
conn, err := dbus.SessionBus()
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
os.Exit(1)
}
conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
"type='signal',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',sender='org.freedesktop.DBus'")
c := make(chan *dbus.Signal, 10)
conn.Signal(c)
for v := range c {
fmt.Println(v)
}
}
-27
View File
@@ -1,27 +0,0 @@
package introspect
import (
"encoding/xml"
"github.com/guelfey/go.dbus"
"strings"
)
// Call calls org.freedesktop.Introspectable.Introspect on a remote object
// and returns the introspection data.
func Call(o *dbus.Object) (*Node, error) {
var xmldata string
var node Node
err := o.Call("org.freedesktop.DBus.Introspectable.Introspect", 0).Store(&xmldata)
if err != nil {
return nil, err
}
err = xml.NewDecoder(strings.NewReader(xmldata)).Decode(&node)
if err != nil {
return nil, err
}
if node.Name == "" {
node.Name = string(o.Path())
}
return &node, nil
}
-80
View File
@@ -1,80 +0,0 @@
// Package introspect provides some utilities for dealing with the DBus
// introspection format.
package introspect
import "encoding/xml"
// The introspection data for the org.freedesktop.DBus.Introspectable interface.
var IntrospectData = Interface{
Name: "org.freedesktop.DBus.Introspectable",
Methods: []Method{
{
Name: "Introspect",
Args: []Arg{
{"out", "s", "out"},
},
},
},
}
// The introspection data for the org.freedesktop.DBus.Introspectable interface,
// as a string.
const IntrospectDataString = `
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="out" direction="out" type="s"/>
</method>
</interface>
`
// Node is the root element of an introspection.
type Node struct {
XMLName xml.Name `xml:"node"`
Name string `xml:"name,attr,omitempty"`
Interfaces []Interface `xml:"interface"`
Children []Node `xml:"node,omitempty"`
}
// Interface describes a DBus interface that is available on the message bus.
type Interface struct {
Name string `xml:"name,attr"`
Methods []Method `xml:"method"`
Signals []Signal `xml:"signal"`
Properties []Property `xml:"property"`
Annotations []Annotation `xml:"annotation"`
}
// Method describes a Method on an Interface as retured by an introspection.
type Method struct {
Name string `xml:"name,attr"`
Args []Arg `xml:"arg"`
Annotations []Annotation `xml:"annotation"`
}
// Signal describes a Signal emitted on an Interface.
type Signal struct {
Name string `xml:"name,attr"`
Args []Arg `xml:"arg"`
Annotations []Annotation `xml:"annotation"`
}
// Property describes a property of an Interface.
type Property struct {
Name string `xml:"name,attr"`
Type string `xml:"type,attr"`
Access string `xml:"access,attr"`
Annotations []Annotation `xml:"annotation"`
}
// Arg represents an argument of a method or a signal.
type Arg struct {
Name string `xml:"name,attr,omitempty"`
Type string `xml:"type,attr"`
Direction string `xml:"direction,attr,omitempty"`
}
// Annotation is an annotation in the introspection format.
type Annotation struct {
Name string `xml:"name,attr"`
Value string `xml:"value,attr"`
}
-74
View File
@@ -1,74 +0,0 @@
package introspect
import (
"encoding/xml"
"github.com/guelfey/go.dbus"
"reflect"
)
// Introspectable implements org.freedesktop.Introspectable.
//
// You can create it by converting the XML-formatted introspection data from a
// string to an Introspectable or call NewIntrospectable with a Node. Then,
// export it as org.freedesktop.Introspectable on you object.
type Introspectable string
// NewIntrospectable returns an Introspectable that returns the introspection
// data that corresponds to the given Node. If n.Interfaces doesn't contain the
// data for org.freedesktop.DBus.Introspectable, it is added automatically.
func NewIntrospectable(n *Node) Introspectable {
found := false
for _, v := range n.Interfaces {
if v.Name == "org.freedesktop.DBus.Introspectable" {
found = true
break
}
}
if !found {
n.Interfaces = append(n.Interfaces, IntrospectData)
}
b, err := xml.Marshal(n)
if err != nil {
panic(err)
}
return Introspectable(b)
}
// Introspect implements org.freedesktop.Introspectable.Introspect.
func (i Introspectable) Introspect() (string, *dbus.Error) {
return string(i), nil
}
// Methods returns the description of the methods of v. This can be used to
// create a Node which can be passed to NewIntrospectable.
func Methods(v interface{}) []Method {
t := reflect.TypeOf(v)
ms := make([]Method, 0, t.NumMethod())
for i := 0; i < t.NumMethod(); i++ {
if t.Method(i).PkgPath != "" {
continue
}
mt := t.Method(i).Type
if mt.NumOut() == 0 ||
mt.Out(mt.NumOut()-1) != reflect.TypeOf(&dbus.Error{"", nil}) {
continue
}
var m Method
m.Name = t.Method(i).Name
m.Args = make([]Arg, 0, mt.NumIn()+mt.NumOut()-2)
for j := 1; j < mt.NumIn(); j++ {
if mt.In(j) != reflect.TypeOf((*dbus.Sender)(nil)).Elem() {
arg := Arg{"", dbus.SignatureOfType(mt.In(j)).String(), "in"}
m.Args = append(m.Args, arg)
}
}
for j := 0; j < mt.NumOut()-1; j++ {
arg := Arg{"", dbus.SignatureOfType(mt.Out(j)).String(), "out"}
m.Args = append(m.Args, arg)
}
m.Annotations = make([]Annotation, 0)
ms = append(ms, m)
}
return ms
}
-264
View File
@@ -1,264 +0,0 @@
// Package prop provides the Properties struct which can be used to implement
// org.freedesktop.DBus.Properties.
package prop
import (
"github.com/guelfey/go.dbus"
"github.com/guelfey/go.dbus/introspect"
"sync"
)
// EmitType controls how org.freedesktop.DBus.Properties.PropertiesChanged is
// emitted for a property. If it is EmitTrue, the signal is emitted. If it is
// EmitInvalidates, the signal is also emitted, but the new value of the property
// is not disclosed.
type EmitType byte
const (
EmitFalse EmitType = iota
EmitTrue
EmitInvalidates
)
// ErrIfaceNotFound is the error returned to peers who try to access properties
// on interfaces that aren't found.
var ErrIfaceNotFound = &dbus.Error{"org.freedesktop.DBus.Properties.Error.InterfaceNotFound", nil}
// ErrPropNotFound is the error returned to peers trying to access properties
// that aren't found.
var ErrPropNotFound = &dbus.Error{"org.freedesktop.DBus.Properties.Error.PropertyNotFound", nil}
// ErrReadOnly is the error returned to peers trying to set a read-only
// property.
var ErrReadOnly = &dbus.Error{"org.freedesktop.DBus.Properties.Error.ReadOnly", nil}
// ErrInvalidArg is returned to peers if the type of the property that is being
// changed and the argument don't match.
var ErrInvalidArg = &dbus.Error{"org.freedesktop.DBus.Properties.Error.InvalidArg", nil}
// The introspection data for the org.freedesktop.DBus.Properties interface.
var IntrospectData = introspect.Interface{
Name: "org.freedesktop.DBus.Properties",
Methods: []introspect.Method{
{
Name: "Get",
Args: []introspect.Arg{
{"interface", "s", "in"},
{"property", "s", "in"},
{"value", "v", "out"},
},
},
{
Name: "GetAll",
Args: []introspect.Arg{
{"interface", "s", "in"},
{"props", "a{sv}", "out"},
},
},
{
Name: "Set",
Args: []introspect.Arg{
{"interface", "s", "in"},
{"property", "s", "in"},
{"value", "v", "in"},
},
},
},
Signals: []introspect.Signal{
{
Name: "PropertiesChanged",
Args: []introspect.Arg{
{"interface", "s", "out"},
{"changed_properties", "a{sv}", "out"},
{"invalidates_properties", "as", "out"},
},
},
},
}
// The introspection data for the org.freedesktop.DBus.Properties interface, as
// a string.
const IntrospectDataString = `
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Get">
<arg name="interface" direction="in" type="s"/>
<arg name="property" direction="in" type="s"/>
<arg name="value" direction="out" type="v"/>
</method>
<method name="GetAll">
<arg name="interface" direction="in" type="s"/>
<arg name="props" direction="out" type="a{sv}"/>
</method>
<method name="Set">
<arg name="interface" direction="in" type="s"/>
<arg name="property" direction="in" type="s"/>
<arg name="value" direction="in" type="v"/>
</method>
<signal name="PropertiesChanged">
<arg name="interface" type="s"/>
<arg name="changed_properties" type="a{sv}"/>
<arg name="invalidates_properties" type="as"/>
</signal>
</interface>
`
// Prop represents a single property. It is used for creating a Properties
// value.
type Prop struct {
// Initial value. Must be a DBus-representable type.
Value interface{}
// If true, the value can be modified by calls to Set.
Writable bool
// Controls how org.freedesktop.DBus.Properties.PropertiesChanged is
// emitted if this property changes.
Emit EmitType
// If not nil, anytime this property is changed by Set, this function is
// called with an appropiate Change as its argument. If the returned error
// is not nil, it is sent back to the caller of Set and the property is not
// changed.
Callback func(*Change) *dbus.Error
}
// Change represents a change of a property by a call to Set.
type Change struct {
Props *Properties
Iface string
Name string
Value interface{}
}
// Properties is a set of values that can be made available to the message bus
// using the org.freedesktop.DBus.Properties interface. It is safe for
// concurrent use by multiple goroutines.
type Properties struct {
m map[string]map[string]*Prop
mut sync.RWMutex
conn *dbus.Conn
path dbus.ObjectPath
}
// New returns a new Properties structure that manages the given properties.
// The key for the first-level map of props is the name of the interface; the
// second-level key is the name of the property. The returned structure will be
// exported as org.freedesktop.DBus.Properties on path.
func New(conn *dbus.Conn, path dbus.ObjectPath, props map[string]map[string]*Prop) *Properties {
p := &Properties{m: props, conn: conn, path: path}
conn.Export(p, path, "org.freedesktop.DBus.Properties")
return p
}
// Get implements org.freedesktop.DBus.Properties.Get.
func (p *Properties) Get(iface, property string) (dbus.Variant, *dbus.Error) {
p.mut.RLock()
defer p.mut.RUnlock()
m, ok := p.m[iface]
if !ok {
return dbus.Variant{}, ErrIfaceNotFound
}
prop, ok := m[property]
if !ok {
return dbus.Variant{}, ErrPropNotFound
}
return dbus.MakeVariant(prop.Value), nil
}
// GetAll implements org.freedesktop.DBus.Properties.GetAll.
func (p *Properties) GetAll(iface string) (map[string]dbus.Variant, *dbus.Error) {
p.mut.RLock()
defer p.mut.RUnlock()
m, ok := p.m[iface]
if !ok {
return nil, ErrIfaceNotFound
}
rm := make(map[string]dbus.Variant, len(m))
for k, v := range m {
rm[k] = dbus.MakeVariant(v.Value)
}
return rm, nil
}
// GetMust returns the value of the given property and panics if either the
// interface or the property name are invalid.
func (p *Properties) GetMust(iface, property string) interface{} {
p.mut.RLock()
defer p.mut.RUnlock()
return p.m[iface][property].Value
}
// Introspection returns the introspection data that represents the properties
// of iface.
func (p *Properties) Introspection(iface string) []introspect.Property {
p.mut.RLock()
defer p.mut.RUnlock()
m := p.m[iface]
s := make([]introspect.Property, 0, len(m))
for k, v := range m {
p := introspect.Property{Name: k, Type: dbus.SignatureOf(v.Value).String()}
if v.Writable {
p.Access = "readwrite"
} else {
p.Access = "read"
}
s = append(s, p)
}
return s
}
// set sets the given property and emits PropertyChanged if appropiate. p.mut
// must already be locked.
func (p *Properties) set(iface, property string, v interface{}) {
prop := p.m[iface][property]
prop.Value = v
switch prop.Emit {
case EmitFalse:
// do nothing
case EmitInvalidates:
p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
iface, map[string]dbus.Variant{}, []string{property})
case EmitTrue:
p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
iface, map[string]dbus.Variant{property: dbus.MakeVariant(v)},
[]string{})
default:
panic("invalid value for EmitType")
}
}
// Set implements org.freedesktop.Properties.Set.
func (p *Properties) Set(iface, property string, newv dbus.Variant) *dbus.Error {
p.mut.Lock()
defer p.mut.Unlock()
m, ok := p.m[iface]
if !ok {
return ErrIfaceNotFound
}
prop, ok := m[property]
if !ok {
return ErrPropNotFound
}
if !prop.Writable {
return ErrReadOnly
}
if newv.Signature() != dbus.SignatureOf(prop.Value) {
return ErrInvalidArg
}
if prop.Callback != nil {
err := prop.Callback(&Change{p, iface, property, newv.Value()})
if err != nil {
return err
}
}
p.set(iface, property, newv.Value())
return nil
}
// SetMust sets the value of the given property and panics if the interface or
// the property name are invalid.
func (p *Properties) SetMust(iface, property string, v interface{}) {
p.mut.Lock()
p.set(iface, property, v)
p.mut.Unlock()
}
-16
View File
@@ -1,16 +0,0 @@
package main
import (
"bufio"
"fmt"
"github.com/mattn/go-colorable"
)
func main() {
stdOut := bufio.NewWriter(colorable.NewColorableStdout())
fmt.Fprint(stdOut, "\x1B[3GMove to 3rd Column\n")
fmt.Fprint(stdOut, "\x1B[1;2HMove to 2nd Column on 1st Line\n")
stdOut.Flush()
}
-16
View File
@@ -1,16 +0,0 @@
package main
import (
"github.com/mattn/go-colorable"
"github.com/sirupsen/logrus"
)
func main() {
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
logrus.SetOutput(colorable.NewColorableStdout())
logrus.Info("succeeded")
logrus.Warn("not correct")
logrus.Error("something error")
logrus.Fatal("panic")
}
-14
View File
@@ -1,14 +0,0 @@
package main
import (
"fmt"
"os"
. "github.com/mattn/go-colorable"
)
func main() {
out := NewColorableStdout()
fmt.Fprint(out, "\x1B]0;TITLE Changed\007(See title and hit any key)")
var c [1]byte
os.Stdin.Read(c[:])
}
-12
View File
@@ -1,12 +0,0 @@
package main
import (
"io"
"os"
"github.com/mattn/go-colorable"
)
func main() {
io.Copy(colorable.NewColorableStdout(), os.Stdin)
}
-135
View File
@@ -1,135 +0,0 @@
package main
import (
"fmt"
"sort"
"strconv"
"github.com/mattn/go-colorable"
"github.com/mgutz/ansi"
)
func main() {
printColors()
print256Colors()
printConstants()
}
func pad(s string, length int) string {
for len(s) < length {
s += " "
}
return s
}
func padColor(s string, styles []string) string {
buffer := ""
for _, style := range styles {
buffer += ansi.Color(pad(s+style, 20), s+style)
}
return buffer
}
func printPlain() {
ansi.DisableColors(true)
bgColors := []string{
"",
":black",
":red",
":green",
":yellow",
":blue",
":magenta",
":cyan",
":white",
}
for fg := range ansi.Colors {
for _, bg := range bgColors {
println(padColor(fg, []string{"" + bg, "+b" + bg, "+bh" + bg, "+u" + bg}))
println(padColor(fg, []string{"+uh" + bg, "+B" + bg, "+Bb" + bg /* backgrounds */, "" + bg + "+h"}))
println(padColor(fg, []string{"+b" + bg + "+h", "+bh" + bg + "+h", "+u" + bg + "+h", "+uh" + bg + "+h"}))
}
}
}
func printColors() {
ansi.DisableColors(false)
stdout := colorable.NewColorableStdout()
bgColors := []string{
"",
":black",
":red",
":green",
":yellow",
":blue",
":magenta",
":cyan",
":white",
}
keys := []string{}
for fg := range ansi.Colors {
_, err := strconv.Atoi(fg)
if err != nil {
keys = append(keys, fg)
}
}
sort.Strings(keys)
for _, fg := range keys {
for _, bg := range bgColors {
fmt.Fprintln(stdout, padColor(fg, []string{"" + bg, "+b" + bg, "+bh" + bg, "+u" + bg}))
fmt.Fprintln(stdout, padColor(fg, []string{"+uh" + bg, "+B" + bg, "+Bb" + bg /* backgrounds */, "" + bg + "+h", "+s" + bg}))
fmt.Fprintln(stdout, padColor(fg, []string{"+b" + bg + "+h", "+bh" + bg + "+h", "+u" + bg + "+h", "+uh" + bg + "+h"}))
}
}
}
func print256Colors() {
ansi.DisableColors(false)
stdout := colorable.NewColorableStdout()
bgColors := []string{""}
for i := 0; i < 256; i++ {
key := fmt.Sprintf(":%d", i)
bgColors = append(bgColors, key)
}
keys := []string{}
for fg := range ansi.Colors {
n, err := strconv.Atoi(fg)
if err == nil {
keys = append(keys, fmt.Sprintf("%3d", n))
}
}
sort.Strings(keys)
for _, fg := range keys {
for _, bg := range bgColors {
fmt.Fprintln(stdout, padColor(fg, []string{"" + bg, "+b" + bg, "+u" + bg}))
fmt.Fprintln(stdout, padColor(fg, []string{"+B" + bg, "+Bb" + bg, "+s" + bg}))
}
}
}
func printConstants() {
stdout := colorable.NewColorableStdout()
fmt.Fprintln(stdout, ansi.DefaultFG, "ansi.DefaultFG", ansi.Reset)
fmt.Fprintln(stdout, ansi.Black, "ansi.Black", ansi.Reset)
fmt.Fprintln(stdout, ansi.Red, "ansi.Red", ansi.Reset)
fmt.Fprintln(stdout, ansi.Green, "ansi.Green", ansi.Reset)
fmt.Fprintln(stdout, ansi.Yellow, "ansi.Yellow", ansi.Reset)
fmt.Fprintln(stdout, ansi.Blue, "ansi.Blue", ansi.Reset)
fmt.Fprintln(stdout, ansi.Magenta, "ansi.Magenta", ansi.Reset)
fmt.Fprintln(stdout, ansi.Cyan, "ansi.Cyan", ansi.Reset)
fmt.Fprintln(stdout, ansi.White, "ansi.White", ansi.Reset)
fmt.Fprintln(stdout, ansi.LightBlack, "ansi.LightBlack", ansi.Reset)
fmt.Fprintln(stdout, ansi.LightRed, "ansi.LightRed", ansi.Reset)
fmt.Fprintln(stdout, ansi.LightGreen, "ansi.LightGreen", ansi.Reset)
fmt.Fprintln(stdout, ansi.LightYellow, "ansi.LightYellow", ansi.Reset)
fmt.Fprintln(stdout, ansi.LightBlue, "ansi.LightBlue", ansi.Reset)
fmt.Fprintln(stdout, ansi.LightMagenta, "ansi.LightMagenta", ansi.Reset)
fmt.Fprintln(stdout, ansi.LightCyan, "ansi.LightCyan", ansi.Reset)
fmt.Fprintln(stdout, ansi.LightWhite, "ansi.LightWhite", ansi.Reset)
}
-50
View File
@@ -1,50 +0,0 @@
// Open is a simple example of the github.com/pkg/browser package.
//
// Usage:
//
// # Open a file in a browser window
// Open $FILE
//
// # Open a URL in a browser window
// Open $URL
//
// # Open the contents of stdin in a browser window
// cat $SOMEFILE | Open
package main
import (
"flag"
"fmt"
"log"
"os"
"github.com/pkg/browser"
)
func usage() {
fmt.Fprintf(os.Stderr, "Usage:\n %s [file]\n", os.Args[0])
flag.PrintDefaults()
}
func init() {
flag.Usage = usage
flag.Parse()
}
func check(err error) {
if err != nil {
log.Fatal(err)
}
}
func main() {
args := flag.Args()
switch len(args) {
case 0:
check(browser.OpenReader(os.Stdin))
case 1:
check(browser.OpenFile(args[0]))
default:
usage()
}
}
-27
View File
@@ -1,27 +0,0 @@
# Timing Tests
It was noted in [issue #2](github.com/sethgrid/pester/issue/2) that Pester may be slower than the standard library (along with bug that was fixed).
I put together a quick test to see how Pester fairs against the stand library. Here are the results:
```
$ go test
Standard Library Get 675178 ns Avg.
Pester, Default 690157 ns Avg.
Pester, Retries 1, Conc 1 671322 ns Avg.
Pester, Retries 2, Conc 2 764386 ns Avg.
Pester, Retries 3, Conc 3 893899 ns Avg.
Pester, Retries 0, Conc 1 730407 ns Avg.
Pester, Retries 0, Conc 2 1077721 ns Avg.
Pester, Retries 0, Conc 3 1889403 ns Avg.
Pester, Retries 0, Conc 1 1758464 ns Avg.
Pester, Retries 2, Conc 1 1249081 ns Avg.
Pester, Retries 3, Conc 1 1824322 ns Avg.
PASS
```
Running the test locally multiple times shows some variance, but this is a typical result. In raw time, these average times are not far off from each other (about 1ms from the best to worst case). In comparisons between percents, we see a drift of up to 3x.
The up to 3x drift between the near identical default Pester implementation and the Standard Library http.Get call compared to the last test case of 'Retries 3, Conc 1' makes little sense in that the default Pester uses 'Retries 3, Conc 1' as its settings.
I think that it is safe to say that there is no material difference in speed between the Standard Library and Pester.

Some files were not shown because too many files have changed in this diff Show More