acquia_toolbelt 1.5.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +8 -8
  2. data/.ruby-version +1 -0
  3. data/Gemfile.lock +35 -0
  4. data/README.md +55 -27
  5. data/acquia_toolbelt.gemspec +2 -0
  6. data/bin/acquia +6 -565
  7. data/lib/acquia_toolbelt/cli.rb +102 -0
  8. data/lib/acquia_toolbelt/cli/api.rb +106 -0
  9. data/lib/acquia_toolbelt/cli/auth.rb +31 -0
  10. data/lib/acquia_toolbelt/cli/database.rb +208 -0
  11. data/lib/acquia_toolbelt/cli/deploy.rb +30 -0
  12. data/lib/acquia_toolbelt/cli/domain.rb +166 -0
  13. data/lib/acquia_toolbelt/cli/environment.rb +38 -0
  14. data/lib/acquia_toolbelt/cli/file.rb +23 -0
  15. data/lib/acquia_toolbelt/cli/server.rb +61 -0
  16. data/lib/acquia_toolbelt/cli/site.rb +28 -0
  17. data/lib/acquia_toolbelt/cli/ssh.rb +69 -0
  18. data/lib/acquia_toolbelt/cli/svn.rb +65 -0
  19. data/lib/acquia_toolbelt/cli/task.rb +71 -0
  20. data/lib/acquia_toolbelt/cli/ui.rb +29 -0
  21. data/lib/acquia_toolbelt/error.rb +4 -0
  22. data/lib/acquia_toolbelt/thor.rb +95 -0
  23. data/lib/acquia_toolbelt/version.rb +1 -1
  24. data/lib/vendor/thor/CHANGELOG.md +139 -0
  25. data/lib/vendor/thor/Gemfile +20 -0
  26. data/lib/vendor/thor/LICENSE.md +20 -0
  27. data/lib/vendor/thor/README.md +35 -0
  28. data/lib/vendor/thor/lib/thor.rb +474 -0
  29. data/lib/vendor/thor/lib/thor/actions.rb +318 -0
  30. data/lib/vendor/thor/lib/thor/actions/create_file.rb +105 -0
  31. data/lib/vendor/thor/lib/thor/actions/create_link.rb +60 -0
  32. data/lib/vendor/thor/lib/thor/actions/directory.rb +119 -0
  33. data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +137 -0
  34. data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +317 -0
  35. data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +109 -0
  36. data/lib/vendor/thor/lib/thor/base.rb +654 -0
  37. data/lib/vendor/thor/lib/thor/command.rb +136 -0
  38. data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +80 -0
  39. data/lib/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  40. data/lib/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
  41. data/lib/vendor/thor/lib/thor/error.rb +32 -0
  42. data/lib/vendor/thor/lib/thor/group.rb +282 -0
  43. data/lib/vendor/thor/lib/thor/invocation.rb +172 -0
  44. data/lib/vendor/thor/lib/thor/parser.rb +4 -0
  45. data/lib/vendor/thor/lib/thor/parser/argument.rb +74 -0
  46. data/lib/vendor/thor/lib/thor/parser/arguments.rb +171 -0
  47. data/lib/vendor/thor/lib/thor/parser/option.rb +121 -0
  48. data/lib/vendor/thor/lib/thor/parser/options.rb +218 -0
  49. data/lib/vendor/thor/lib/thor/rake_compat.rb +72 -0
  50. data/lib/vendor/thor/lib/thor/runner.rb +322 -0
  51. data/lib/vendor/thor/lib/thor/shell.rb +88 -0
  52. data/lib/vendor/thor/lib/thor/shell/basic.rb +422 -0
  53. data/lib/vendor/thor/lib/thor/shell/color.rb +148 -0
  54. data/lib/vendor/thor/lib/thor/shell/html.rb +127 -0
  55. data/lib/vendor/thor/lib/thor/util.rb +270 -0
  56. data/lib/vendor/thor/lib/thor/version.rb +3 -0
  57. data/lib/vendor/thor/spec/actions/create_file_spec.rb +170 -0
  58. data/lib/vendor/thor/spec/actions/create_link_spec.rb +95 -0
  59. data/lib/vendor/thor/spec/actions/directory_spec.rb +169 -0
  60. data/lib/vendor/thor/spec/actions/empty_directory_spec.rb +129 -0
  61. data/lib/vendor/thor/spec/actions/file_manipulation_spec.rb +382 -0
  62. data/lib/vendor/thor/spec/actions/inject_into_file_spec.rb +135 -0
  63. data/lib/vendor/thor/spec/actions_spec.rb +331 -0
  64. data/lib/vendor/thor/spec/base_spec.rb +291 -0
  65. data/lib/vendor/thor/spec/command_spec.rb +80 -0
  66. data/lib/vendor/thor/spec/core_ext/hash_with_indifferent_access_spec.rb +48 -0
  67. data/lib/vendor/thor/spec/core_ext/ordered_hash_spec.rb +115 -0
  68. data/lib/vendor/thor/spec/exit_condition_spec.rb +19 -0
  69. data/lib/vendor/thor/spec/fixtures/application.rb +2 -0
  70. data/lib/vendor/thor/spec/fixtures/app{1}/README +3 -0
  71. data/lib/vendor/thor/spec/fixtures/bundle/execute.rb +6 -0
  72. data/lib/vendor/thor/spec/fixtures/bundle/main.thor +1 -0
  73. data/lib/vendor/thor/spec/fixtures/command.thor +10 -0
  74. data/lib/vendor/thor/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  75. data/lib/vendor/thor/spec/fixtures/doc/COMMENTER +11 -0
  76. data/lib/vendor/thor/spec/fixtures/doc/README +3 -0
  77. data/lib/vendor/thor/spec/fixtures/doc/block_helper.rb +3 -0
  78. data/lib/vendor/thor/spec/fixtures/doc/components/.empty_directory +0 -0
  79. data/lib/vendor/thor/spec/fixtures/doc/config.rb +1 -0
  80. data/lib/vendor/thor/spec/fixtures/doc/config.yaml.tt +1 -0
  81. data/lib/vendor/thor/spec/fixtures/doc/excluding/%file_name%.rb.tt +1 -0
  82. data/lib/vendor/thor/spec/fixtures/enum.thor +10 -0
  83. data/lib/vendor/thor/spec/fixtures/group.thor +128 -0
  84. data/lib/vendor/thor/spec/fixtures/invoke.thor +118 -0
  85. data/lib/vendor/thor/spec/fixtures/path with spaces b/data/lib/vendor/thor/spec/fixtures/path with → spaces +0 -0
  86. data/lib/vendor/thor/spec/fixtures/preserve/script.sh +3 -0
  87. data/lib/vendor/thor/spec/fixtures/script.thor +220 -0
  88. data/lib/vendor/thor/spec/fixtures/subcommand.thor +17 -0
  89. data/lib/vendor/thor/spec/group_spec.rb +222 -0
  90. data/lib/vendor/thor/spec/helper.rb +67 -0
  91. data/lib/vendor/thor/spec/invocation_spec.rb +108 -0
  92. data/lib/vendor/thor/spec/parser/argument_spec.rb +53 -0
  93. data/lib/vendor/thor/spec/parser/arguments_spec.rb +66 -0
  94. data/lib/vendor/thor/spec/parser/option_spec.rb +202 -0
  95. data/lib/vendor/thor/spec/parser/options_spec.rb +400 -0
  96. data/lib/vendor/thor/spec/rake_compat_spec.rb +72 -0
  97. data/lib/vendor/thor/spec/register_spec.rb +197 -0
  98. data/lib/vendor/thor/spec/runner_spec.rb +241 -0
  99. data/lib/vendor/thor/spec/shell/basic_spec.rb +330 -0
  100. data/lib/vendor/thor/spec/shell/color_spec.rb +95 -0
  101. data/lib/vendor/thor/spec/shell/html_spec.rb +31 -0
  102. data/lib/vendor/thor/spec/shell_spec.rb +47 -0
  103. data/lib/vendor/thor/spec/subcommand_spec.rb +30 -0
  104. data/lib/vendor/thor/spec/thor_spec.rb +499 -0
  105. data/lib/vendor/thor/spec/util_spec.rb +196 -0
  106. data/lib/vendor/thor/thor.gemspec +24 -0
  107. data/spec/auth_spec.rb +8 -0
  108. data/spec_helper.rb +6 -0
  109. metadata +135 -4
  110. data/tests/example_test.rb +0 -5
@@ -0,0 +1,71 @@
1
+ module AcquiaToolbelt
2
+ class CLI
3
+ class Tasks < AcquiaToolbelt::Thor
4
+ no_tasks do
5
+ # Internal: Output information for a single task item.
6
+ def output_task_item(task)
7
+ completion_time = (task["completed"].to_i - task["started"].to_i) / 60
8
+ ui.say
9
+ ui.say "Task ID: #{task["id"].to_i}"
10
+ ui.say "Description: #{task["description"]}"
11
+ ui.say "Status: #{task["state"]}"
12
+
13
+ # If the completion time is greater then 0, output it in minutes
14
+ # otherwise just say it was less then a minute.
15
+ if completion_time > 0
16
+ ui.say "Compeletion time: About #{completion_time} minutes"
17
+ else
18
+ ui.say "Compeletion time: Less than 1 minute"
19
+ end
20
+
21
+ ui.say "Queue: #{task["queue"]}"
22
+ end
23
+ end
24
+
25
+ # Public: List all tasks from the Acquia tasks queue(s).
26
+ #
27
+ # Returns a task listing.
28
+ desc "list", "List all tasks."
29
+ method_option :queue, :type => :string, :aliases => %w(-q),
30
+ :desc => "Task queue to target."
31
+ method_option :count, :type => :string, :aliases => %w(-c),
32
+ :desc => "Limit the tasks returned."
33
+ def list
34
+ if options[:subscription]
35
+ subscription = options[:subscription]
36
+ else
37
+ subscription = AcquiaToolbelt::CLI::API.default_subscription
38
+ end
39
+
40
+ queue = options[:queue]
41
+ count = options[:count]
42
+
43
+ all_tasks = AcquiaToolbelt::CLI::API.request "sites/#{subscription}/tasks"
44
+ tasks = []
45
+
46
+ # Fetch a single queue from the tasks list if the queue parameter is set
47
+ # otherwise just add all the tasks.
48
+ if queue
49
+ all_tasks.each do |task|
50
+ if task["queue"] == queue
51
+ tasks << task
52
+ end
53
+ end
54
+ else
55
+ all_tasks.each do |task|
56
+ tasks << task
57
+ end
58
+ end
59
+
60
+ # If there is a count to return, restrict it to that required amount.
61
+ if count && tasks.any?
62
+ tasks = tasks.last(count.to_i)
63
+ end
64
+
65
+ tasks.each do |task|
66
+ output_task_item(task)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,29 @@
1
+ require "highline/import"
2
+ require "rainbow"
3
+
4
+ module AcquiaToolbelt
5
+ class CLI
6
+ class UI < Thor::Base.shell
7
+ # Internal: Used for outputting a pretty success message.
8
+ #
9
+ # Returns the string coloured and formatted.
10
+ def success(text)
11
+ puts "#{text}".foreground(:green)
12
+ end
13
+
14
+ # Internal: Used for outputting a pretty error message.
15
+ #
16
+ # Returns the string coloured and formatted.
17
+ def fail(text)
18
+ puts "#{text}".foreground(:red)
19
+ end
20
+
21
+ # Internal: Used for outputting a pretty info message.
22
+ #
23
+ # Returns the string coloured and formatted.
24
+ def info(text)
25
+ puts "#{text}".foreground(:cyan)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,4 @@
1
+ module AcquiaToolbelt
2
+ class Error < RuntimeError
3
+ end
4
+ end
@@ -0,0 +1,95 @@
1
+ $:.unshift(File.expand_path('../vendor/thor/lib/', File.dirname(__FILE__)))
2
+ require 'thor'
3
+
4
+ module AcquiaToolbelt
5
+ module UtilityMethods
6
+ protected
7
+
8
+ # Alias Thor's shell to UI instead.
9
+ def ui
10
+ shell
11
+ end
12
+ end
13
+
14
+ class Thor < ::Thor
15
+ include UtilityMethods
16
+ no_tasks do
17
+ def self.help(shell, subcommand = false)
18
+ list = printable_commands(true, subcommand).sort!{ |a,b| a[0] <=> b[0] }
19
+
20
+ shell.say "Type 'acquia [COMMAND] help' for more details on subcommands or to show example usage."
21
+
22
+ if @package_name
23
+ shell.say "#{@package_name} commands:"
24
+ else
25
+ shell.say
26
+ shell.say "Commands:"
27
+ end
28
+
29
+ shell.print_table(list, :indent => 2, :truncate => true)
30
+ shell.say unless subcommand
31
+ class_options_help(shell)
32
+ end
33
+
34
+ def self.printable_commands(all = true, subcommand = true)
35
+ (all ? all_commands : commands).map do |_, command|
36
+ # Don't show the hidden commands or the help commands.
37
+ next if command.hidden? || next if command.name.include? 'help'
38
+ item = []
39
+ item << banner(command, false, subcommand)
40
+ item << (command.description ? "# #{command.description.gsub(/\s+/m,' ')}" : "") unless command.description.empty?
41
+ item
42
+ end.compact
43
+ end
44
+
45
+ # Define a base for the commands.
46
+ def self.banner_base
47
+ "acquia"
48
+ end
49
+
50
+ def self.banner(task, task_help = false, subcommand = false)
51
+ subcommand_banner = to_s.split(/::/).map{|s| s.downcase}[2..-1]
52
+ subcommand_banner = if subcommand_banner.size > 0
53
+ subcommand_banner.join(" ")
54
+ else
55
+ nil
56
+ end
57
+
58
+ task = (task_help ? task.formatted_usage(self, false, subcommand) : task.name)
59
+ banner_base + " " + [subcommand_banner, task].compact.join(":")
60
+ end
61
+
62
+ def self.handle_no_task_error(task)
63
+ raise UndefinedTaskError, "Could not find command #{task.inspect}."
64
+ end
65
+
66
+ def self.subcommand(name, klass)
67
+ @@subcommand_class_for ||= {}
68
+ @@subcommand_class_for[name] = klass
69
+ super
70
+ end
71
+
72
+ def self.subcommand_class_for(name)
73
+ @@subcommand_class_for ||= {}
74
+ @@subcommand_class_for[name]
75
+ end
76
+
77
+ end
78
+
79
+ protected
80
+
81
+ def self.exit_on_failure?
82
+ true
83
+ end
84
+ end
85
+
86
+ # Patch handle_no_method_error? to work with rubinius' error text.
87
+ class ::Thor::Task
88
+ def handle_no_method_error?(instance, error, caller)
89
+ not_debugging?(instance) && (
90
+ error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ ||
91
+ error.message =~ /undefined method `#{name}' on an instance of #{Regexp.escape(instance.class.name)}/
92
+ )
93
+ end
94
+ end
95
+ end
@@ -1,3 +1,3 @@
1
1
  module AcquiaToolbelt
2
- VERSION = "1.5.1"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -0,0 +1,139 @@
1
+ ## 0.18.1, release 2013-03-30
2
+ * Revert regressions found in 0.18.0
3
+
4
+ ## 0.18.0, release 2013-03-26
5
+ * Remove rake2thor
6
+ * Only display colors if output medium supports colors
7
+ * Pass parent_options to subcommands
8
+ * Fix non-dash-prefixed aliases
9
+ * Make error messages more helpful
10
+ * Rename "task" to "command"
11
+ * Add the method to allow for custom package name
12
+
13
+ ## 0.17.0, release 2013-01-24
14
+ * Add better support for tasks that accept arbitrary additional arguments (e.g. things like `bundle exec`)
15
+ * Add #stop_on_unknown_option!
16
+ * Only strip from stdin.gets if it wasn't ended with EOF
17
+ * Allow "send" as a task name
18
+ * Allow passing options as arguments after "--"
19
+ * Autoload Thor::Group
20
+
21
+ ## 0.16.0, release 2012-08-14
22
+ * Add enum to string arguments
23
+
24
+ ## 0.15.4, release 2012-06-29
25
+ * Fix regression when destination root contains reserved regexp characters
26
+
27
+ ## 0.15.3, release 2012-06-18
28
+ * Support strict_args_position! for backwards compatibility
29
+ * Escape Dir glob characters in paths
30
+
31
+ ## 0.15.2, released 2012-05-07
32
+ * Added print_in_columns
33
+ * Exposed terminal_width as a public API
34
+
35
+ ## 0.15.1, release 2012-05-06
36
+ * Fix Ruby 1.8 truncation bug with unicode chars
37
+ * Fix shell delegate methods to pass their block
38
+ * Don't output trailing spaces when printing the last column in a table
39
+
40
+ ## 0.15, released 2012-04-29
41
+ * Alias method_options to options
42
+ * Refactor say to allow multiple colors
43
+ * Exposed error as a public API
44
+ * Exposed file_collision as a public API
45
+ * Exposed print_wrapped as a public API
46
+ * Exposed set_color as a public API
47
+ * Fix number-formatting bugs in print_table
48
+ * Fix "indent" typo in print_table
49
+ * Fix Errno::EPIPE when piping tasks to `head`
50
+ * More friendly error messages
51
+
52
+ ## 0.14, released 2010-07-25
53
+ * Added CreateLink class and #link_file method
54
+ * Made Thor::Actions#run use system as default method for system calls
55
+ * Allow use of private methods from superclass as tasks
56
+ * Added mute(&block) method which allows to run block without any output
57
+ * Removed config[:pretend]
58
+ * Enabled underscores for command line switches
59
+ * Added Thor::Base.basename which is used by both Thor.banner and Thor::Group.banner
60
+ * Deprecated invoke() without arguments
61
+ * Added :only and :except to check_unknown_options
62
+
63
+ ## 0.13, released 2010-02-03
64
+ * Added :lazy_default which is only triggered if a switch is given
65
+ * Added Thor::Shell::HTML
66
+ * Added subcommands
67
+ * Decoupled Thor::Group and Thor, so it's easier to vendor
68
+ * Added check_unknown_options! in case you want error messages to be raised in valid switches
69
+ * run(command) should return the results of command
70
+
71
+ ## 0.12, released 2010-01-02
72
+ * Methods generated by attr_* are automatically not marked as tasks
73
+ * inject_into_file does not add the same content twice, unless :force is set
74
+ * Removed rr in favor to rspec mock framework
75
+ * Improved output for thor -T
76
+ * [#7] Do not force white color on status
77
+ * [#8] Yield a block with the filename on directory
78
+
79
+ ## 0.11, released 2009-07-01
80
+ * Added a rake compatibility layer. It allows you to use spec and rdoc tasks on
81
+ Thor classes.
82
+ * BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore
83
+ since it may cause wrong behavior in the invocation system.
84
+ * thor help now show information about any class/task. All those calls are
85
+ possible:
86
+
87
+ thor help describe
88
+ thor help describe:amazing
89
+ Or even with default namespaces:
90
+
91
+ thor help :spec
92
+ * Thor::Runner now invokes the default task if none is supplied:
93
+
94
+ thor describe # invokes the default task, usually help
95
+ * Thor::Runner now works with mappings:
96
+
97
+ thor describe -h
98
+ * Added some documentation and code refactoring.
99
+
100
+ ## 0.9.8, released 2008-10-20
101
+ * Fixed some tiny issues that were introduced lately.
102
+
103
+ ## 0.9.7, released 2008-10-13
104
+ * Setting global method options on the initialize method works as expected:
105
+ All other tasks will accept these global options in addition to their own.
106
+ * Added 'group' notion to Thor task sets (class Thor); by default all tasks
107
+ are in the 'standard' group. Running 'thor -T' will only show the standard
108
+ tasks - adding --all will show all tasks. You can also filter on a specific
109
+ group using the --group option: thor -T --group advanced
110
+
111
+ ## 0.9.6, released 2008-09-13
112
+ * Generic improvements
113
+
114
+ ## 0.9.5, released 2008-08-27
115
+ * Improve Windows compatibility
116
+ * Update (incorrect) README and task.thor sample file
117
+ * Options hash is now frozen (once returned)
118
+ * Allow magic predicates on options object. For instance: `options.force?`
119
+ * Add support for :numeric type
120
+ * BACKWARDS INCOMPATIBLE: Refactor Thor::Options. You cannot access shorthand forms in options hash anymore (for instance, options[:f])
121
+ * Allow specifying optional args with default values: method_options(:user => "mislav")
122
+ * Don't write options for nil or false values. This allows, for example, turning color off when running specs.
123
+ * Exit with the status of the spec command to help CI stuff out some.
124
+
125
+ ## 0.9.4, released 2008-08-13
126
+ * Try to add Windows compatibility.
127
+ * BACKWARDS INCOMPATIBLE: options hash is now accessed as a property in your class and is not passed as last argument anymore
128
+ * Allow options at the beginning of the argument list as well as the end.
129
+ * Make options available with symbol keys in addition to string keys.
130
+ * Allow true to be passed to Thor#method_options to denote a boolean option.
131
+ * If loading a thor file fails, don't give up, just print a warning and keep going.
132
+ * Make sure that we re-raise errors if they happened further down the pipe than we care about.
133
+ * Only delete the old file on updating when the installation of the new one is a success
134
+ * Make it Ruby 1.8.5 compatible.
135
+ * Don't raise an error if a boolean switch is defined multiple times.
136
+ * Thor::Options now doesn't parse through things that look like options but aren't.
137
+ * Add URI detection to install task, and make sure we don't append ".thor" to URIs
138
+ * Add rake2thor to the gem binfiles.
139
+ * Make sure local Thorfiles override system-wide ones.
@@ -0,0 +1,20 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rake', '>= 0.9'
4
+ gem 'rdoc', '>= 3.9'
5
+
6
+ group :development do
7
+ gem 'pry'
8
+ gem 'pry-debugger', :platforms => :mri_19
9
+ end
10
+
11
+ group :test do
12
+ gem 'childlabor'
13
+ gem 'coveralls', '>=0.5.7', :require => false
14
+ gem 'fakeweb', '>= 1.3'
15
+ gem 'rspec', '>= 2.14'
16
+ gem 'rspec-mocks', '>= 2.12.2'
17
+ gem 'simplecov', :require => false
18
+ end
19
+
20
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Yehuda Katz, Eric Hodel, et al.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,35 @@
1
+ [![Gem Version](https://badge.fury.io/rb/thor.png)](https://rubygems.org/gems/thor)
2
+ [![Build Status](https://secure.travis-ci.org/erikhuda/thor.png?branch=master)](http://travis-ci.org/erikhuda/thor)
3
+ [![Dependency Status](https://gemnasium.com/erikhuda/thor.png?travis)](https://gemnasium.com/erikhuda/thor)
4
+ [![Code Climate](https://codeclimate.com/github/erikhuda/thor.png)](https://codeclimate.com/github/erikhuda/thor)
5
+ [![Coverage Status](https://coveralls.io/repos/erikhuda/thor/badge.png?branch=master)](https://coveralls.io/r/erikhuda/thor)
6
+
7
+ Thor
8
+ ====
9
+
10
+ Description
11
+ -----------
12
+ Thor is a simple and efficient tool for building self-documenting command line
13
+ utilities. It removes the pain of parsing command line options, writing
14
+ "USAGE:" banners, and can also be used as an alternative to the [Rake][rake]
15
+ build tool. The syntax is Rake-like, so it should be familiar to most Rake
16
+ users.
17
+
18
+ [rake]: https://github.com/jimweirich/rake
19
+
20
+ Installation
21
+ ------------
22
+ gem install thor
23
+
24
+ Usage and documentation
25
+ -----------------------
26
+ Please see the [wiki][] for basic usage and other documentation on using Thor. You can also checkout the [official homepage][homepage].
27
+
28
+ [wiki]: https://github.com/erikhuda/thor/wiki
29
+ [homepage]: http://whatisthor.com/
30
+
31
+ License
32
+ -------
33
+ Released under the MIT License. See the [LICENSE][] file for further details.
34
+
35
+ [license]: LICENSE.md
@@ -0,0 +1,474 @@
1
+ require 'set'
2
+ require 'thor/base'
3
+
4
+ class Thor
5
+ class << self
6
+ # Allows for custom "Command" package naming.
7
+ #
8
+ # === Parameters
9
+ # name<String>
10
+ # options<Hash>
11
+ #
12
+ def package_name(name, options={})
13
+ @package_name = name.nil? || name == '' ? nil : name
14
+ end
15
+
16
+ # Sets the default command when thor is executed without an explicit command to be called.
17
+ #
18
+ # ==== Parameters
19
+ # meth<Symbol>:: name of the default command
20
+ #
21
+ def default_command(meth=nil)
22
+ @default_command = case meth
23
+ when :none
24
+ 'help'
25
+ when nil
26
+ @default_command || from_superclass(:default_command, 'help')
27
+ else
28
+ meth.to_s
29
+ end
30
+ end
31
+ alias default_task default_command
32
+
33
+ # Registers another Thor subclass as a command.
34
+ #
35
+ # ==== Parameters
36
+ # klass<Class>:: Thor subclass to register
37
+ # command<String>:: Subcommand name to use
38
+ # usage<String>:: Short usage for the subcommand
39
+ # description<String>:: Description for the subcommand
40
+ def register(klass, subcommand_name, usage, description, options={})
41
+ if klass <= Thor::Group
42
+ desc usage, description, options
43
+ define_method(subcommand_name) { |*args| invoke(klass, args) }
44
+ else
45
+ desc usage, description, options
46
+ subcommand subcommand_name, klass
47
+ end
48
+ end
49
+
50
+ # Defines the usage and the description of the next command.
51
+ #
52
+ # ==== Parameters
53
+ # usage<String>
54
+ # description<String>
55
+ # options<String>
56
+ #
57
+ def desc(usage, description, options={})
58
+ if options[:for]
59
+ command = find_and_refresh_command(options[:for])
60
+ command.usage = usage if usage
61
+ command.description = description if description
62
+ else
63
+ @usage, @desc, @hide = usage, description, options[:hide] || false
64
+ end
65
+ end
66
+
67
+ # Defines the long description of the next command.
68
+ #
69
+ # ==== Parameters
70
+ # long description<String>
71
+ #
72
+ def long_desc(long_description, options={})
73
+ if options[:for]
74
+ command = find_and_refresh_command(options[:for])
75
+ command.long_description = long_description if long_description
76
+ else
77
+ @long_desc = long_description
78
+ end
79
+ end
80
+
81
+ # Maps an input to a command. If you define:
82
+ #
83
+ # map "-T" => "list"
84
+ #
85
+ # Running:
86
+ #
87
+ # thor -T
88
+ #
89
+ # Will invoke the list command.
90
+ #
91
+ # ==== Parameters
92
+ # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
93
+ #
94
+ def map(mappings=nil)
95
+ @map ||= from_superclass(:map, {})
96
+
97
+ if mappings
98
+ mappings.each do |key, value|
99
+ if key.respond_to?(:each)
100
+ key.each {|subkey| @map[subkey] = value}
101
+ else
102
+ @map[key] = value
103
+ end
104
+ end
105
+ end
106
+
107
+ @map
108
+ end
109
+
110
+ # Declares the options for the next command to be declared.
111
+ #
112
+ # ==== Parameters
113
+ # Hash[Symbol => Object]:: The hash key is the name of the option and the value
114
+ # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric
115
+ # or :required (string). If you give a value, the type of the value is used.
116
+ #
117
+ def method_options(options=nil)
118
+ @method_options ||= {}
119
+ build_options(options, @method_options) if options
120
+ @method_options
121
+ end
122
+
123
+ alias options method_options
124
+
125
+ # Adds an option to the set of method options. If :for is given as option,
126
+ # it allows you to change the options from a previous defined command.
127
+ #
128
+ # def previous_command
129
+ # # magic
130
+ # end
131
+ #
132
+ # method_option :foo => :bar, :for => :previous_command
133
+ #
134
+ # def next_command
135
+ # # magic
136
+ # end
137
+ #
138
+ # ==== Parameters
139
+ # name<Symbol>:: The name of the argument.
140
+ # options<Hash>:: Described below.
141
+ #
142
+ # ==== Options
143
+ # :desc - Description for the argument.
144
+ # :required - If the argument is required or not.
145
+ # :default - Default value for this argument. It cannot be required and have default values.
146
+ # :aliases - Aliases for this option.
147
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
148
+ # :banner - String to show on usage notes.
149
+ # :hide - If you want to hide this option from the help.
150
+ #
151
+ def method_option(name, options={})
152
+ scope = if options[:for]
153
+ find_and_refresh_command(options[:for]).options
154
+ else
155
+ method_options
156
+ end
157
+
158
+ build_option(name, options, scope)
159
+ end
160
+ alias option method_option
161
+
162
+ # Prints help information for the given command.
163
+ #
164
+ # ==== Parameters
165
+ # shell<Thor::Shell>
166
+ # command_name<String>
167
+ #
168
+ def command_help(shell, command_name)
169
+ meth = normalize_command_name(command_name)
170
+ command = all_commands[meth]
171
+ handle_no_command_error(meth) unless command
172
+
173
+ shell.say "Usage:"
174
+ shell.say " #{banner(command)}"
175
+ shell.say
176
+ class_options_help(shell, nil => command.options.map { |_, o| o })
177
+ if command.long_description
178
+ shell.say "Description:"
179
+ shell.print_wrapped(command.long_description, :indent => 2)
180
+ else
181
+ shell.say command.description
182
+ end
183
+ end
184
+ alias task_help command_help
185
+
186
+ # Prints help information for this class.
187
+ #
188
+ # ==== Parameters
189
+ # shell<Thor::Shell>
190
+ #
191
+ def help(shell, subcommand = false)
192
+ list = printable_commands(true, subcommand)
193
+ Thor::Util.thor_classes_in(self).each do |klass|
194
+ list += klass.printable_commands(false)
195
+ end
196
+ list.sort!{ |a,b| a[0] <=> b[0] }
197
+
198
+ if @package_name
199
+ shell.say "#{@package_name} commands:"
200
+ else
201
+ shell.say
202
+ shell.say "Commands:"
203
+ end
204
+
205
+ shell.print_table(list, :indent => 2, :truncate => true)
206
+ shell.say
207
+ class_options_help(shell)
208
+ end
209
+
210
+ # Returns commands ready to be printed.
211
+ def printable_commands(all = true, subcommand = false)
212
+ (all ? all_commands : commands).map do |_, command|
213
+ next if command.hidden?
214
+ item = []
215
+ item << banner(command, false, subcommand)
216
+ item << (command.description ? "# #{command.description.gsub(/\s+/m,' ')}" : "")
217
+ item
218
+ end.compact
219
+ end
220
+ alias printable_tasks printable_commands
221
+
222
+ def subcommands
223
+ @subcommands ||= from_superclass(:subcommands, [])
224
+ end
225
+ alias subtasks subcommands
226
+
227
+ def subcommand(subcommand, subcommand_class)
228
+ self.subcommands << subcommand.to_s
229
+ subcommand_class.subcommand_help subcommand
230
+
231
+ define_method(subcommand) do |*args|
232
+ args, opts = Thor::Arguments.split(args)
233
+ invoke subcommand_class, args, opts, :invoked_via_subcommand => true, :class_options => options
234
+ end
235
+ end
236
+ alias subtask subcommand
237
+
238
+ # Extend check unknown options to accept a hash of conditions.
239
+ #
240
+ # === Parameters
241
+ # options<Hash>: A hash containing :only and/or :except keys
242
+ def check_unknown_options!(options={})
243
+ @check_unknown_options ||= Hash.new
244
+ options.each do |key, value|
245
+ if value
246
+ @check_unknown_options[key] = Array(value)
247
+ else
248
+ @check_unknown_options.delete(key)
249
+ end
250
+ end
251
+ @check_unknown_options
252
+ end
253
+
254
+ # Overwrite check_unknown_options? to take subcommands and options into account.
255
+ def check_unknown_options?(config) #:nodoc:
256
+ options = check_unknown_options
257
+ return false unless options
258
+
259
+ command = config[:current_command]
260
+ return true unless command
261
+
262
+ name = command.name
263
+
264
+ if subcommands.include?(name)
265
+ false
266
+ elsif options[:except]
267
+ !options[:except].include?(name.to_sym)
268
+ elsif options[:only]
269
+ options[:only].include?(name.to_sym)
270
+ else
271
+ true
272
+ end
273
+ end
274
+
275
+ # Stop parsing of options as soon as an unknown option or a regular
276
+ # argument is encountered. All remaining arguments are passed to the command.
277
+ # This is useful if you have a command that can receive arbitrary additional
278
+ # options, and where those additional options should not be handled by
279
+ # Thor.
280
+ #
281
+ # ==== Example
282
+ #
283
+ # To better understand how this is useful, let's consider a command that calls
284
+ # an external command. A user may want to pass arbitrary options and
285
+ # arguments to that command. The command itself also accepts some options,
286
+ # which should be handled by Thor.
287
+ #
288
+ # class_option "verbose", :type => :boolean
289
+ # stop_on_unknown_option! :exec
290
+ # check_unknown_options! :except => :exec
291
+ #
292
+ # desc "exec", "Run a shell command"
293
+ # def exec(*args)
294
+ # puts "diagnostic output" if options[:verbose]
295
+ # Kernel.exec(*args)
296
+ # end
297
+ #
298
+ # Here +exec+ can be called with +--verbose+ to get diagnostic output,
299
+ # e.g.:
300
+ #
301
+ # $ thor exec --verbose echo foo
302
+ # diagnostic output
303
+ # foo
304
+ #
305
+ # But if +--verbose+ is given after +echo+, it is passed to +echo+ instead:
306
+ #
307
+ # $ thor exec echo --verbose foo
308
+ # --verbose foo
309
+ #
310
+ # ==== Parameters
311
+ # Symbol ...:: A list of commands that should be affected.
312
+ def stop_on_unknown_option!(*command_names)
313
+ @stop_on_unknown_option ||= Set.new
314
+ @stop_on_unknown_option.merge(command_names)
315
+ end
316
+
317
+ def stop_on_unknown_option?(command) #:nodoc:
318
+ command && !@stop_on_unknown_option.nil? && @stop_on_unknown_option.include?(command.name.to_sym)
319
+ end
320
+
321
+ protected
322
+
323
+ # The method responsible for dispatching given the args.
324
+ def dispatch(meth, given_args, given_opts, config) #:nodoc:
325
+ # There is an edge case when dispatching from a subcommand.
326
+ # A problem occurs invoking the default command. This case occurs
327
+ # when arguments are passed and a default command is defined, and
328
+ # the first given_args does not match the default command.
329
+ # Thor use "help" by default so we skip that case.
330
+ # Note the call to retrieve_command_name. It's called with
331
+ # given_args.dup since that method calls args.shift. Then lookup
332
+ # the command normally. If the first item in given_args is not
333
+ # a command then use the default command. The given_args will be
334
+ # intact later since dup was used.
335
+ if config[:invoked_via_subcommand] && given_args.size >= 1 && default_command != "help" && given_args.first != default_command
336
+ meth ||= retrieve_command_name(given_args.dup)
337
+ command = all_commands[normalize_command_name(meth)]
338
+ command ||= all_commands[normalize_command_name(default_command)]
339
+ else
340
+ meth ||= retrieve_command_name(given_args)
341
+ command = all_commands[normalize_command_name(meth)]
342
+ end
343
+
344
+ if command
345
+ args, opts = Thor::Options.split(given_args)
346
+ if stop_on_unknown_option?(command) && !args.empty?
347
+ # given_args starts with a non-option, so we treat everything as
348
+ # ordinary arguments
349
+ args.concat opts
350
+ opts.clear
351
+ end
352
+ else
353
+ args, opts = given_args, nil
354
+ command = Thor::DynamicCommand.new(meth)
355
+ end
356
+
357
+ opts = given_opts || opts || []
358
+ config.merge!(:current_command => command, :command_options => command.options)
359
+
360
+ instance = new(args, opts, config)
361
+ yield instance if block_given?
362
+ args = instance.args
363
+ trailing = args[Range.new(arguments.size, -1)]
364
+ instance.invoke_command(command, trailing || [])
365
+ end
366
+
367
+ # The banner for this class. You can customize it if you are invoking the
368
+ # thor class by another ways which is not the Thor::Runner. It receives
369
+ # the command that is going to be invoked and a boolean which indicates if
370
+ # the namespace should be displayed as arguments.
371
+ #
372
+ def banner(command, namespace = nil, subcommand = false)
373
+ "#{basename} #{command.formatted_usage(self, $thor_runner, subcommand)}"
374
+ end
375
+
376
+ def baseclass #:nodoc:
377
+ Thor
378
+ end
379
+
380
+ def create_command(meth) #:nodoc:
381
+ if @usage && @desc
382
+ base_class = @hide ? Thor::HiddenCommand : Thor::Command
383
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
384
+ @usage, @desc, @long_desc, @method_options, @hide = nil
385
+ true
386
+ elsif self.all_commands[meth] || meth == "method_missing"
387
+ true
388
+ else
389
+ puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " <<
390
+ "Call desc if you want this method to be available as command or declare it inside a " <<
391
+ "no_commands{} block. Invoked from #{caller[1].inspect}."
392
+ false
393
+ end
394
+ end
395
+ alias create_task create_command
396
+
397
+ def initialize_added #:nodoc:
398
+ class_options.merge!(method_options)
399
+ @method_options = nil
400
+ end
401
+
402
+ # Retrieve the command name from given args.
403
+ def retrieve_command_name(args) #:nodoc:
404
+ meth = args.first.to_s unless args.empty?
405
+ if meth && (map[meth] || meth !~ /^\-/)
406
+ args.shift
407
+ else
408
+ nil
409
+ end
410
+ end
411
+ alias retrieve_task_name retrieve_command_name
412
+
413
+ # receives a (possibly nil) command name and returns a name that is in
414
+ # the commands hash. In addition to normalizing aliases, this logic
415
+ # will determine if a shortened command is an unambiguous substring of
416
+ # a command or alias.
417
+ #
418
+ # +normalize_command_name+ also converts names like +animal-prison+
419
+ # into +animal_prison+.
420
+ def normalize_command_name(meth) #:nodoc:
421
+ return default_command.to_s.gsub('-', '_') unless meth
422
+
423
+ possibilities = find_command_possibilities(meth)
424
+ if possibilities.size > 1
425
+ raise AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]"
426
+ elsif possibilities.size < 1
427
+ meth = meth || default_command
428
+ elsif map[meth]
429
+ meth = map[meth]
430
+ else
431
+ meth = possibilities.first
432
+ end
433
+
434
+ meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
435
+ end
436
+ alias normalize_task_name normalize_command_name
437
+
438
+ # this is the logic that takes the command name passed in by the user
439
+ # and determines whether it is an unambiguous substrings of a command or
440
+ # alias name.
441
+ def find_command_possibilities(meth)
442
+ len = meth.to_s.length
443
+ possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort
444
+ unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
445
+
446
+ if possibilities.include?(meth)
447
+ [meth]
448
+ elsif unique_possibilities.size == 1
449
+ unique_possibilities
450
+ else
451
+ possibilities
452
+ end
453
+ end
454
+ alias find_task_possibilities find_command_possibilities
455
+
456
+ def subcommand_help(cmd)
457
+ desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
458
+ class_eval <<-RUBY
459
+ def help(command = nil, subcommand = true); super; end
460
+ RUBY
461
+ end
462
+ alias subtask_help subcommand_help
463
+
464
+ end
465
+
466
+ include Thor::Base
467
+
468
+ map HELP_MAPPINGS => :help
469
+
470
+ desc "help [COMMAND]", "Describe available commands or one specific command"
471
+ def help(command = nil, subcommand = false)
472
+ command ? self.class.command_help(shell, command) : self.class.help(shell, subcommand)
473
+ end
474
+ end