rfix 1.4.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/rfix +78 -34
- data/lib/rfix.rb +17 -28
- data/lib/rfix/branch.rb +3 -25
- data/lib/rfix/branch/base.rb +27 -0
- data/lib/rfix/branch/head.rb +15 -0
- data/lib/rfix/branch/main.rb +33 -0
- data/lib/rfix/branch/name.rb +21 -0
- data/lib/rfix/branch/reference.rb +15 -0
- data/lib/rfix/branch/upstream.rb +17 -0
- data/lib/rfix/cli/command.rb +19 -0
- data/lib/rfix/cli/command/base.rb +61 -0
- data/lib/rfix/cli/command/branch.rb +13 -0
- data/lib/rfix/cli/command/config.rb +22 -0
- data/lib/rfix/cli/command/extension.rb +25 -0
- data/lib/rfix/cli/command/help.rb +11 -0
- data/lib/rfix/cli/command/info.rb +11 -0
- data/lib/rfix/cli/command/lint.rb +17 -0
- data/lib/rfix/cli/command/local.rb +11 -0
- data/lib/rfix/cli/command/origin.rb +11 -0
- data/lib/rfix/cli/command/setup.rb +11 -0
- data/lib/rfix/error.rb +5 -1
- data/lib/rfix/extension/offense.rb +79 -0
- data/lib/rfix/extension/pastel.rb +11 -0
- data/lib/rfix/extension/string.rb +12 -0
- data/lib/rfix/extension/strings.rb +9 -0
- data/lib/rfix/file.rb +6 -41
- data/lib/rfix/file/base.rb +73 -0
- data/lib/rfix/file/deleted.rb +17 -0
- data/lib/rfix/file/ignored.rb +17 -0
- data/lib/rfix/file/tracked.rb +42 -0
- data/lib/rfix/file/untracked.rb +20 -0
- data/lib/rfix/formatter.rb +125 -86
- data/lib/rfix/highlighter.rb +118 -0
- data/lib/rfix/indicator.rb +19 -0
- data/lib/rfix/log.rb +12 -121
- data/lib/rfix/rake/gemfile.rb +111 -0
- data/lib/rfix/rake/paths.rb +25 -23
- data/lib/rfix/rake/support.rb +72 -57
- data/lib/rfix/repository.rb +114 -164
- data/lib/rfix/types.rb +52 -0
- data/lib/rfix/version.rb +1 -1
- data/rfix.gemspec +28 -38
- data/vendor/dry-cli/CHANGELOG.md +191 -0
- data/vendor/dry-cli/CODEOWNERS +1 -0
- data/vendor/dry-cli/CODE_OF_CONDUCT.md +13 -0
- data/vendor/dry-cli/CONTRIBUTING.md +29 -0
- data/vendor/dry-cli/Gemfile +14 -0
- data/vendor/dry-cli/Gemfile.devtools +18 -0
- data/vendor/dry-cli/LICENSE +20 -0
- data/vendor/dry-cli/README.md +29 -0
- data/vendor/dry-cli/Rakefile +13 -0
- data/vendor/dry-cli/bin/console +15 -0
- data/vendor/dry-cli/bin/setup +8 -0
- data/vendor/dry-cli/changelog.yml +97 -0
- data/vendor/dry-cli/docsite/source/arguments.html.md +57 -0
- data/vendor/dry-cli/docsite/source/callbacks.html.md +51 -0
- data/vendor/dry-cli/docsite/source/commands-with-subcommands-and-params.md +86 -0
- data/vendor/dry-cli/docsite/source/commands.html.md +41 -0
- data/vendor/dry-cli/docsite/source/index.html.md +302 -0
- data/vendor/dry-cli/docsite/source/options.html.md +51 -0
- data/vendor/dry-cli/docsite/source/subcommands.html.md +38 -0
- data/vendor/dry-cli/docsite/source/variadic-arguments.html.md +45 -0
- data/vendor/dry-cli/dry-cli.gemspec +36 -0
- data/vendor/dry-cli/lib/dry/cli.rb +224 -0
- data/vendor/dry-cli/lib/dry/cli/banner.rb +135 -0
- data/vendor/dry-cli/lib/dry/cli/command.rb +387 -0
- data/vendor/dry-cli/lib/dry/cli/command_registry.rb +253 -0
- data/vendor/dry-cli/lib/dry/cli/errors.rb +37 -0
- data/vendor/dry-cli/lib/dry/cli/inflector.rb +17 -0
- data/vendor/dry-cli/lib/dry/cli/inline.rb +75 -0
- data/vendor/dry-cli/lib/dry/cli/option.rb +131 -0
- data/vendor/dry-cli/lib/dry/cli/parser.rb +138 -0
- data/vendor/dry-cli/lib/dry/cli/program_name.rb +21 -0
- data/vendor/dry-cli/lib/dry/cli/registry.rb +338 -0
- data/vendor/dry-cli/lib/dry/cli/usage.rb +94 -0
- data/vendor/dry-cli/lib/dry/cli/version.rb +8 -0
- data/vendor/dry-cli/project.yml +13 -0
- data/vendor/dry-cli/spec/integration/commands_spec.rb +14 -0
- data/vendor/dry-cli/spec/integration/inherited_commands_spec.rb +24 -0
- data/vendor/dry-cli/spec/integration/inline_spec.rb +43 -0
- data/vendor/dry-cli/spec/integration/processes_errors_spec.rb +29 -0
- data/vendor/dry-cli/spec/integration/rendering_spec.rb +31 -0
- data/vendor/dry-cli/spec/integration/single_command_spec.rb +81 -0
- data/vendor/dry-cli/spec/integration/subcommands_spec.rb +60 -0
- data/vendor/dry-cli/spec/integration/third_party_gems_spec.rb +18 -0
- data/vendor/dry-cli/spec/spec_helper.rb +15 -0
- data/vendor/dry-cli/spec/support/coverage.rb +15 -0
- data/vendor/dry-cli/spec/support/files.rb +13 -0
- data/vendor/dry-cli/spec/support/fixtures/based +65 -0
- data/vendor/dry-cli/spec/support/fixtures/baz +9 -0
- data/vendor/dry-cli/spec/support/fixtures/baz_command.rb +19 -0
- data/vendor/dry-cli/spec/support/fixtures/foo +588 -0
- data/vendor/dry-cli/spec/support/fixtures/infinites +31 -0
- data/vendor/dry-cli/spec/support/fixtures/inline +20 -0
- data/vendor/dry-cli/spec/support/fixtures/registry.rb +15 -0
- data/vendor/dry-cli/spec/support/fixtures/shared_commands.rb +596 -0
- data/vendor/dry-cli/spec/support/fixtures/with_block.rb +86 -0
- data/vendor/dry-cli/spec/support/fixtures/with_registry.rb +90 -0
- data/vendor/dry-cli/spec/support/fixtures/with_zero_arity_block.rb +87 -0
- data/vendor/dry-cli/spec/support/helpers.rb +37 -0
- data/vendor/dry-cli/spec/support/path.rb +24 -0
- data/vendor/dry-cli/spec/support/rspec.rb +26 -0
- data/vendor/dry-cli/spec/support/rspec_options.rb +16 -0
- data/vendor/dry-cli/spec/support/shared_examples/commands.rb +300 -0
- data/vendor/dry-cli/spec/support/shared_examples/inherited_commands.rb +197 -0
- data/vendor/dry-cli/spec/support/shared_examples/rendering.rb +181 -0
- data/vendor/dry-cli/spec/support/shared_examples/subcommands.rb +226 -0
- data/vendor/dry-cli/spec/support/shared_examples/third_party_gems.rb +49 -0
- data/vendor/dry-cli/spec/support/warnings.rb +10 -0
- data/vendor/dry-cli/spec/unit/dry/cli/cli_spec.rb +123 -0
- data/vendor/dry-cli/spec/unit/dry/cli/inflector_spec.rb +26 -0
- data/vendor/dry-cli/spec/unit/dry/cli/registry_spec.rb +78 -0
- data/vendor/dry-cli/spec/unit/dry/cli/version_spec.rb +7 -0
- data/vendor/strings-ansi/CHANGELOG.md +24 -0
- data/vendor/strings-ansi/CODE_OF_CONDUCT.md +74 -0
- data/vendor/strings-ansi/Gemfile +11 -0
- data/{LICENSE.txt → vendor/strings-ansi/LICENSE.txt} +1 -1
- data/vendor/strings-ansi/README.md +155 -0
- data/vendor/strings-ansi/Rakefile +8 -0
- data/vendor/strings-ansi/appveyor.yml +32 -0
- data/vendor/strings-ansi/bin/console +14 -0
- data/vendor/strings-ansi/bin/setup +8 -0
- data/vendor/strings-ansi/lib/strings-ansi.rb +1 -0
- data/vendor/strings-ansi/lib/strings/ansi.rb +84 -0
- data/vendor/strings-ansi/lib/strings/ansi/extensions.rb +23 -0
- data/vendor/strings-ansi/lib/strings/ansi/version.rb +7 -0
- data/vendor/strings-ansi/spec/fixtures/ansi_codes.yaml +194 -0
- data/vendor/strings-ansi/spec/spec_helper.rb +51 -0
- data/vendor/strings-ansi/spec/unit/ansi_spec.rb +15 -0
- data/vendor/strings-ansi/spec/unit/extensions_spec.rb +19 -0
- data/vendor/strings-ansi/spec/unit/only_ansi_spec.rb +36 -0
- data/vendor/strings-ansi/spec/unit/sanitize_spec.rb +53 -0
- data/vendor/strings-ansi/strings-ansi.gemspec +34 -0
- data/vendor/strings-ansi/tasks/console.rake +11 -0
- data/vendor/strings-ansi/tasks/coverage.rake +11 -0
- data/vendor/strings-ansi/tasks/spec.rake +29 -0
- metadata +274 -188
- data/.github/workflows/main.yml +0 -26
- data/.gitignore +0 -43
- data/.rspec +0 -2
- data/.rubocop.yml +0 -87
- data/.travis.yml +0 -35
- data/Gemfile +0 -2
- data/Gemfile.base +0 -14
- data/Gemfile.base.lock +0 -172
- data/Gemfile.lock +0 -188
- data/Guardfile +0 -16
- data/Makefile +0 -12
- data/README.md +0 -85
- data/Rakefile +0 -31
- data/bin/bundle +0 -114
- data/bin/console +0 -29
- data/bin/guard +0 -29
- data/bin/rake +0 -29
- data/bin/rfix +0 -29
- data/bin/rspec +0 -29
- data/bin/setup +0 -29
- data/ci/Gemfile.rubocop-0.80 +0 -2
- data/ci/Gemfile.rubocop-0.80.lock +0 -170
- data/ci/Gemfile.rubocop-0.81 +0 -2
- data/ci/Gemfile.rubocop-0.81.lock +0 -170
- data/ci/Gemfile.rubocop-0.82 +0 -2
- data/ci/Gemfile.rubocop-0.82.lock +0 -170
- data/ci/Gemfile.rubocop-0.83 +0 -2
- data/ci/Gemfile.rubocop-0.83.lock +0 -168
- data/ci/Gemfile.rubocop-0.84 +0 -2
- data/ci/Gemfile.rubocop-0.84.lock +0 -171
- data/ci/Gemfile.rubocop-0.85 +0 -2
- data/ci/Gemfile.rubocop-0.85.1 +0 -2
- data/ci/Gemfile.rubocop-0.85.1.lock +0 -173
- data/ci/Gemfile.rubocop-0.85.lock +0 -173
- data/lib/rfix/box.rb +0 -112
- data/lib/rfix/branches/base.rb +0 -15
- data/lib/rfix/branches/head.rb +0 -13
- data/lib/rfix/branches/main.rb +0 -28
- data/lib/rfix/branches/name.rb +0 -23
- data/lib/rfix/branches/reference.rb +0 -21
- data/lib/rfix/branches/upstream.rb +0 -13
- data/lib/rfix/cmd.rb +0 -39
- data/lib/rfix/commands/branch.rb +0 -15
- data/lib/rfix/commands/extensions/options.rb +0 -8
- data/lib/rfix/commands/help.rb +0 -7
- data/lib/rfix/commands/helper/args.rb +0 -141
- data/lib/rfix/commands/helper/help.rb +0 -6
- data/lib/rfix/commands/helper/loader.rb +0 -6
- data/lib/rfix/commands/helper/option.rb +0 -0
- data/lib/rfix/commands/helper/params.rb +0 -0
- data/lib/rfix/commands/helper/rubocop.rb +0 -17
- data/lib/rfix/commands/info.rb +0 -30
- data/lib/rfix/commands/lint.rb +0 -22
- data/lib/rfix/commands/local.rb +0 -12
- data/lib/rfix/commands/origin.rb +0 -19
- data/lib/rfix/commands/setup.rb +0 -29
- data/lib/rfix/commands/welcome.rb +0 -24
- data/lib/rfix/deleted.rb +0 -13
- data/lib/rfix/extensions/extensions.rb +0 -18
- data/lib/rfix/extensions/offense.rb +0 -78
- data/lib/rfix/extensions/string.rb +0 -8
- data/lib/rfix/file_cache.rb +0 -59
- data/lib/rfix/git_helper.rb +0 -59
- data/lib/rfix/indentation.rb +0 -39
- data/lib/rfix/loader/bundler.rb +0 -37
- data/lib/rfix/loader/env.rb +0 -33
- data/lib/rfix/loader/spec.rb +0 -41
- data/lib/rfix/no_file.rb +0 -13
- data/lib/rfix/rfix.rb +0 -34
- data/lib/rfix/tracked.rb +0 -72
- data/lib/rfix/tracked_file.rb +0 -16
- data/lib/rfix/untracked.rb +0 -13
- data/resources/ps.png +0 -0
- data/tasks/bump.rake +0 -11
- data/tasks/bundle.rake +0 -17
- data/tasks/complex.rake +0 -54
- data/tasks/execute.rake +0 -38
- data/tasks/libgit2.rake +0 -33
- data/tasks/simple.rake +0 -62
- data/tasks/travis.rake +0 -74
- data/tasks/vendor.rake +0 -34
@@ -0,0 +1,51 @@
|
|
1
|
+
---
|
2
|
+
title: Options
|
3
|
+
layout: gem-single
|
4
|
+
name: dry-cli
|
5
|
+
---
|
6
|
+
|
7
|
+
An option is a named argument that is passed after the _command name_ **and** the arguments.
|
8
|
+
|
9
|
+
For instance, given the `foo request` command, when an user types `foo request --mode=http2`, then `--mode=http2` is considered an option.
|
10
|
+
A command can accept none or many options.
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
#!/usr/bin/env ruby
|
14
|
+
require "bundler/setup"
|
15
|
+
require "dry/cli"
|
16
|
+
|
17
|
+
module Foo
|
18
|
+
module CLI
|
19
|
+
module Commands
|
20
|
+
extend Dry::CLI::Registry
|
21
|
+
|
22
|
+
class Request < Dry::CLI::Command
|
23
|
+
option :mode, default: "http", values: %w[http http2], desc: "The request mode"
|
24
|
+
|
25
|
+
def call(**options)
|
26
|
+
puts "Performing a request (mode: #{options.fetch(:mode)})"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
register "request", Request
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Dry::CLI.new(Foo::CLI::Commands).call
|
36
|
+
```
|
37
|
+
|
38
|
+
```sh
|
39
|
+
$ foo request
|
40
|
+
Performing a request (mode: http)
|
41
|
+
```
|
42
|
+
|
43
|
+
```sh
|
44
|
+
$ foo request --mode=http2
|
45
|
+
Performing a request (mode: http2)
|
46
|
+
```
|
47
|
+
|
48
|
+
```sh
|
49
|
+
$ foo request --mode=unknown
|
50
|
+
ERROR: "foo request" was called with arguments "--mode=unknown"
|
51
|
+
```
|
@@ -0,0 +1,38 @@
|
|
1
|
+
---
|
2
|
+
title: Subcommands
|
3
|
+
layout: gem-single
|
4
|
+
name: dry-cli
|
5
|
+
---
|
6
|
+
|
7
|
+
There is nothing special about subcommands, they are simply _command objects_ registered under a **nested** _command name_:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
#!/usr/bin/env ruby
|
11
|
+
require "bundler/setup"
|
12
|
+
require "dry/cli"
|
13
|
+
|
14
|
+
module Foo
|
15
|
+
module CLI
|
16
|
+
module Commands
|
17
|
+
extend Dry::CLI::Registry
|
18
|
+
|
19
|
+
module Generate
|
20
|
+
class Configuration < Dry::CLI::Command
|
21
|
+
def call(*)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Foo::CLI::Commands.register "generate configuration", Foo::CLI::Commands::Generate::Configuration
|
30
|
+
|
31
|
+
Dry::CLI.new(Foo::CLI::Commands).call
|
32
|
+
```
|
33
|
+
|
34
|
+
```sh
|
35
|
+
$ foo generate
|
36
|
+
Commands:
|
37
|
+
foo generate config # Generate configuration
|
38
|
+
```
|
@@ -0,0 +1,45 @@
|
|
1
|
+
---
|
2
|
+
title: Variadic arguments
|
3
|
+
layout: gem-single
|
4
|
+
name: dry-cli
|
5
|
+
---
|
6
|
+
|
7
|
+
Sometimes we need extra arguments because those will be forwarded to a sub-command like `ssh`, `docker` or `cat`.
|
8
|
+
|
9
|
+
By using `--` (double dash, aka hypen), the user indicates the end of the arguments and options belonging to the main command, and the beginning of the variadic arguments that can be forwarded to the sub-command.
|
10
|
+
These extra arguments are included as `:args` in the keyword arguments available for each command.
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
#!/usr/bin/env ruby
|
14
|
+
require "bundler/setup"
|
15
|
+
require "dry/cli"
|
16
|
+
|
17
|
+
module Foo
|
18
|
+
module CLI
|
19
|
+
module Commands
|
20
|
+
extend Dry::CLI::Registry
|
21
|
+
|
22
|
+
class Runner < Dry::CLI::Command
|
23
|
+
argument :image, required: true, desc: "Docker image"
|
24
|
+
|
25
|
+
def call(image:, args: [], **)
|
26
|
+
puts `docker run -it --rm #{image} #{args.join(" ")}`
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
register "run", Runner
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Dry::CLI.new(Foo::CLI::Commands).call
|
36
|
+
```
|
37
|
+
|
38
|
+
```sh
|
39
|
+
$ foo run ruby:latest -- ruby -v
|
40
|
+
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
|
41
|
+
```
|
42
|
+
|
43
|
+
The user separates via `--` the arguments for `foo` and the command has to be run by the Docker container.
|
44
|
+
In this specific case, `ruby:latest` corresponds to the `image` mandatory argument for `foo`, whereas `ruby -v` is the variadic argument that is passed to Docker via `args`.
|
45
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# this file is managed by dry-rb/devtools project
|
3
|
+
|
4
|
+
lib = File.expand_path('lib', __dir__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require 'dry/cli/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'dry-cli'
|
10
|
+
spec.authors = ["Luca Guidi"]
|
11
|
+
spec.email = ["me@lucaguidi.com"]
|
12
|
+
spec.license = 'MIT'
|
13
|
+
spec.version = Dry::CLI::VERSION.dup
|
14
|
+
|
15
|
+
spec.summary = "Common framework to build command line interfaces with Ruby"
|
16
|
+
spec.description = spec.summary
|
17
|
+
spec.homepage = 'https://dry-rb.org/gems/dry-cli'
|
18
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-cli.gemspec", "lib/**/*"]
|
19
|
+
spec.bindir = 'bin'
|
20
|
+
spec.executables = []
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
|
23
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
24
|
+
spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-cli/blob/master/CHANGELOG.md'
|
25
|
+
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-cli'
|
26
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-cli/issues'
|
27
|
+
|
28
|
+
spec.required_ruby_version = ">= 2.4.0"
|
29
|
+
|
30
|
+
# to update dependencies edit project.yml
|
31
|
+
spec.add_development_dependency "bundler", ">= 1.6", "< 3"
|
32
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.7"
|
34
|
+
spec.add_development_dependency "rubocop", "~> 0.82"
|
35
|
+
spec.add_development_dependency "simplecov", "~> 0.17.1"
|
36
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Dry
|
4
|
+
#
|
5
|
+
# @since 0.1.0
|
6
|
+
module Dry
|
7
|
+
# General purpose Command Line Interface (CLI) framework for Ruby
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
class CLI
|
11
|
+
require "dry/cli/version"
|
12
|
+
require "dry/cli/errors"
|
13
|
+
require "dry/cli/command"
|
14
|
+
require "dry/cli/registry"
|
15
|
+
require "dry/cli/parser"
|
16
|
+
require "dry/cli/usage"
|
17
|
+
require "dry/cli/banner"
|
18
|
+
require "dry/cli/inflector"
|
19
|
+
|
20
|
+
# Check if command
|
21
|
+
#
|
22
|
+
# @param command [Object] the command to check
|
23
|
+
#
|
24
|
+
# @return [TrueClass,FalseClass] true if instance of `Dry::CLI::Command`
|
25
|
+
#
|
26
|
+
# @since 0.1.0
|
27
|
+
# @api private
|
28
|
+
def self.command?(command)
|
29
|
+
case command
|
30
|
+
when Class
|
31
|
+
command.ancestors.include?(Command)
|
32
|
+
else
|
33
|
+
command.is_a?(Command)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Create a new instance
|
38
|
+
#
|
39
|
+
# @param command_or_registry [Dry::CLI::Registry, Dry::CLI::Command]
|
40
|
+
# a registry or singular command
|
41
|
+
# @param &block [Block] a configuration block for registry
|
42
|
+
#
|
43
|
+
# @return [Dry::CLI] the new instance
|
44
|
+
# @since 0.1.0
|
45
|
+
def initialize(command_or_registry = nil, &block)
|
46
|
+
@kommand = command_or_registry if command?(command_or_registry)
|
47
|
+
|
48
|
+
@registry =
|
49
|
+
if block_given?
|
50
|
+
anonymous_registry(&block)
|
51
|
+
else
|
52
|
+
command_or_registry
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Invoke the CLI
|
57
|
+
#
|
58
|
+
# @param arguments [Array<string>] the command line arguments (defaults to `ARGV`)
|
59
|
+
# @param out [IO] the standard output (defaults to `$stdout`)
|
60
|
+
# @param err [IO] the error output (defaults to `$stderr`)
|
61
|
+
#
|
62
|
+
# @since 0.1.0
|
63
|
+
def call(arguments: ARGV, out: $stdout, err: $stderr)
|
64
|
+
@out, @err = out, err
|
65
|
+
kommand ? perform_command(arguments) : perform_registry(arguments)
|
66
|
+
rescue SignalException => e
|
67
|
+
signal_exception(e)
|
68
|
+
rescue Errno::EPIPE
|
69
|
+
# no op
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# @since 0.6.0
|
75
|
+
# @api private
|
76
|
+
attr_reader :registry
|
77
|
+
|
78
|
+
# @since 0.6.0
|
79
|
+
# @api private
|
80
|
+
attr_reader :kommand
|
81
|
+
|
82
|
+
# @since 0.6.0
|
83
|
+
# @api private
|
84
|
+
attr_reader :out
|
85
|
+
|
86
|
+
# @since 0.6.0
|
87
|
+
# @api private
|
88
|
+
attr_reader :err
|
89
|
+
|
90
|
+
# Invoke the CLI if singular command passed
|
91
|
+
#
|
92
|
+
# @param arguments [Array<string>] the command line arguments
|
93
|
+
# @param out [IO] the standard output (defaults to `$stdout`)
|
94
|
+
#
|
95
|
+
# @since 0.6.0
|
96
|
+
# @api private
|
97
|
+
def perform_command(arguments)
|
98
|
+
command, args = parse(kommand, arguments, [])
|
99
|
+
command.call(**args)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Invoke the CLI if registry passed
|
103
|
+
#
|
104
|
+
# @param arguments [Array<string>] the command line arguments
|
105
|
+
# @param out [IO] the standard output (defaults to `$stdout`)
|
106
|
+
#
|
107
|
+
# @since 0.6.0
|
108
|
+
# @api private
|
109
|
+
def perform_registry(arguments)
|
110
|
+
result = registry.get(arguments)
|
111
|
+
return usage(result) unless result.found?
|
112
|
+
|
113
|
+
command, args = parse(result.command, result.arguments, result.names)
|
114
|
+
|
115
|
+
result.before_callbacks.run(command, args)
|
116
|
+
command.call(**args)
|
117
|
+
result.after_callbacks.run(command, args)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Parse arguments for a command.
|
121
|
+
#
|
122
|
+
# It may exit in case of error, or in case of help.
|
123
|
+
#
|
124
|
+
# @param result [Dry::CLI::CommandRegistry::LookupResult]
|
125
|
+
# @param out [IO] sta output
|
126
|
+
#
|
127
|
+
# @return [Array<Dry:CLI::Command, Array>] returns an array where the
|
128
|
+
# first element is a command and the second one is the list of arguments
|
129
|
+
#
|
130
|
+
# @since 0.6.0
|
131
|
+
# @api private
|
132
|
+
def parse(command, arguments, names)
|
133
|
+
prog_name = ProgramName.call(names)
|
134
|
+
|
135
|
+
result = Parser.call(command, arguments, prog_name)
|
136
|
+
|
137
|
+
return help(command, prog_name) if result.help?
|
138
|
+
|
139
|
+
return error(result) if result.error?
|
140
|
+
|
141
|
+
[build_command(command), result.arguments]
|
142
|
+
end
|
143
|
+
|
144
|
+
# @since 0.6.0
|
145
|
+
# @api private
|
146
|
+
def build_command(command)
|
147
|
+
command.is_a?(Class) ? command.new : command
|
148
|
+
end
|
149
|
+
|
150
|
+
# @since 0.6.0
|
151
|
+
# @api private
|
152
|
+
def help(command, prog_name)
|
153
|
+
out.puts Banner.call(command, prog_name)
|
154
|
+
exit(0) # Successful exit
|
155
|
+
end
|
156
|
+
|
157
|
+
# @since 0.6.0
|
158
|
+
# @api private
|
159
|
+
def error(result)
|
160
|
+
err.puts(result.error)
|
161
|
+
exit(1)
|
162
|
+
end
|
163
|
+
|
164
|
+
# @since 0.1.0
|
165
|
+
# @api private
|
166
|
+
def usage(result)
|
167
|
+
err.puts Usage.call(result)
|
168
|
+
exit(1)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Handles Exit codes for signals
|
172
|
+
# Fatal error signal "n". Say 130 = 128 + 2 (SIGINT) or 137 = 128 + 9 (SIGKILL)
|
173
|
+
#
|
174
|
+
# @since 0.7.0
|
175
|
+
# @api private
|
176
|
+
def signal_exception(exception)
|
177
|
+
exit(128 + exception.signo)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Check if command
|
181
|
+
#
|
182
|
+
# @param command [Object] the command to check
|
183
|
+
#
|
184
|
+
# @return [TrueClass,FalseClass] true if instance of `Dry::CLI::Command`
|
185
|
+
#
|
186
|
+
# @since 0.1.0
|
187
|
+
# @api private
|
188
|
+
#
|
189
|
+
# @see .command?
|
190
|
+
def command?(command)
|
191
|
+
CLI.command?(command)
|
192
|
+
end
|
193
|
+
|
194
|
+
# Generates registry in runtime
|
195
|
+
#
|
196
|
+
# @param &block [Block] configuration for the registry
|
197
|
+
#
|
198
|
+
# @return [Module] module extended with registry abilities and configured with a block
|
199
|
+
#
|
200
|
+
# @since 0.4.0
|
201
|
+
# @api private
|
202
|
+
def anonymous_registry(&block)
|
203
|
+
registry = Module.new { extend(Dry::CLI::Registry) }
|
204
|
+
if block.arity.zero?
|
205
|
+
registry.instance_eval(&block)
|
206
|
+
else
|
207
|
+
yield(registry)
|
208
|
+
end
|
209
|
+
registry
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Create a new instance
|
214
|
+
#
|
215
|
+
# @param registry_or_command [Dry::CLI::Registry, Dry::CLI::Command]
|
216
|
+
# a registry or singular command
|
217
|
+
# @param &block [Block] a configuration block for registry
|
218
|
+
#
|
219
|
+
# @return [Dry::CLI] the new instance
|
220
|
+
# @since 0.4.0
|
221
|
+
def self.CLI(registry_or_command = nil, &block)
|
222
|
+
CLI.new(registry_or_command, &block)
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/cli/program_name"
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
class CLI
|
7
|
+
# Command banner
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
# @api private
|
11
|
+
module Banner
|
12
|
+
# Prints command banner
|
13
|
+
#
|
14
|
+
# @param command [Dry::CLI::Command] the command
|
15
|
+
# @param out [IO] standard output
|
16
|
+
#
|
17
|
+
# @since 0.1.0
|
18
|
+
# @api private
|
19
|
+
def self.call(command, name)
|
20
|
+
[
|
21
|
+
command_name(name),
|
22
|
+
command_name_and_arguments(command, name),
|
23
|
+
command_description(command),
|
24
|
+
command_subcommands(command),
|
25
|
+
command_arguments(command),
|
26
|
+
command_options(command),
|
27
|
+
command_examples(command, name)
|
28
|
+
].compact.join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
# @since 0.1.0
|
32
|
+
# @api private
|
33
|
+
def self.command_name(name)
|
34
|
+
"Command:\n #{name}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# @since 0.1.0
|
38
|
+
# @api private
|
39
|
+
def self.command_name_and_arguments(command, name)
|
40
|
+
usage = "\nUsage:\n #{name}#{arguments(command)}"
|
41
|
+
|
42
|
+
return usage + " | #{name} SUBCOMMAND" if command.subcommands.any?
|
43
|
+
|
44
|
+
usage
|
45
|
+
end
|
46
|
+
|
47
|
+
# @since 0.1.0
|
48
|
+
# @api private
|
49
|
+
def self.command_examples(command, name)
|
50
|
+
return if command.examples.empty?
|
51
|
+
|
52
|
+
"\nExamples:\n#{command.examples.map { |example| " #{name} #{example}" }.join("\n")}"
|
53
|
+
end
|
54
|
+
|
55
|
+
# @since 0.1.0
|
56
|
+
# @api private
|
57
|
+
def self.command_description(command)
|
58
|
+
return if command.description.nil?
|
59
|
+
|
60
|
+
"\nDescription:\n #{command.description}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.command_subcommands(command)
|
64
|
+
return if command.subcommands.empty?
|
65
|
+
|
66
|
+
"\nSubcommands:\n#{build_subcommands_list(command.subcommands)}"
|
67
|
+
end
|
68
|
+
|
69
|
+
# @since 0.1.0
|
70
|
+
# @api private
|
71
|
+
def self.command_arguments(command)
|
72
|
+
return if command.arguments.empty?
|
73
|
+
|
74
|
+
"\nArguments:\n#{extended_command_arguments(command)}"
|
75
|
+
end
|
76
|
+
|
77
|
+
# @since 0.1.0
|
78
|
+
# @api private
|
79
|
+
def self.command_options(command)
|
80
|
+
"\nOptions:\n#{extended_command_options(command)}"
|
81
|
+
end
|
82
|
+
|
83
|
+
# @since 0.1.0
|
84
|
+
# @api private
|
85
|
+
def self.arguments(command)
|
86
|
+
required_arguments = command.required_arguments
|
87
|
+
optional_arguments = command.optional_arguments
|
88
|
+
|
89
|
+
required = required_arguments.map { |arg| arg.name.upcase }.join(" ") if required_arguments.any? # rubocop:disable Metrics/LineLength
|
90
|
+
optional = optional_arguments.map { |arg| "[#{arg.name.upcase}]" }.join(" ") if optional_arguments.any? # rubocop:disable Metrics/LineLength
|
91
|
+
result = [required, optional].compact
|
92
|
+
|
93
|
+
" #{result.join(" ")}" unless result.empty?
|
94
|
+
end
|
95
|
+
|
96
|
+
# @since 0.1.0
|
97
|
+
# @api private
|
98
|
+
def self.extended_command_arguments(command)
|
99
|
+
command.arguments.map do |argument|
|
100
|
+
" #{argument.name.to_s.upcase.ljust(32)} # #{"REQUIRED " if argument.required?}#{argument.desc}" # rubocop:disable Metrics/LineLength
|
101
|
+
end.join("\n")
|
102
|
+
end
|
103
|
+
|
104
|
+
# @since 0.1.0
|
105
|
+
# @api private
|
106
|
+
#
|
107
|
+
def self.extended_command_options(command)
|
108
|
+
result = command.options.map do |option|
|
109
|
+
name = Inflector.dasherize(option.name)
|
110
|
+
name = if option.boolean?
|
111
|
+
"[no-]#{name}"
|
112
|
+
elsif option.array?
|
113
|
+
"#{name}=VALUE1,VALUE2,.."
|
114
|
+
else
|
115
|
+
"#{name}=VALUE"
|
116
|
+
end
|
117
|
+
name = "#{name}, #{option.alias_names.join(", ")}" if option.aliases.any?
|
118
|
+
name = " --#{name.ljust(30)}"
|
119
|
+
name = "#{name} # #{option.desc}"
|
120
|
+
name = "#{name}, default: #{option.default.inspect}" unless option.default.nil?
|
121
|
+
name
|
122
|
+
end
|
123
|
+
|
124
|
+
result << " --#{"help, -h".ljust(30)} # Print this help"
|
125
|
+
result.join("\n")
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.build_subcommands_list(subcommands)
|
129
|
+
subcommands.map do |subcommand_name, subcommand|
|
130
|
+
" #{subcommand_name.ljust(32)} # #{subcommand.command.description}"
|
131
|
+
end.join("\n")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|