rfix 1.4.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (219) hide show
  1. checksums.yaml +4 -4
  2. data/exe/rfix +78 -34
  3. data/lib/rfix.rb +17 -28
  4. data/lib/rfix/branch.rb +3 -25
  5. data/lib/rfix/branch/base.rb +27 -0
  6. data/lib/rfix/branch/head.rb +15 -0
  7. data/lib/rfix/branch/main.rb +33 -0
  8. data/lib/rfix/branch/name.rb +21 -0
  9. data/lib/rfix/branch/reference.rb +15 -0
  10. data/lib/rfix/branch/upstream.rb +17 -0
  11. data/lib/rfix/cli/command.rb +19 -0
  12. data/lib/rfix/cli/command/base.rb +61 -0
  13. data/lib/rfix/cli/command/branch.rb +13 -0
  14. data/lib/rfix/cli/command/config.rb +22 -0
  15. data/lib/rfix/cli/command/extension.rb +25 -0
  16. data/lib/rfix/cli/command/help.rb +11 -0
  17. data/lib/rfix/cli/command/info.rb +11 -0
  18. data/lib/rfix/cli/command/lint.rb +17 -0
  19. data/lib/rfix/cli/command/local.rb +11 -0
  20. data/lib/rfix/cli/command/origin.rb +11 -0
  21. data/lib/rfix/cli/command/setup.rb +11 -0
  22. data/lib/rfix/error.rb +5 -1
  23. data/lib/rfix/extension/offense.rb +79 -0
  24. data/lib/rfix/extension/pastel.rb +11 -0
  25. data/lib/rfix/extension/string.rb +12 -0
  26. data/lib/rfix/extension/strings.rb +9 -0
  27. data/lib/rfix/file.rb +6 -41
  28. data/lib/rfix/file/base.rb +73 -0
  29. data/lib/rfix/file/deleted.rb +17 -0
  30. data/lib/rfix/file/ignored.rb +17 -0
  31. data/lib/rfix/file/tracked.rb +42 -0
  32. data/lib/rfix/file/untracked.rb +20 -0
  33. data/lib/rfix/formatter.rb +125 -86
  34. data/lib/rfix/highlighter.rb +118 -0
  35. data/lib/rfix/indicator.rb +19 -0
  36. data/lib/rfix/log.rb +12 -121
  37. data/lib/rfix/rake/gemfile.rb +111 -0
  38. data/lib/rfix/rake/paths.rb +25 -23
  39. data/lib/rfix/rake/support.rb +72 -57
  40. data/lib/rfix/repository.rb +114 -164
  41. data/lib/rfix/types.rb +52 -0
  42. data/lib/rfix/version.rb +1 -1
  43. data/rfix.gemspec +28 -38
  44. data/vendor/dry-cli/CHANGELOG.md +191 -0
  45. data/vendor/dry-cli/CODEOWNERS +1 -0
  46. data/vendor/dry-cli/CODE_OF_CONDUCT.md +13 -0
  47. data/vendor/dry-cli/CONTRIBUTING.md +29 -0
  48. data/vendor/dry-cli/Gemfile +14 -0
  49. data/vendor/dry-cli/Gemfile.devtools +18 -0
  50. data/vendor/dry-cli/LICENSE +20 -0
  51. data/vendor/dry-cli/README.md +29 -0
  52. data/vendor/dry-cli/Rakefile +13 -0
  53. data/vendor/dry-cli/bin/console +15 -0
  54. data/vendor/dry-cli/bin/setup +8 -0
  55. data/vendor/dry-cli/changelog.yml +97 -0
  56. data/vendor/dry-cli/docsite/source/arguments.html.md +57 -0
  57. data/vendor/dry-cli/docsite/source/callbacks.html.md +51 -0
  58. data/vendor/dry-cli/docsite/source/commands-with-subcommands-and-params.md +86 -0
  59. data/vendor/dry-cli/docsite/source/commands.html.md +41 -0
  60. data/vendor/dry-cli/docsite/source/index.html.md +302 -0
  61. data/vendor/dry-cli/docsite/source/options.html.md +51 -0
  62. data/vendor/dry-cli/docsite/source/subcommands.html.md +38 -0
  63. data/vendor/dry-cli/docsite/source/variadic-arguments.html.md +45 -0
  64. data/vendor/dry-cli/dry-cli.gemspec +36 -0
  65. data/vendor/dry-cli/lib/dry/cli.rb +224 -0
  66. data/vendor/dry-cli/lib/dry/cli/banner.rb +135 -0
  67. data/vendor/dry-cli/lib/dry/cli/command.rb +387 -0
  68. data/vendor/dry-cli/lib/dry/cli/command_registry.rb +253 -0
  69. data/vendor/dry-cli/lib/dry/cli/errors.rb +37 -0
  70. data/vendor/dry-cli/lib/dry/cli/inflector.rb +17 -0
  71. data/vendor/dry-cli/lib/dry/cli/inline.rb +75 -0
  72. data/vendor/dry-cli/lib/dry/cli/option.rb +131 -0
  73. data/vendor/dry-cli/lib/dry/cli/parser.rb +138 -0
  74. data/vendor/dry-cli/lib/dry/cli/program_name.rb +21 -0
  75. data/vendor/dry-cli/lib/dry/cli/registry.rb +338 -0
  76. data/vendor/dry-cli/lib/dry/cli/usage.rb +94 -0
  77. data/vendor/dry-cli/lib/dry/cli/version.rb +8 -0
  78. data/vendor/dry-cli/project.yml +13 -0
  79. data/vendor/dry-cli/spec/integration/commands_spec.rb +14 -0
  80. data/vendor/dry-cli/spec/integration/inherited_commands_spec.rb +24 -0
  81. data/vendor/dry-cli/spec/integration/inline_spec.rb +43 -0
  82. data/vendor/dry-cli/spec/integration/processes_errors_spec.rb +29 -0
  83. data/vendor/dry-cli/spec/integration/rendering_spec.rb +31 -0
  84. data/vendor/dry-cli/spec/integration/single_command_spec.rb +81 -0
  85. data/vendor/dry-cli/spec/integration/subcommands_spec.rb +60 -0
  86. data/vendor/dry-cli/spec/integration/third_party_gems_spec.rb +18 -0
  87. data/vendor/dry-cli/spec/spec_helper.rb +15 -0
  88. data/vendor/dry-cli/spec/support/coverage.rb +15 -0
  89. data/vendor/dry-cli/spec/support/files.rb +13 -0
  90. data/vendor/dry-cli/spec/support/fixtures/based +65 -0
  91. data/vendor/dry-cli/spec/support/fixtures/baz +9 -0
  92. data/vendor/dry-cli/spec/support/fixtures/baz_command.rb +19 -0
  93. data/vendor/dry-cli/spec/support/fixtures/foo +588 -0
  94. data/vendor/dry-cli/spec/support/fixtures/infinites +31 -0
  95. data/vendor/dry-cli/spec/support/fixtures/inline +20 -0
  96. data/vendor/dry-cli/spec/support/fixtures/registry.rb +15 -0
  97. data/vendor/dry-cli/spec/support/fixtures/shared_commands.rb +596 -0
  98. data/vendor/dry-cli/spec/support/fixtures/with_block.rb +86 -0
  99. data/vendor/dry-cli/spec/support/fixtures/with_registry.rb +90 -0
  100. data/vendor/dry-cli/spec/support/fixtures/with_zero_arity_block.rb +87 -0
  101. data/vendor/dry-cli/spec/support/helpers.rb +37 -0
  102. data/vendor/dry-cli/spec/support/path.rb +24 -0
  103. data/vendor/dry-cli/spec/support/rspec.rb +26 -0
  104. data/vendor/dry-cli/spec/support/rspec_options.rb +16 -0
  105. data/vendor/dry-cli/spec/support/shared_examples/commands.rb +300 -0
  106. data/vendor/dry-cli/spec/support/shared_examples/inherited_commands.rb +197 -0
  107. data/vendor/dry-cli/spec/support/shared_examples/rendering.rb +181 -0
  108. data/vendor/dry-cli/spec/support/shared_examples/subcommands.rb +226 -0
  109. data/vendor/dry-cli/spec/support/shared_examples/third_party_gems.rb +49 -0
  110. data/vendor/dry-cli/spec/support/warnings.rb +10 -0
  111. data/vendor/dry-cli/spec/unit/dry/cli/cli_spec.rb +123 -0
  112. data/vendor/dry-cli/spec/unit/dry/cli/inflector_spec.rb +26 -0
  113. data/vendor/dry-cli/spec/unit/dry/cli/registry_spec.rb +78 -0
  114. data/vendor/dry-cli/spec/unit/dry/cli/version_spec.rb +7 -0
  115. data/vendor/strings-ansi/CHANGELOG.md +24 -0
  116. data/vendor/strings-ansi/CODE_OF_CONDUCT.md +74 -0
  117. data/vendor/strings-ansi/Gemfile +11 -0
  118. data/{LICENSE.txt → vendor/strings-ansi/LICENSE.txt} +1 -1
  119. data/vendor/strings-ansi/README.md +155 -0
  120. data/vendor/strings-ansi/Rakefile +8 -0
  121. data/vendor/strings-ansi/appveyor.yml +32 -0
  122. data/vendor/strings-ansi/bin/console +14 -0
  123. data/vendor/strings-ansi/bin/setup +8 -0
  124. data/vendor/strings-ansi/lib/strings-ansi.rb +1 -0
  125. data/vendor/strings-ansi/lib/strings/ansi.rb +84 -0
  126. data/vendor/strings-ansi/lib/strings/ansi/extensions.rb +23 -0
  127. data/vendor/strings-ansi/lib/strings/ansi/version.rb +7 -0
  128. data/vendor/strings-ansi/spec/fixtures/ansi_codes.yaml +194 -0
  129. data/vendor/strings-ansi/spec/spec_helper.rb +51 -0
  130. data/vendor/strings-ansi/spec/unit/ansi_spec.rb +15 -0
  131. data/vendor/strings-ansi/spec/unit/extensions_spec.rb +19 -0
  132. data/vendor/strings-ansi/spec/unit/only_ansi_spec.rb +36 -0
  133. data/vendor/strings-ansi/spec/unit/sanitize_spec.rb +53 -0
  134. data/vendor/strings-ansi/strings-ansi.gemspec +34 -0
  135. data/vendor/strings-ansi/tasks/console.rake +11 -0
  136. data/vendor/strings-ansi/tasks/coverage.rake +11 -0
  137. data/vendor/strings-ansi/tasks/spec.rake +29 -0
  138. metadata +274 -188
  139. data/.github/workflows/main.yml +0 -26
  140. data/.gitignore +0 -43
  141. data/.rspec +0 -2
  142. data/.rubocop.yml +0 -87
  143. data/.travis.yml +0 -35
  144. data/Gemfile +0 -2
  145. data/Gemfile.base +0 -14
  146. data/Gemfile.base.lock +0 -172
  147. data/Gemfile.lock +0 -188
  148. data/Guardfile +0 -16
  149. data/Makefile +0 -12
  150. data/README.md +0 -85
  151. data/Rakefile +0 -31
  152. data/bin/bundle +0 -114
  153. data/bin/console +0 -29
  154. data/bin/guard +0 -29
  155. data/bin/rake +0 -29
  156. data/bin/rfix +0 -29
  157. data/bin/rspec +0 -29
  158. data/bin/setup +0 -29
  159. data/ci/Gemfile.rubocop-0.80 +0 -2
  160. data/ci/Gemfile.rubocop-0.80.lock +0 -170
  161. data/ci/Gemfile.rubocop-0.81 +0 -2
  162. data/ci/Gemfile.rubocop-0.81.lock +0 -170
  163. data/ci/Gemfile.rubocop-0.82 +0 -2
  164. data/ci/Gemfile.rubocop-0.82.lock +0 -170
  165. data/ci/Gemfile.rubocop-0.83 +0 -2
  166. data/ci/Gemfile.rubocop-0.83.lock +0 -168
  167. data/ci/Gemfile.rubocop-0.84 +0 -2
  168. data/ci/Gemfile.rubocop-0.84.lock +0 -171
  169. data/ci/Gemfile.rubocop-0.85 +0 -2
  170. data/ci/Gemfile.rubocop-0.85.1 +0 -2
  171. data/ci/Gemfile.rubocop-0.85.1.lock +0 -173
  172. data/ci/Gemfile.rubocop-0.85.lock +0 -173
  173. data/lib/rfix/box.rb +0 -112
  174. data/lib/rfix/branches/base.rb +0 -15
  175. data/lib/rfix/branches/head.rb +0 -13
  176. data/lib/rfix/branches/main.rb +0 -28
  177. data/lib/rfix/branches/name.rb +0 -23
  178. data/lib/rfix/branches/reference.rb +0 -21
  179. data/lib/rfix/branches/upstream.rb +0 -13
  180. data/lib/rfix/cmd.rb +0 -39
  181. data/lib/rfix/commands/branch.rb +0 -15
  182. data/lib/rfix/commands/extensions/options.rb +0 -8
  183. data/lib/rfix/commands/help.rb +0 -7
  184. data/lib/rfix/commands/helper/args.rb +0 -141
  185. data/lib/rfix/commands/helper/help.rb +0 -6
  186. data/lib/rfix/commands/helper/loader.rb +0 -6
  187. data/lib/rfix/commands/helper/option.rb +0 -0
  188. data/lib/rfix/commands/helper/params.rb +0 -0
  189. data/lib/rfix/commands/helper/rubocop.rb +0 -17
  190. data/lib/rfix/commands/info.rb +0 -30
  191. data/lib/rfix/commands/lint.rb +0 -22
  192. data/lib/rfix/commands/local.rb +0 -12
  193. data/lib/rfix/commands/origin.rb +0 -19
  194. data/lib/rfix/commands/setup.rb +0 -29
  195. data/lib/rfix/commands/welcome.rb +0 -24
  196. data/lib/rfix/deleted.rb +0 -13
  197. data/lib/rfix/extensions/extensions.rb +0 -18
  198. data/lib/rfix/extensions/offense.rb +0 -78
  199. data/lib/rfix/extensions/string.rb +0 -8
  200. data/lib/rfix/file_cache.rb +0 -59
  201. data/lib/rfix/git_helper.rb +0 -59
  202. data/lib/rfix/indentation.rb +0 -39
  203. data/lib/rfix/loader/bundler.rb +0 -37
  204. data/lib/rfix/loader/env.rb +0 -33
  205. data/lib/rfix/loader/spec.rb +0 -41
  206. data/lib/rfix/no_file.rb +0 -13
  207. data/lib/rfix/rfix.rb +0 -34
  208. data/lib/rfix/tracked.rb +0 -72
  209. data/lib/rfix/tracked_file.rb +0 -16
  210. data/lib/rfix/untracked.rb +0 -13
  211. data/resources/ps.png +0 -0
  212. data/tasks/bump.rake +0 -11
  213. data/tasks/bundle.rake +0 -17
  214. data/tasks/complex.rake +0 -54
  215. data/tasks/execute.rake +0 -38
  216. data/tasks/libgit2.rake +0 -33
  217. data/tasks/simple.rake +0 -62
  218. data/tasks/travis.rake +0 -74
  219. 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