diff --git a/vendor/github.com/c4milo/gotoolkit/LICENSE b/vendor/github.com/c4milo/gotoolkit/LICENSE new file mode 100644 index 0000000..52d1351 --- /dev/null +++ b/vendor/github.com/c4milo/gotoolkit/LICENSE @@ -0,0 +1,374 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/c4milo/gotoolkit/queue.go b/vendor/github.com/c4milo/gotoolkit/queue.go new file mode 100644 index 0000000..6caf125 --- /dev/null +++ b/vendor/github.com/c4milo/gotoolkit/queue.go @@ -0,0 +1,114 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package gotoolkit + +import "errors" + +// Queue defines an interface for implementing Queue data structures. +type Queue interface { + Enqueue(item interface{}) + Dequeue() (interface{}, error) + Peek() (interface{}, error) + IsEmpty() bool + Size() uint64 +} + +// ListQueue implements a queue backed by a linked list, it may be faster than SliceQueue +// but consumes more memory and has worse cache locality than SliceQueue +type ListQueue struct { + first *node + last *node + size uint64 +} + +// Enqueue adds an element to the end of the queue. +func (q *ListQueue) Enqueue(item interface{}) { + last := new(node) + last.item = item + + if q.IsEmpty() { + q.first = last + } else { + oldLast := q.last + oldLast.next = last + } + q.last = last + q.size++ +} + +// Dequeue removes the first element from the queue. +func (q *ListQueue) Dequeue() (interface{}, error) { + if q.IsEmpty() { + q.last = nil + return nil, errors.New("unable to dequeue element, queue is empty") + } + + item := q.first.item + q.first = q.first.next + q.size-- + return item, nil +} + +// Peek returns the first element in the queue without removing it. +func (q *ListQueue) Peek() (interface{}, error) { + if q.IsEmpty() { + return nil, errors.New("unable to peek element, queue is empty") + } + return q.first.item, nil +} + +// IsEmpty returns whether the queue is empty or not. +func (q *ListQueue) IsEmpty() bool { + return q.first == nil +} + +// Size returns the number of elements in the queue. +func (q *ListQueue) Size() uint64 { + return q.size +} + +// SliceQueue implements a queue backed by a growing slice. Useful for memory +// constrained environments. It also has better cache locality than ListQueue +type SliceQueue struct { + size uint64 + backing []interface{} +} + +// Enqueue adds an element to the end of the queue. +func (s *SliceQueue) Enqueue(item interface{}) { + s.size++ + s.backing = append(s.backing, item) +} + +// Peek returns the first element of the queue without removing it from the queue. +func (s *SliceQueue) Peek() (interface{}, error) { + if s.IsEmpty() { + return nil, errors.New("unable to peek element, queue is empty") + } + return s.backing[0], nil +} + +// Dequeue removes and return the first element from the queue. +func (s *SliceQueue) Dequeue() (interface{}, error) { + if s.IsEmpty() { + return nil, errors.New("unable to dequeue element, queue is empty") + } + + item := s.backing[0] + // https://github.com/golang/go/wiki/SliceTricks + s.backing = append(s.backing[:0], s.backing[1:]...) + s.size-- + return item, nil +} + +// IsEmpty returns whether or not the queue is empty. +func (s *SliceQueue) IsEmpty() bool { + return len(s.backing) == 0 +} + +// Size returns the number of elements in the queue. +func (s *SliceQueue) Size() uint64 { + return s.size +} diff --git a/vendor/github.com/c4milo/gotoolkit/stack.go b/vendor/github.com/c4milo/gotoolkit/stack.go new file mode 100644 index 0000000..8314cb3 --- /dev/null +++ b/vendor/github.com/c4milo/gotoolkit/stack.go @@ -0,0 +1,110 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package gotoolkit + +import "errors" + +// Stack defines an interface for implementing Stack data structures. +type Stack interface { + Push(item interface{}) + Pop() (interface{}, error) + Peek() (interface{}, error) + IsEmpty() bool + Size() uint64 +} + +type node struct { + item interface{} + next *node +} + +// ListStack is a stack backed by a linked list, it may be faster than SliceStack +// but consumes more memory and has worse cache locality than SliceQueue. +type ListStack struct { + first *node + size uint64 +} + +// Push adds an element to the top of the stack. +func (s *ListStack) Push(item interface{}) { + oldFirst := s.first + s.first = new(node) + s.first.item = item + s.first.next = oldFirst + s.size++ +} + +// Peek returns the latest added element without removing it from the stack. +func (s *ListStack) Peek() (interface{}, error) { + if s.IsEmpty() { + return nil, errors.New("unable to peek element, stack is empty") + } + + return s.first.item, nil +} + +// Pop removes and return the latest added element from the stack. +func (s *ListStack) Pop() (interface{}, error) { + if s.IsEmpty() { + return nil, errors.New("unable to pop element, stack is empty") + } + item := s.first.item + s.first = s.first.next + s.size-- + return item, nil +} + +// IsEmpty returns whether or not the stack is empty. +func (s *ListStack) IsEmpty() bool { + return s.first == nil +} + +// Size returns the number of elements in the stack. +func (s *ListStack) Size() uint64 { + return s.size +} + +// SliceStack implements a stack backed by a growing slice. Useful for memory +// constrained environments. It also has better cache locality. +type SliceStack struct { + size uint64 + backing []interface{} +} + +// Push adds an element to the top of the stack. +func (s *SliceStack) Push(item interface{}) { + s.size++ + s.backing = append(s.backing, item) +} + +// Peek returns the latest added element without removing it from the stack. +func (s *SliceStack) Peek() (interface{}, error) { + if s.IsEmpty() { + return nil, errors.New("unable to peek element, stack is empty") + } + return s.backing[s.size-1], nil +} + +// Pop removes and return the latest added element from the stack. +func (s *SliceStack) Pop() (interface{}, error) { + if s.IsEmpty() { + return nil, errors.New("unable to pop element, stack is empty") + } + + s.size-- + item := s.backing[s.size] + s.backing = s.backing[0:s.size] + return item, nil +} + +// IsEmpty returns whether or not the stack is empty. +func (s *SliceStack) IsEmpty() bool { + return len(s.backing) == 0 +} + +// Size returns the number of elements in the stack. +func (s *SliceStack) Size() uint64 { + return s.size +} diff --git a/vendor/github.com/docopt/docopt-go/LICENSE b/vendor/github.com/docopt/docopt-go/LICENSE new file mode 100644 index 0000000..8841af1 --- /dev/null +++ b/vendor/github.com/docopt/docopt-go/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Keith Batten + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/docopt/docopt-go/docopt.go b/vendor/github.com/docopt/docopt-go/docopt.go new file mode 100644 index 0000000..d929fc3 --- /dev/null +++ b/vendor/github.com/docopt/docopt-go/docopt.go @@ -0,0 +1,1239 @@ +// Licensed under terms of MIT license (see LICENSE-MIT) +// Copyright (c) 2013 Keith Batten, kbatten@gmail.com + +/* +Package docopt parses command-line arguments based on a help message. + +⚠ Use the alias “docopt-go”: + import "github.com/docopt/docopt-go" +or + $ go get github.com/docopt/docopt-go +*/ +package docopt + +import ( + "fmt" + "os" + "reflect" + "regexp" + "strings" + "unicode" +) + +/* +Parse `argv` based on the command-line interface described in `doc`. + +Given a conventional command-line help message, docopt creates a parser and +processes the arguments. See +https://github.com/docopt/docopt#help-message-format for a description of the +help message format. If `argv` is `nil`, `os.Args[1:]` is used. + +docopt returns a map of option names to the values parsed from `argv`, and an +error or `nil`. + +Set `help` to `false` to disable automatic help messages on `-h` or `--help`. +If `version` is a non-empty string, it will be printed when `--version` is +specified. Set `optionsFirst` to `true` to require that options always come +before positional arguments; otherwise they can overlap. + +By default, docopt calls `os.Exit(0)` if it handled a built-in option such as +`-h` or `--version`. If the user errored with a wrong command or options, +docopt exits with a return code of 1. To stop docopt from calling `os.Exit()` +and to handle your own return codes, pass an optional last parameter of `false` +for `exit`. +*/ +func Parse(doc string, argv []string, help bool, version string, + optionsFirst bool, exit ...bool) (map[string]interface{}, error) { + // if "false" was the (optional) last arg, don't call os.Exit() + exitOk := true + if len(exit) > 0 { + exitOk = exit[0] + } + args, output, err := parse(doc, argv, help, version, optionsFirst) + if _, ok := err.(*UserError); ok { + // the user gave us bad input + fmt.Fprintln(os.Stderr, output) + if exitOk { + os.Exit(1) + } + } else if len(output) > 0 && err == nil { + // the user asked for help or `--version` + fmt.Println(output) + if exitOk { + os.Exit(0) + } + } + return args, err +} + +// parse and return a map of args, output and all errors +func parse(doc string, argv []string, help bool, version string, optionsFirst bool) (args map[string]interface{}, output string, err error) { + if argv == nil && len(os.Args) > 1 { + argv = os.Args[1:] + } + + usageSections := parseSection("usage:", doc) + + if len(usageSections) == 0 { + err = newLanguageError("\"usage:\" (case-insensitive) not found.") + return + } + if len(usageSections) > 1 { + err = newLanguageError("More than one \"usage:\" (case-insensitive).") + return + } + usage := usageSections[0] + + options := parseDefaults(doc) + formal, err := formalUsage(usage) + if err != nil { + output = handleError(err, usage) + return + } + + pat, err := parsePattern(formal, &options) + if err != nil { + output = handleError(err, usage) + return + } + + patternArgv, err := parseArgv(newTokenList(argv, errorUser), &options, optionsFirst) + if err != nil { + output = handleError(err, usage) + return + } + patFlat, err := pat.flat(patternOption) + if err != nil { + output = handleError(err, usage) + return + } + patternOptions := patFlat.unique() + + patFlat, err = pat.flat(patternOptionSSHORTCUT) + if err != nil { + output = handleError(err, usage) + return + } + for _, optionsShortcut := range patFlat { + docOptions := parseDefaults(doc) + optionsShortcut.children = docOptions.unique().diff(patternOptions) + } + + if output = extras(help, version, patternArgv, doc); len(output) > 0 { + return + } + + err = pat.fix() + if err != nil { + output = handleError(err, usage) + return + } + matched, left, collected := pat.match(&patternArgv, nil) + if matched && len(*left) == 0 { + patFlat, err = pat.flat(patternDefault) + if err != nil { + output = handleError(err, usage) + return + } + args = append(patFlat, *collected...).dictionary() + return + } + + err = newUserError("") + output = handleError(err, usage) + return +} + +func handleError(err error, usage string) string { + if _, ok := err.(*UserError); ok { + return strings.TrimSpace(fmt.Sprintf("%s\n%s", err, usage)) + } + return "" +} + +func parseSection(name, source string) []string { + p := regexp.MustCompile(`(?im)^([^\n]*` + name + `[^\n]*\n?(?:[ \t].*?(?:\n|$))*)`) + s := p.FindAllString(source, -1) + if s == nil { + s = []string{} + } + for i, v := range s { + s[i] = strings.TrimSpace(v) + } + return s +} + +func parseDefaults(doc string) patternList { + defaults := patternList{} + p := regexp.MustCompile(`\n[ \t]*(-\S+?)`) + for _, s := range parseSection("options:", doc) { + // FIXME corner case "bla: options: --foo" + _, _, s = stringPartition(s, ":") // get rid of "options:" + split := p.Split("\n"+s, -1)[1:] + match := p.FindAllStringSubmatch("\n"+s, -1) + for i := range split { + optionDescription := match[i][1] + split[i] + if strings.HasPrefix(optionDescription, "-") { + defaults = append(defaults, parseOption(optionDescription)) + } + } + } + return defaults +} + +func parsePattern(source string, options *patternList) (*pattern, error) { + tokens := tokenListFromPattern(source) + result, err := parseExpr(tokens, options) + if err != nil { + return nil, err + } + if tokens.current() != nil { + return nil, tokens.errorFunc("unexpected ending: %s" + strings.Join(tokens.tokens, " ")) + } + return newRequired(result...), nil +} + +func parseArgv(tokens *tokenList, options *patternList, optionsFirst bool) (patternList, error) { + /* + Parse command-line argument vector. + + If options_first: + argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ; + else: + argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ; + */ + parsed := patternList{} + for tokens.current() != nil { + if tokens.current().eq("--") { + for _, v := range tokens.tokens { + parsed = append(parsed, newArgument("", v)) + } + return parsed, nil + } else if tokens.current().hasPrefix("--") { + pl, err := parseLong(tokens, options) + if err != nil { + return nil, err + } + parsed = append(parsed, pl...) + } else if tokens.current().hasPrefix("-") && !tokens.current().eq("-") { + ps, err := parseShorts(tokens, options) + if err != nil { + return nil, err + } + parsed = append(parsed, ps...) + } else if optionsFirst { + for _, v := range tokens.tokens { + parsed = append(parsed, newArgument("", v)) + } + return parsed, nil + } else { + parsed = append(parsed, newArgument("", tokens.move().String())) + } + } + return parsed, nil +} + +func parseOption(optionDescription string) *pattern { + optionDescription = strings.TrimSpace(optionDescription) + options, _, description := stringPartition(optionDescription, " ") + options = strings.Replace(options, ",", " ", -1) + options = strings.Replace(options, "=", " ", -1) + + short := "" + long := "" + argcount := 0 + var value interface{} + value = false + + reDefault := regexp.MustCompile(`(?i)\[default: (.*)\]`) + for _, s := range strings.Fields(options) { + if strings.HasPrefix(s, "--") { + long = s + } else if strings.HasPrefix(s, "-") { + short = s + } else { + argcount = 1 + } + if argcount > 0 { + matched := reDefault.FindAllStringSubmatch(description, -1) + if len(matched) > 0 { + value = matched[0][1] + } else { + value = nil + } + } + } + return newOption(short, long, argcount, value) +} + +func parseExpr(tokens *tokenList, options *patternList) (patternList, error) { + // expr ::= seq ( '|' seq )* ; + seq, err := parseSeq(tokens, options) + if err != nil { + return nil, err + } + if !tokens.current().eq("|") { + return seq, nil + } + var result patternList + if len(seq) > 1 { + result = patternList{newRequired(seq...)} + } else { + result = seq + } + for tokens.current().eq("|") { + tokens.move() + seq, err = parseSeq(tokens, options) + if err != nil { + return nil, err + } + if len(seq) > 1 { + result = append(result, newRequired(seq...)) + } else { + result = append(result, seq...) + } + } + if len(result) > 1 { + return patternList{newEither(result...)}, nil + } + return result, nil +} + +func parseSeq(tokens *tokenList, options *patternList) (patternList, error) { + // seq ::= ( atom [ '...' ] )* ; + result := patternList{} + for !tokens.current().match(true, "]", ")", "|") { + atom, err := parseAtom(tokens, options) + if err != nil { + return nil, err + } + if tokens.current().eq("...") { + atom = patternList{newOneOrMore(atom...)} + tokens.move() + } + result = append(result, atom...) + } + return result, nil +} + +func parseAtom(tokens *tokenList, options *patternList) (patternList, error) { + // atom ::= '(' expr ')' | '[' expr ']' | 'options' | long | shorts | argument | command ; + tok := tokens.current() + result := patternList{} + if tokens.current().match(false, "(", "[") { + tokens.move() + var matching string + pl, err := parseExpr(tokens, options) + if err != nil { + return nil, err + } + if tok.eq("(") { + matching = ")" + result = patternList{newRequired(pl...)} + } else if tok.eq("[") { + matching = "]" + result = patternList{newOptional(pl...)} + } + moved := tokens.move() + if !moved.eq(matching) { + return nil, tokens.errorFunc("unmatched '%s', expected: '%s' got: '%s'", tok, matching, moved) + } + return result, nil + } else if tok.eq("options") { + tokens.move() + return patternList{newOptionsShortcut()}, nil + } else if tok.hasPrefix("--") && !tok.eq("--") { + return parseLong(tokens, options) + } else if tok.hasPrefix("-") && !tok.eq("-") && !tok.eq("--") { + return parseShorts(tokens, options) + } else if tok.hasPrefix("<") && tok.hasSuffix(">") || tok.isUpper() { + return patternList{newArgument(tokens.move().String(), nil)}, nil + } + return patternList{newCommand(tokens.move().String(), false)}, nil +} + +func parseLong(tokens *tokenList, options *patternList) (patternList, error) { + // long ::= '--' chars [ ( ' ' | '=' ) chars ] ; + long, eq, v := stringPartition(tokens.move().String(), "=") + var value interface{} + var opt *pattern + if eq == "" && v == "" { + value = nil + } else { + value = v + } + + if !strings.HasPrefix(long, "--") { + return nil, newError("long option '%s' doesn't start with --", long) + } + similar := patternList{} + for _, o := range *options { + if o.long == long { + similar = append(similar, o) + } + } + if tokens.err == errorUser && len(similar) == 0 { // if no exact match + similar = patternList{} + for _, o := range *options { + if strings.HasPrefix(o.long, long) { + similar = append(similar, o) + } + } + } + if len(similar) > 1 { // might be simply specified ambiguously 2+ times? + similarLong := make([]string, len(similar)) + for i, s := range similar { + similarLong[i] = s.long + } + return nil, tokens.errorFunc("%s is not a unique prefix: %s?", long, strings.Join(similarLong, ", ")) + } else if len(similar) < 1 { + argcount := 0 + if eq == "=" { + argcount = 1 + } + opt = newOption("", long, argcount, false) + *options = append(*options, opt) + if tokens.err == errorUser { + var val interface{} + if argcount > 0 { + val = value + } else { + val = true + } + opt = newOption("", long, argcount, val) + } + } else { + opt = newOption(similar[0].short, similar[0].long, similar[0].argcount, similar[0].value) + if opt.argcount == 0 { + if value != nil { + return nil, tokens.errorFunc("%s must not have an argument", opt.long) + } + } else { + if value == nil { + if tokens.current().match(true, "--") { + return nil, tokens.errorFunc("%s requires argument", opt.long) + } + moved := tokens.move() + if moved != nil { + value = moved.String() // only set as string if not nil + } + } + } + if tokens.err == errorUser { + if value != nil { + opt.value = value + } else { + opt.value = true + } + } + } + + return patternList{opt}, nil +} + +func parseShorts(tokens *tokenList, options *patternList) (patternList, error) { + // shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ; + tok := tokens.move() + if !tok.hasPrefix("-") || tok.hasPrefix("--") { + return nil, newError("short option '%s' doesn't start with -", tok) + } + left := strings.TrimLeft(tok.String(), "-") + parsed := patternList{} + for left != "" { + var opt *pattern + short := "-" + left[0:1] + left = left[1:] + similar := patternList{} + for _, o := range *options { + if o.short == short { + similar = append(similar, o) + } + } + if len(similar) > 1 { + return nil, tokens.errorFunc("%s is specified ambiguously %d times", short, len(similar)) + } else if len(similar) < 1 { + opt = newOption(short, "", 0, false) + *options = append(*options, opt) + if tokens.err == errorUser { + opt = newOption(short, "", 0, true) + } + } else { // why copying is necessary here? + opt = newOption(short, similar[0].long, similar[0].argcount, similar[0].value) + var value interface{} + if opt.argcount > 0 { + if left == "" { + if tokens.current().match(true, "--") { + return nil, tokens.errorFunc("%s requires argument", short) + } + value = tokens.move().String() + } else { + value = left + left = "" + } + } + if tokens.err == errorUser { + if value != nil { + opt.value = value + } else { + opt.value = true + } + } + } + parsed = append(parsed, opt) + } + return parsed, nil +} + +func newTokenList(source []string, err errorType) *tokenList { + errorFunc := newError + if err == errorUser { + errorFunc = newUserError + } else if err == errorLanguage { + errorFunc = newLanguageError + } + return &tokenList{source, errorFunc, err} +} + +func tokenListFromString(source string) *tokenList { + return newTokenList(strings.Fields(source), errorUser) +} + +func tokenListFromPattern(source string) *tokenList { + p := regexp.MustCompile(`([\[\]\(\)\|]|\.\.\.)`) + source = p.ReplaceAllString(source, ` $1 `) + p = regexp.MustCompile(`\s+|(\S*<.*?>)`) + split := p.Split(source, -1) + match := p.FindAllStringSubmatch(source, -1) + var result []string + l := len(split) + for i := 0; i < l; i++ { + if len(split[i]) > 0 { + result = append(result, split[i]) + } + if i < l-1 && len(match[i][1]) > 0 { + result = append(result, match[i][1]) + } + } + return newTokenList(result, errorLanguage) +} + +func formalUsage(section string) (string, error) { + _, _, section = stringPartition(section, ":") // drop "usage:" + pu := strings.Fields(section) + + if len(pu) == 0 { + return "", newLanguageError("no fields found in usage (perhaps a spacing error).") + } + + result := "( " + for _, s := range pu[1:] { + if s == pu[0] { + result += ") | ( " + } else { + result += s + " " + } + } + result += ")" + + return result, nil +} + +func extras(help bool, version string, options patternList, doc string) string { + if help { + for _, o := range options { + if (o.name == "-h" || o.name == "--help") && o.value == true { + return strings.Trim(doc, "\n") + } + } + } + if version != "" { + for _, o := range options { + if (o.name == "--version") && o.value == true { + return version + } + } + } + return "" +} + +type errorType int + +const ( + errorUser errorType = iota + errorLanguage +) + +func (e errorType) String() string { + switch e { + case errorUser: + return "errorUser" + case errorLanguage: + return "errorLanguage" + } + return "" +} + +// UserError records an error with program arguments. +type UserError struct { + msg string + Usage string +} + +func (e UserError) Error() string { + return e.msg +} +func newUserError(msg string, f ...interface{}) error { + return &UserError{fmt.Sprintf(msg, f...), ""} +} + +// LanguageError records an error with the doc string. +type LanguageError struct { + msg string +} + +func (e LanguageError) Error() string { + return e.msg +} +func newLanguageError(msg string, f ...interface{}) error { + return &LanguageError{fmt.Sprintf(msg, f...)} +} + +var newError = fmt.Errorf + +type tokenList struct { + tokens []string + errorFunc func(string, ...interface{}) error + err errorType +} +type token string + +func (t *token) eq(s string) bool { + if t == nil { + return false + } + return string(*t) == s +} +func (t *token) match(matchNil bool, tokenStrings ...string) bool { + if t == nil && matchNil { + return true + } else if t == nil && !matchNil { + return false + } + + for _, tok := range tokenStrings { + if tok == string(*t) { + return true + } + } + return false +} +func (t *token) hasPrefix(prefix string) bool { + if t == nil { + return false + } + return strings.HasPrefix(string(*t), prefix) +} +func (t *token) hasSuffix(suffix string) bool { + if t == nil { + return false + } + return strings.HasSuffix(string(*t), suffix) +} +func (t *token) isUpper() bool { + if t == nil { + return false + } + return isStringUppercase(string(*t)) +} +func (t *token) String() string { + if t == nil { + return "" + } + return string(*t) +} + +func (tl *tokenList) current() *token { + if len(tl.tokens) > 0 { + return (*token)(&(tl.tokens[0])) + } + return nil +} + +func (tl *tokenList) length() int { + return len(tl.tokens) +} + +func (tl *tokenList) move() *token { + if len(tl.tokens) > 0 { + t := tl.tokens[0] + tl.tokens = tl.tokens[1:] + return (*token)(&t) + } + return nil +} + +type patternType uint + +const ( + // leaf + patternArgument patternType = 1 << iota + patternCommand + patternOption + + // branch + patternRequired + patternOptionAL + patternOptionSSHORTCUT // Marker/placeholder for [options] shortcut. + patternOneOrMore + patternEither + + patternLeaf = patternArgument + + patternCommand + + patternOption + patternBranch = patternRequired + + patternOptionAL + + patternOptionSSHORTCUT + + patternOneOrMore + + patternEither + patternAll = patternLeaf + patternBranch + patternDefault = 0 +) + +func (pt patternType) String() string { + switch pt { + case patternArgument: + return "argument" + case patternCommand: + return "command" + case patternOption: + return "option" + case patternRequired: + return "required" + case patternOptionAL: + return "optional" + case patternOptionSSHORTCUT: + return "optionsshortcut" + case patternOneOrMore: + return "oneormore" + case patternEither: + return "either" + case patternLeaf: + return "leaf" + case patternBranch: + return "branch" + case patternAll: + return "all" + case patternDefault: + return "default" + } + return "" +} + +type pattern struct { + t patternType + + children patternList + + name string + value interface{} + + short string + long string + argcount int +} + +type patternList []*pattern + +func newBranchPattern(t patternType, pl ...*pattern) *pattern { + var p pattern + p.t = t + p.children = make(patternList, len(pl)) + copy(p.children, pl) + return &p +} + +func newRequired(pl ...*pattern) *pattern { + return newBranchPattern(patternRequired, pl...) +} + +func newEither(pl ...*pattern) *pattern { + return newBranchPattern(patternEither, pl...) +} + +func newOneOrMore(pl ...*pattern) *pattern { + return newBranchPattern(patternOneOrMore, pl...) +} + +func newOptional(pl ...*pattern) *pattern { + return newBranchPattern(patternOptionAL, pl...) +} + +func newOptionsShortcut() *pattern { + var p pattern + p.t = patternOptionSSHORTCUT + return &p +} + +func newLeafPattern(t patternType, name string, value interface{}) *pattern { + // default: value=nil + var p pattern + p.t = t + p.name = name + p.value = value + return &p +} + +func newArgument(name string, value interface{}) *pattern { + // default: value=nil + return newLeafPattern(patternArgument, name, value) +} + +func newCommand(name string, value interface{}) *pattern { + // default: value=false + var p pattern + p.t = patternCommand + p.name = name + p.value = value + return &p +} + +func newOption(short, long string, argcount int, value interface{}) *pattern { + // default: "", "", 0, false + var p pattern + p.t = patternOption + p.short = short + p.long = long + if long != "" { + p.name = long + } else { + p.name = short + } + p.argcount = argcount + if value == false && argcount > 0 { + p.value = nil + } else { + p.value = value + } + return &p +} + +func (p *pattern) flat(types patternType) (patternList, error) { + if p.t&patternLeaf != 0 { + if types == patternDefault { + types = patternAll + } + if p.t&types != 0 { + return patternList{p}, nil + } + return patternList{}, nil + } + + if p.t&patternBranch != 0 { + if p.t&types != 0 { + return patternList{p}, nil + } + result := patternList{} + for _, child := range p.children { + childFlat, err := child.flat(types) + if err != nil { + return nil, err + } + result = append(result, childFlat...) + } + return result, nil + } + return nil, newError("unknown pattern type: %d, %d", p.t, types) +} + +func (p *pattern) fix() error { + err := p.fixIdentities(nil) + if err != nil { + return err + } + p.fixRepeatingArguments() + return nil +} + +func (p *pattern) fixIdentities(uniq patternList) error { + // Make pattern-tree tips point to same object if they are equal. + if p.t&patternBranch == 0 { + return nil + } + if uniq == nil { + pFlat, err := p.flat(patternDefault) + if err != nil { + return err + } + uniq = pFlat.unique() + } + for i, child := range p.children { + if child.t&patternBranch == 0 { + ind, err := uniq.index(child) + if err != nil { + return err + } + p.children[i] = uniq[ind] + } else { + err := child.fixIdentities(uniq) + if err != nil { + return err + } + } + } + return nil +} + +func (p *pattern) fixRepeatingArguments() { + // Fix elements that should accumulate/increment values. + var either []patternList + + for _, child := range p.transform().children { + either = append(either, child.children) + } + for _, cas := range either { + casMultiple := patternList{} + for _, e := range cas { + if cas.count(e) > 1 { + casMultiple = append(casMultiple, e) + } + } + for _, e := range casMultiple { + if e.t == patternArgument || e.t == patternOption && e.argcount > 0 { + switch e.value.(type) { + case string: + e.value = strings.Fields(e.value.(string)) + case []string: + default: + e.value = []string{} + } + } + if e.t == patternCommand || e.t == patternOption && e.argcount == 0 { + e.value = 0 + } + } + } +} + +func (p *pattern) match(left *patternList, collected *patternList) (bool, *patternList, *patternList) { + if collected == nil { + collected = &patternList{} + } + if p.t&patternRequired != 0 { + l := left + c := collected + for _, p := range p.children { + var matched bool + matched, l, c = p.match(l, c) + if !matched { + return false, left, collected + } + } + return true, l, c + } else if p.t&patternOptionAL != 0 || p.t&patternOptionSSHORTCUT != 0 { + for _, p := range p.children { + _, left, collected = p.match(left, collected) + } + return true, left, collected + } else if p.t&patternOneOrMore != 0 { + if len(p.children) != 1 { + panic("OneOrMore.match(): assert len(p.children) == 1") + } + l := left + c := collected + var lAlt *patternList + matched := true + times := 0 + for matched { + // could it be that something didn't match but changed l or c? + matched, l, c = p.children[0].match(l, c) + if matched { + times++ + } + if lAlt == l { + break + } + lAlt = l + } + if times >= 1 { + return true, l, c + } + return false, left, collected + } else if p.t&patternEither != 0 { + type outcomeStruct struct { + matched bool + left *patternList + collected *patternList + length int + } + outcomes := []outcomeStruct{} + for _, p := range p.children { + matched, l, c := p.match(left, collected) + outcome := outcomeStruct{matched, l, c, len(*l)} + if matched { + outcomes = append(outcomes, outcome) + } + } + if len(outcomes) > 0 { + minLen := outcomes[0].length + minIndex := 0 + for i, v := range outcomes { + if v.length < minLen { + minIndex = i + } + } + return outcomes[minIndex].matched, outcomes[minIndex].left, outcomes[minIndex].collected + } + return false, left, collected + } else if p.t&patternLeaf != 0 { + pos, match := p.singleMatch(left) + var increment interface{} + if match == nil { + return false, left, collected + } + leftAlt := make(patternList, len((*left)[:pos]), len((*left)[:pos])+len((*left)[pos+1:])) + copy(leftAlt, (*left)[:pos]) + leftAlt = append(leftAlt, (*left)[pos+1:]...) + sameName := patternList{} + for _, a := range *collected { + if a.name == p.name { + sameName = append(sameName, a) + } + } + + switch p.value.(type) { + case int, []string: + switch p.value.(type) { + case int: + increment = 1 + case []string: + switch match.value.(type) { + case string: + increment = []string{match.value.(string)} + default: + increment = match.value + } + } + if len(sameName) == 0 { + match.value = increment + collectedMatch := make(patternList, len(*collected), len(*collected)+1) + copy(collectedMatch, *collected) + collectedMatch = append(collectedMatch, match) + return true, &leftAlt, &collectedMatch + } + switch sameName[0].value.(type) { + case int: + sameName[0].value = sameName[0].value.(int) + increment.(int) + case []string: + sameName[0].value = append(sameName[0].value.([]string), increment.([]string)...) + } + return true, &leftAlt, collected + } + collectedMatch := make(patternList, len(*collected), len(*collected)+1) + copy(collectedMatch, *collected) + collectedMatch = append(collectedMatch, match) + return true, &leftAlt, &collectedMatch + } + panic("unmatched type") +} + +func (p *pattern) singleMatch(left *patternList) (int, *pattern) { + if p.t&patternArgument != 0 { + for n, pat := range *left { + if pat.t&patternArgument != 0 { + return n, newArgument(p.name, pat.value) + } + } + return -1, nil + } else if p.t&patternCommand != 0 { + for n, pat := range *left { + if pat.t&patternArgument != 0 { + if pat.value == p.name { + return n, newCommand(p.name, true) + } + break + } + } + return -1, nil + } else if p.t&patternOption != 0 { + for n, pat := range *left { + if p.name == pat.name { + return n, pat + } + } + return -1, nil + } + panic("unmatched type") +} + +func (p *pattern) String() string { + if p.t&patternOption != 0 { + return fmt.Sprintf("%s(%s, %s, %d, %+v)", p.t, p.short, p.long, p.argcount, p.value) + } else if p.t&patternLeaf != 0 { + return fmt.Sprintf("%s(%s, %+v)", p.t, p.name, p.value) + } else if p.t&patternBranch != 0 { + result := "" + for i, child := range p.children { + if i > 0 { + result += ", " + } + result += child.String() + } + return fmt.Sprintf("%s(%s)", p.t, result) + } + panic("unmatched type") +} + +func (p *pattern) transform() *pattern { + /* + Expand pattern into an (almost) equivalent one, but with single Either. + + Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d) + Quirks: [-a] => (-a), (-a...) => (-a -a) + */ + result := []patternList{} + groups := []patternList{patternList{p}} + parents := patternRequired + + patternOptionAL + + patternOptionSSHORTCUT + + patternEither + + patternOneOrMore + for len(groups) > 0 { + children := groups[0] + groups = groups[1:] + var child *pattern + for _, c := range children { + if c.t&parents != 0 { + child = c + break + } + } + if child != nil { + children.remove(child) + if child.t&patternEither != 0 { + for _, c := range child.children { + r := patternList{} + r = append(r, c) + r = append(r, children...) + groups = append(groups, r) + } + } else if child.t&patternOneOrMore != 0 { + r := patternList{} + r = append(r, child.children.double()...) + r = append(r, children...) + groups = append(groups, r) + } else { + r := patternList{} + r = append(r, child.children...) + r = append(r, children...) + groups = append(groups, r) + } + } else { + result = append(result, children) + } + } + either := patternList{} + for _, e := range result { + either = append(either, newRequired(e...)) + } + return newEither(either...) +} + +func (p *pattern) eq(other *pattern) bool { + return reflect.DeepEqual(p, other) +} + +func (pl patternList) unique() patternList { + table := make(map[string]bool) + result := patternList{} + for _, v := range pl { + if !table[v.String()] { + table[v.String()] = true + result = append(result, v) + } + } + return result +} + +func (pl patternList) index(p *pattern) (int, error) { + for i, c := range pl { + if c.eq(p) { + return i, nil + } + } + return -1, newError("%s not in list", p) +} + +func (pl patternList) count(p *pattern) int { + count := 0 + for _, c := range pl { + if c.eq(p) { + count++ + } + } + return count +} + +func (pl patternList) diff(l patternList) patternList { + lAlt := make(patternList, len(l)) + copy(lAlt, l) + result := make(patternList, 0, len(pl)) + for _, v := range pl { + if v != nil { + match := false + for i, w := range lAlt { + if w.eq(v) { + match = true + lAlt[i] = nil + break + } + } + if match == false { + result = append(result, v) + } + } + } + return result +} + +func (pl patternList) double() patternList { + l := len(pl) + result := make(patternList, l*2) + copy(result, pl) + copy(result[l:2*l], pl) + return result +} + +func (pl *patternList) remove(p *pattern) { + (*pl) = pl.diff(patternList{p}) +} + +func (pl patternList) dictionary() map[string]interface{} { + dict := make(map[string]interface{}) + for _, a := range pl { + dict[a.name] = a.value + } + return dict +} + +func stringPartition(s, sep string) (string, string, string) { + sepPos := strings.Index(s, sep) + if sepPos == -1 { // no seperator found + return s, "", "" + } + split := strings.SplitN(s, sep, 2) + return split[0], sep, split[1] +} + +// returns true if all cased characters in the string are uppercase +// and there are there is at least one cased charcter +func isStringUppercase(s string) bool { + if strings.ToUpper(s) != s { + return false + } + for _, c := range []rune(s) { + if unicode.IsUpper(c) { + return true + } + } + return false +} diff --git a/vendor/github.com/docopt/docopt-go/examples/arguments/arguments_example.go b/vendor/github.com/docopt/docopt-go/examples/arguments/arguments_example.go new file mode 100644 index 0000000..7555b99 --- /dev/null +++ b/vendor/github.com/docopt/docopt-go/examples/arguments/arguments_example.go @@ -0,0 +1,29 @@ +package main + +import ( + "fmt" + "github.com/docopt/docopt-go" +) + +func main() { + usage := `Usage: arguments_example [-vqrh] [FILE] ... + arguments_example (--left | --right) CORRECTION FILE + +Process FILE and optionally apply correction to either left-hand side or +right-hand side. + +Arguments: + FILE optional input file + CORRECTION correction angle, needs FILE, --left or --right to be present + +Options: + -h --help + -v verbose mode + -q quiet mode + -r make report + --left use left-hand side + --right use right-hand side` + + arguments, _ := docopt.Parse(usage, nil, true, "", false) + fmt.Println(arguments) +} diff --git a/vendor/github.com/docopt/docopt-go/examples/calculator/calculator_example.go b/vendor/github.com/docopt/docopt-go/examples/calculator/calculator_example.go new file mode 100644 index 0000000..26c3b32 --- /dev/null +++ b/vendor/github.com/docopt/docopt-go/examples/calculator/calculator_example.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "github.com/docopt/docopt-go" +) + +func main() { + usage := `Not a serious example. + +Usage: + calculator_example ( ( + | - | * | / ) )... + calculator_example [( , )]... + calculator_example (-h | --help) + +Examples: + calculator_example 1 + 2 + 3 + 4 + 5 + calculator_example 1 + 2 '*' 3 / 4 - 5 # note quotes around '*' + calculator_example sum 10 , 20 , 30 , 40 + +Options: + -h, --help +` + arguments, _ := docopt.Parse(usage, nil, true, "", false) + fmt.Println(arguments) +} diff --git a/vendor/github.com/docopt/docopt-go/examples/config_file/config_file_example.go b/vendor/github.com/docopt/docopt-go/examples/config_file/config_file_example.go new file mode 100644 index 0000000..b0b1c18 --- /dev/null +++ b/vendor/github.com/docopt/docopt-go/examples/config_file/config_file_example.go @@ -0,0 +1,76 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/docopt/docopt-go" + "strings" +) + +func loadJSONConfig() map[string]interface{} { + var result map[string]interface{} + jsonData := []byte(`{"--force": true, "--timeout": "10", "--baud": "9600"}`) + json.Unmarshal(jsonData, &result) + return result +} + +func loadIniConfig() map[string]interface{} { + iniData := ` +[default-arguments] +--force +--baud=19200 +=localhost` + // trivial ini parser + // default value for an item is bool: true (for --force) + // otherwise the value is a string + iniParsed := make(map[string]map[string]interface{}) + var section string + for _, line := range strings.Split(iniData, "\n") { + if strings.HasPrefix(line, "[") { + section = line + iniParsed[section] = make(map[string]interface{}) + } else if section != "" { + kv := strings.SplitN(line, "=", 2) + if len(kv) == 1 { + iniParsed[section][kv[0]] = true + } else if len(kv) == 2 { + iniParsed[section][kv[0]] = kv[1] + } + } + } + return iniParsed["[default-arguments]"] +} + +// merge combines two maps. +// truthiness takes priority over falsiness +// mapA takes priority over mapB +func merge(mapA, mapB map[string]interface{}) map[string]interface{} { + result := make(map[string]interface{}) + for k, v := range mapA { + result[k] = v + } + for k, v := range mapB { + if _, ok := result[k]; !ok || result[k] == nil || result[k] == false { + result[k] = v + } + } + return result +} + +func main() { + usage := `Usage: + config_file_example tcp [] [--force] [--timeout=] + config_file_example serial [--baud=] [--timeout=] + config_file_example -h | --help | --version` + + jsonConfig := loadJSONConfig() + iniConfig := loadIniConfig() + arguments, _ := docopt.Parse(usage, nil, true, "0.1.1rc", false) + + // Arguments take priority over INI, INI takes priority over JSON + result := merge(arguments, merge(iniConfig, jsonConfig)) + + fmt.Println("JSON config: ", jsonConfig) + fmt.Println("INI config: ", iniConfig) + fmt.Println("Result: ", result) +} diff --git a/vendor/github.com/docopt/docopt-go/examples/counted/counted_example.go b/vendor/github.com/docopt/docopt-go/examples/counted/counted_example.go new file mode 100644 index 0000000..c1da06f --- /dev/null +++ b/vendor/github.com/docopt/docopt-go/examples/counted/counted_example.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "github.com/docopt/docopt-go" +) + +func main() { + usage := `Usage: counted_example --help + counted_example -v... + counted_example go [go] + counted_example (--path=)... + counted_example + +Try: counted_example -vvvvvvvvvv + counted_example go go + counted_example --path ./here --path ./there + counted_example this.txt that.txt` + + arguments, _ := docopt.Parse(usage, nil, true, "", false) + fmt.Println(arguments) +} diff --git a/vendor/github.com/docopt/docopt-go/examples/git/branch/git_branch.go b/vendor/github.com/docopt/docopt-go/examples/git/branch/git_branch.go new file mode 100644 index 0000000..47a4884 --- /dev/null +++ b/vendor/github.com/docopt/docopt-go/examples/git/branch/git_branch.go @@ -0,0 +1,38 @@ +package git + +import ( + "fmt" + "github.com/docopt/docopt-go" +) + +func main() { + usage := `usage: git branch [options] [-r | -a] [--merged= | --no-merged=] + git branch [options] [-l] [-f] [] + git branch [options] [-r] (-d | -D) + git branch [options] (-m | -M) [] + +Generic options: + -h, --help + -v, --verbose show hash and subject, give twice for upstream branch + -t, --track set up tracking mode (see git-pull(1)) + --set-upstream change upstream info + --color= use colored output + -r act on remote-tracking branches + --contains= print only branches that contain the commit + --abbrev= use digits to display SHA-1s + +Specific git-branch actions: + -a list both remote-tracking and local branches + -d delete fully merged branch + -D delete branch (even if not merged) + -m move/rename a branch and its reflog + -M move/rename a branch, even if target exists + -l create the branch's reflog + -f, --force force creation (when already exists) + --no-merged= print only not merged branches + --merged= print only merged branches +` + + args, _ := docopt.Parse(usage, nil, true, "", false) + fmt.Println(args) +} diff --git a/vendor/github.com/docopt/docopt-go/examples/git/checkout/git_checkout.go b/vendor/github.com/docopt/docopt-go/examples/git/checkout/git_checkout.go new file mode 100644 index 0000000..00fe71c --- /dev/null +++ b/vendor/github.com/docopt/docopt-go/examples/git/checkout/git_checkout.go @@ -0,0 +1,30 @@ +package git + +import ( + "fmt" + "github.com/docopt/docopt-go" +) + +func main() { + usage := `usage: git checkout [options] + git checkout [options] -- ... + +options: + -q, --quiet suppress progress reporting + -b create and checkout a new branch + -B create/reset and checkout a branch + -l create reflog for new branch + -t, --track set upstream info for new branch + --orphan + new unparented branch + -2, --ours checkout our version for unmerged files + -3, --theirs checkout their version for unmerged files + -f, --force force checkout (throw away local modifications) + -m, --merge perform a 3-way merge with the new branch + --conflict