bbcloud 0.11.2 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (198) hide show
  1. data/.gitignore +3 -2
  2. data/Gemfile +3 -0
  3. data/README +11 -1
  4. data/README.rdoc +11 -1
  5. data/Rakefile +12 -0
  6. data/bbcloud.gemspec +10 -10
  7. data/bin/brightbox-accounts +7 -2
  8. data/bin/brightbox-cloudips +7 -2
  9. data/bin/brightbox-config +7 -2
  10. data/bin/brightbox-images +7 -2
  11. data/bin/brightbox-lbs +7 -2
  12. data/bin/brightbox-servers +7 -2
  13. data/bin/brightbox-types +7 -2
  14. data/bin/brightbox-users +7 -2
  15. data/bin/brightbox-zones +7 -2
  16. data/lib/bbcloud.rb +43 -0
  17. data/lib/bbcloud/accounts.rb +5 -3
  18. data/lib/bbcloud/command_generator.rb +50 -0
  19. data/lib/bbcloud/commands/accounts-list.rb +13 -11
  20. data/lib/bbcloud/commands/accounts-reset-ftp-password.rb +26 -23
  21. data/lib/bbcloud/commands/accounts-show.rb +20 -16
  22. data/lib/bbcloud/commands/cloudips-create.rb +16 -14
  23. data/lib/bbcloud/commands/cloudips-destroy.rb +29 -26
  24. data/lib/bbcloud/commands/cloudips-list.rb +13 -11
  25. data/lib/bbcloud/commands/cloudips-map.rb +48 -46
  26. data/lib/bbcloud/commands/cloudips-show.rb +15 -12
  27. data/lib/bbcloud/commands/cloudips-unmap.rb +28 -25
  28. data/lib/bbcloud/commands/config-client-add.rb +33 -31
  29. data/lib/bbcloud/commands/config-client-default.rb +18 -16
  30. data/lib/bbcloud/commands/config-client-list.rb +19 -16
  31. data/lib/bbcloud/commands/config-client-remove.rb +18 -16
  32. data/lib/bbcloud/commands/images-destroy.rb +18 -16
  33. data/lib/bbcloud/commands/images-list.rb +20 -18
  34. data/lib/bbcloud/commands/images-register.rb +21 -19
  35. data/lib/bbcloud/commands/images-show.rb +17 -15
  36. data/lib/bbcloud/commands/lbs-add-nodes.rb +15 -13
  37. data/lib/bbcloud/commands/lbs-create.rb +65 -63
  38. data/lib/bbcloud/commands/lbs-destroy.rb +13 -11
  39. data/lib/bbcloud/commands/lbs-list.rb +13 -11
  40. data/lib/bbcloud/commands/lbs-remove-nodes.rb +15 -13
  41. data/lib/bbcloud/commands/lbs-show.rb +15 -13
  42. data/lib/bbcloud/commands/lbs-update.rb +59 -57
  43. data/lib/bbcloud/commands/servers-activate-cloud.rb +18 -16
  44. data/lib/bbcloud/commands/servers-create.rb +80 -77
  45. data/lib/bbcloud/commands/servers-destroy.rb +17 -15
  46. data/lib/bbcloud/commands/servers-list.rb +14 -14
  47. data/lib/bbcloud/commands/servers-show.rb +39 -37
  48. data/lib/bbcloud/commands/servers-shutdown.rb +14 -12
  49. data/lib/bbcloud/commands/servers-snapshot.rb +14 -12
  50. data/lib/bbcloud/commands/servers-start.rb +15 -13
  51. data/lib/bbcloud/commands/servers-stop.rb +14 -12
  52. data/lib/bbcloud/commands/types-list.rb +13 -11
  53. data/lib/bbcloud/commands/types-show.rb +18 -16
  54. data/lib/bbcloud/commands/users-list.rb +13 -11
  55. data/lib/bbcloud/commands/users-show.rb +17 -15
  56. data/lib/bbcloud/commands/users-update.rb +27 -25
  57. data/lib/bbcloud/commands/zones-list.rb +13 -11
  58. data/lib/bbcloud/config.rb +125 -111
  59. data/lib/bbcloud/error_parser.rb +34 -0
  60. data/lib/bbcloud/fog_extensions.rb +19 -0
  61. data/lib/bbcloud/gli_global_hooks.rb +56 -0
  62. data/lib/bbcloud/logging.rb +40 -0
  63. data/lib/bbcloud/ruby_core_ext.rb +9 -0
  64. data/lib/bbcloud/servers.rb +7 -2
  65. data/lib/bbcloud/tables.rb +78 -73
  66. data/lib/bbcloud/vendor/gli/.gitignore +10 -0
  67. data/lib/bbcloud/vendor/gli/.rvmrc +1 -0
  68. data/lib/bbcloud/vendor/gli/Gemfile +5 -0
  69. data/lib/bbcloud/vendor/gli/LICENSE.txt +201 -0
  70. data/lib/bbcloud/vendor/gli/README.rdoc +54 -0
  71. data/lib/bbcloud/vendor/gli/Rakefile +84 -0
  72. data/lib/bbcloud/vendor/gli/bin/gli +72 -0
  73. data/lib/bbcloud/vendor/gli/bin/report_on_rake_results +10 -0
  74. data/lib/bbcloud/vendor/gli/bin/test_all_rubies.sh +2 -0
  75. data/lib/bbcloud/vendor/gli/features/gli_executable.feature +88 -0
  76. data/lib/bbcloud/vendor/gli/features/gli_init.feature +122 -0
  77. data/lib/bbcloud/vendor/gli/features/step_definitions/gli_executable_steps.rb +12 -0
  78. data/lib/bbcloud/vendor/gli/features/step_definitions/gli_init_steps.rb +4 -0
  79. data/lib/bbcloud/vendor/gli/features/support/env.rb +21 -0
  80. data/lib/bbcloud/vendor/gli/gli.cheat +80 -0
  81. data/lib/bbcloud/vendor/gli/gli.gemspec +46 -0
  82. data/lib/bbcloud/vendor/gli/gli.rdoc +51 -0
  83. data/lib/bbcloud/vendor/gli/lib/gli.rb +560 -0
  84. data/lib/bbcloud/vendor/gli/lib/gli/command.rb +124 -0
  85. data/lib/bbcloud/vendor/gli/lib/gli/command_line_token.rb +58 -0
  86. data/lib/bbcloud/vendor/gli/lib/gli/copy_options_to_aliases.rb +33 -0
  87. data/lib/bbcloud/vendor/gli/lib/gli/exceptions.rb +45 -0
  88. data/lib/bbcloud/vendor/gli/lib/gli/flag.rb +67 -0
  89. data/lib/bbcloud/vendor/gli/lib/gli/options.rb +19 -0
  90. data/lib/bbcloud/vendor/gli/lib/gli/switch.rb +63 -0
  91. data/lib/bbcloud/vendor/gli/lib/gli/terminal.rb +79 -0
  92. data/lib/bbcloud/vendor/gli/lib/gli_version.rb +3 -0
  93. data/lib/bbcloud/vendor/gli/lib/support/help.rb +180 -0
  94. data/lib/bbcloud/vendor/gli/lib/support/initconfig.rb +34 -0
  95. data/lib/bbcloud/vendor/gli/lib/support/rdoc.rb +119 -0
  96. data/lib/bbcloud/vendor/gli/lib/support/scaffold.rb +284 -0
  97. data/lib/bbcloud/vendor/gli/test/config.yaml +9 -0
  98. data/lib/bbcloud/vendor/gli/test/gli.reek +116 -0
  99. data/lib/bbcloud/vendor/gli/test/roodi.yaml +9 -0
  100. data/lib/bbcloud/vendor/gli/test/tc_command.rb +329 -0
  101. data/lib/bbcloud/vendor/gli/test/tc_flag.rb +67 -0
  102. data/lib/bbcloud/vendor/gli/test/tc_gli.rb +429 -0
  103. data/lib/bbcloud/vendor/gli/test/tc_options.rb +31 -0
  104. data/lib/bbcloud/vendor/gli/test/tc_parsing.rb +279 -0
  105. data/lib/bbcloud/vendor/gli/test/tc_switch.rb +80 -0
  106. data/lib/bbcloud/vendor/gli/test/tc_terminal.rb +91 -0
  107. data/lib/bbcloud/version.rb +1 -1
  108. data/pkg/bbcloud-0.12.0.gem +0 -0
  109. data/spec/fixtures/vcr_cassettes/server_list.yml +117 -0
  110. data/spec/servers_spec.rb +36 -0
  111. data/spec/spec_helper.rb +24 -0
  112. data/spec/support/common_helpers.rb +47 -0
  113. metadata +129 -135
  114. data/lib/bbcloud/cli.rb +0 -160
  115. data/lib/bbcloud/vendor/fog/lib/fog.rb +0 -14
  116. data/lib/bbcloud/vendor/fog/lib/fog/compute.rb +0 -43
  117. data/lib/bbcloud/vendor/fog/lib/fog/compute/brightbox.rb +0 -162
  118. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/account.rb +0 -51
  119. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/cloud_ip.rb +0 -47
  120. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/cloud_ips.rb +0 -34
  121. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/flavor.rb +0 -33
  122. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/flavors.rb +0 -28
  123. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/image.rb +0 -56
  124. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/images.rb +0 -28
  125. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/load_balancer.rb +0 -50
  126. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/load_balancers.rb +0 -28
  127. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/server.rb +0 -108
  128. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/servers.rb +0 -29
  129. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/user.rb +0 -39
  130. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/users.rb +0 -29
  131. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/zone.rb +0 -21
  132. data/lib/bbcloud/vendor/fog/lib/fog/compute/models/brightbox/zones.rb +0 -29
  133. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/activate_console_server.rb +0 -20
  134. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/add_listeners_load_balancer.rb +0 -20
  135. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/add_nodes_load_balancer.rb +0 -20
  136. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/create_api_client.rb +0 -19
  137. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/create_cloud_ip.rb +0 -19
  138. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/create_image.rb +0 -19
  139. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/create_load_balancer.rb +0 -19
  140. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/create_server.rb +0 -19
  141. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/destroy_api_client.rb +0 -20
  142. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/destroy_cloud_ip.rb +0 -20
  143. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/destroy_image.rb +0 -20
  144. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/destroy_load_balancer.rb +0 -20
  145. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/destroy_server.rb +0 -20
  146. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/get_account.rb +0 -19
  147. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/get_api_client.rb +0 -20
  148. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/get_cloud_ip.rb +0 -20
  149. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/get_image.rb +0 -20
  150. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/get_interface.rb +0 -20
  151. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/get_load_balancer.rb +0 -20
  152. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/get_server.rb +0 -20
  153. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/get_server_type.rb +0 -20
  154. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/get_user.rb +0 -20
  155. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/get_zone.rb +0 -20
  156. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/list_api_clients.rb +0 -19
  157. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/list_cloud_ips.rb +0 -19
  158. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/list_images.rb +0 -19
  159. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/list_load_balancers.rb +0 -19
  160. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/list_server_types.rb +0 -19
  161. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/list_servers.rb +0 -19
  162. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/list_users.rb +0 -19
  163. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/list_zones.rb +0 -19
  164. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/map_cloud_ip.rb +0 -20
  165. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/remove_listeners_load_balancer.rb +0 -20
  166. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/remove_nodes_load_balancer.rb +0 -20
  167. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/reset_ftp_password_account.rb +0 -19
  168. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/resize_server.rb +0 -19
  169. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/shutdown_server.rb +0 -20
  170. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/snapshot_server.rb +0 -20
  171. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/start_server.rb +0 -20
  172. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/stop_server.rb +0 -20
  173. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/unmap_cloud_ip.rb +0 -20
  174. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/update_account.rb +0 -20
  175. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/update_api_client.rb +0 -21
  176. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/update_image.rb +0 -21
  177. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/update_load_balancer.rb +0 -21
  178. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/update_server.rb +0 -21
  179. data/lib/bbcloud/vendor/fog/lib/fog/compute/requests/brightbox/update_user.rb +0 -21
  180. data/lib/bbcloud/vendor/fog/lib/fog/core.rb +0 -32
  181. data/lib/bbcloud/vendor/fog/lib/fog/core/attributes.rb +0 -178
  182. data/lib/bbcloud/vendor/fog/lib/fog/core/collection.rb +0 -127
  183. data/lib/bbcloud/vendor/fog/lib/fog/core/connection.rb +0 -35
  184. data/lib/bbcloud/vendor/fog/lib/fog/core/credentials.rb +0 -92
  185. data/lib/bbcloud/vendor/fog/lib/fog/core/deprecation.rb +0 -23
  186. data/lib/bbcloud/vendor/fog/lib/fog/core/errors.rb +0 -20
  187. data/lib/bbcloud/vendor/fog/lib/fog/core/hmac.rb +0 -48
  188. data/lib/bbcloud/vendor/fog/lib/fog/core/mock.rb +0 -68
  189. data/lib/bbcloud/vendor/fog/lib/fog/core/model.rb +0 -57
  190. data/lib/bbcloud/vendor/fog/lib/fog/core/parser.rb +0 -99
  191. data/lib/bbcloud/vendor/fog/lib/fog/core/provider.rb +0 -18
  192. data/lib/bbcloud/vendor/fog/lib/fog/core/scp.rb +0 -67
  193. data/lib/bbcloud/vendor/fog/lib/fog/core/service.rb +0 -175
  194. data/lib/bbcloud/vendor/fog/lib/fog/core/ssh.rb +0 -120
  195. data/lib/bbcloud/vendor/fog/lib/fog/core/time.rb +0 -27
  196. data/lib/bbcloud/vendor/fog/lib/fog/core/wait_for.rb +0 -17
  197. data/lib/bbcloud/vendor/fog/lib/fog/providers.rb +0 -9
  198. data/lib/bbcloud/vendor/fog/lib/fog/providers/brightbox.rb +0 -9
@@ -0,0 +1,4 @@
1
+ Given /^GLI's libs are in my path$/ do
2
+ ENV['RUBYLIB'] = GLI_LIB_PATH
3
+ end
4
+
@@ -0,0 +1,21 @@
1
+ require 'aruba/cucumber'
2
+ require 'fileutils'
3
+
4
+ ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
5
+ GLI_LIB_PATH = File.expand_path(File.join(File.dirname(__FILE__),'..','..','lib'))
6
+
7
+ GLI_GEMSET = 'gli-testing'
8
+ TMP_PATH = 'tmp/aruba'
9
+
10
+ Before do
11
+ # Not sure how else to get this dynamically
12
+ @dirs = [TMP_PATH]
13
+ end
14
+
15
+ After do |scenario|
16
+ ENV['RUBYLIB'] = ''
17
+ todo_app_dir = File.join(TMP_PATH,'todo')
18
+ if File.exists? todo_app_dir
19
+ FileUtils.rm_rf(todo_app_dir)
20
+ end
21
+ end
@@ -0,0 +1,80 @@
1
+ gli - create command-suite apps, a la git, using this awesome Ruby DSL
2
+ ======================================================================
3
+
4
+ Setup and Usage
5
+ ---------------
6
+
7
+ Installation:
8
+ $ gem install gli
9
+
10
+ Show list of commands
11
+ $ gli help [command]
12
+
13
+ Show help for one command
14
+ $ gli help init
15
+
16
+ Create a new GLI-based project with the commands foo and bar
17
+ $ gli init project_name foo bar
18
+
19
+ Create a new GLI-based project with an ext directory
20
+ $ gli init -e project_name foo bar
21
+
22
+ Create a new GLI-based project without a test directory (bad!)
23
+ $ gli init --notest project_name foo bar
24
+
25
+ Create a new GLI-based project somewhere else than .
26
+ $ gli -r /tmp init project_name foo bar
27
+
28
+ Just see what GLI would create
29
+ $ gli -n init -e project_name foo bar
30
+
31
+
32
+ Using GLI's DSL
33
+ ---------------
34
+
35
+ Create a switch (option that takes no args)
36
+
37
+ desc 'Dry-run; don't change the disk
38
+ switch [:n,'dry-run']
39
+ # Both -n and --dry-run will work
40
+ # Access in code via global_options[:n]
41
+
42
+ Create a flag (option that takes an argument)
43
+
44
+ desc 'Location of the config file'
45
+ arg_name 'path_to_file'
46
+ default_value '~/.glirc'
47
+ flag [:c,:conf]
48
+ # Both -c and --conf work, if this flag is omitted
49
+ # then the default of ~/.glirc is avaialble to the code
50
+ # Access in code via global_options[:c] (or :conf)
51
+
52
+ Create a command
53
+
54
+ desc 'Get the list of open tickets'
55
+ command [:tickets] do |c|
56
+ c.desc 'Only assigned to me'
57
+ c.switch [:m,:me]
58
+
59
+ c.desc 'Show only tickets for one project'
60
+ c.flag [:p,:project,'only-project']
61
+
62
+ c.action do |global_options,options,args|
63
+ # global_options has the global options as a hash
64
+ # options are the command specific ones (e.g. options[:p])
65
+ # args are the command line arguments that weren't parsed
66
+ # raise an exception or exit_now! if things go wrong
67
+ end
68
+ end
69
+
70
+ Set up stuff ahead of time
71
+
72
+ pre do |global_options,command,options,args|
73
+ return true if things_are_ok
74
+ return false if we_should_abort_the_command
75
+ end
76
+
77
+ Use GLI
78
+
79
+ exit run(ARGV)
80
+ # run returns a suitable exit status
@@ -0,0 +1,46 @@
1
+ # Make sure we get the gli that's local
2
+ require File.join([File.dirname(__FILE__),'lib','gli_version.rb'])
3
+
4
+ spec = Gem::Specification.new do |s|
5
+ s.name = 'gli'
6
+ s.version = GLI::VERSION
7
+ s.author = 'David Copeland'
8
+ s.email = 'davidcopeland@naildrivin5.com'
9
+ s.homepage = 'http://davetron5000.github.com/gli'
10
+ s.platform = Gem::Platform::RUBY
11
+ s.summary = 'A Git Like Interface for building command line apps'
12
+ s.description = 'An application and API for describing command line interfaces that can be used to quickly create a shell for executing command-line tasks. The command line user interface is similar to Git''s, in that it takes global options, a command, command-specific options, and arguments'
13
+ s.files = %w(
14
+ lib/gli/command.rb
15
+ lib/gli/command_line_token.rb
16
+ lib/gli/copy_options_to_aliases.rb
17
+ lib/gli/flag.rb
18
+ lib/gli/switch.rb
19
+ lib/gli/options.rb
20
+ lib/gli/exceptions.rb
21
+ lib/gli/terminal.rb
22
+ lib/gli.rb
23
+ lib/gli_version.rb
24
+ lib/support/help.rb
25
+ lib/support/rdoc.rb
26
+ lib/support/scaffold.rb
27
+ lib/support/initconfig.rb
28
+ bin/gli
29
+ )
30
+ s.require_paths << 'lib'
31
+ s.has_rdoc = true
32
+ s.extra_rdoc_files = ['README.rdoc', 'gli.rdoc']
33
+ s.rdoc_options << '--title' << 'Git Like Interface' << '--main' << 'README.rdoc' << '-R'
34
+ s.bindir = 'bin'
35
+ s.executables << 'gli'
36
+ s.rubyforge_project = 'gli'
37
+ s.add_development_dependency('rake', '~> 0.8.0')
38
+ s.add_development_dependency('rdoc', '~> 2.4.0')
39
+ s.add_development_dependency('sdoc', '~> 0.2.0')
40
+ s.add_development_dependency('reek', '~> 1.2.0')
41
+ s.add_development_dependency('roodi', '~> 2.1.0')
42
+ s.add_development_dependency('grancher', '~> 0.1.5')
43
+ s.add_development_dependency('rainbow', '~> 1.1.1')
44
+ s.add_development_dependency('aruba', '~> 0.3.6')
45
+ end
46
+
@@ -0,0 +1,51 @@
1
+ = <tt>gli</tt>
2
+
3
+ gli allows you to create the scaffolding for a GLI-powered application
4
+ gli [global options] command_name [command-specific options] [--] arguments...
5
+
6
+ * Use the command +help+ to get a summary of commands
7
+ * Use the command <tt>help command_name</tt> to get a help for +command_name+
8
+ * Use <tt>--</tt> to stop command line argument processing; useful if your arguments have dashes in them
9
+
10
+ == Global Options
11
+ These options are available for any command and are specified before the name of the command
12
+
13
+ [<tt>-n</tt>] Dry run; dont change the disk
14
+ [<tt>-r, --root=arg</tt>] Root dir of project <i>( default: <tt>.</tt>)</i>
15
+
16
+ This is the directory where the projects directory will be made, so if you specify a project name foo and the root dir of ., the directory ./foo will be created
17
+
18
+ [<tt>-v</tt>] Be verbose
19
+ == Commands
20
+ [<tt>help</tt>] Shows list of commands or help for one command
21
+ [<tt>init</tt>] Create a new GLI-based project
22
+
23
+ === <tt>help [command]</tt>
24
+
25
+ Shows list of commands or help for one command
26
+
27
+ Gets help for the application or its commands. Can also list the commands in a way helpful to creating a bash-style completion function
28
+
29
+ ==== Options
30
+ These options are specified *after* the command.
31
+
32
+ [<tt>-c, --completion</tt>] List all commands one line at a time, for use with shell completion ([command] argument is partial command to match)
33
+ === <tt>init project_name [command[ command]*]</tt>
34
+
35
+ Create a new GLI-based project
36
+
37
+ *Aliases*
38
+ * <tt><b>scaffold</b></tt>
39
+
40
+ This will create a scaffold command line project that uses GLI
41
+ for command line processing. Specifically, this will create
42
+ an executable ready to go, as well as a lib and test directory, all
43
+ inside the directory named for your project
44
+
45
+
46
+ ==== Options
47
+ These options are specified *after* the command.
48
+
49
+ [<tt>-e, --ext</tt>] Create an ext dir
50
+ [<tt>--force</tt>] Overwrite/ignore existing files and directories
51
+ [<tt>--notest</tt>] Do not create a test dir
@@ -0,0 +1,560 @@
1
+ require 'gli/command.rb'
2
+ require 'gli/command_line_token.rb'
3
+ require 'gli/copy_options_to_aliases.rb'
4
+ require 'gli/exceptions.rb'
5
+ require 'gli/flag.rb'
6
+ require 'gli/options.rb'
7
+ require 'gli/switch.rb'
8
+ require 'gli_version.rb'
9
+ require 'support/help.rb'
10
+ require 'support/rdoc.rb'
11
+ require 'support/initconfig.rb'
12
+ require 'etc'
13
+
14
+ # A means to define and parse a command line interface that works as
15
+ # Git's does, in that you specify global options, a command name, command
16
+ # specific options, and then command arguments.
17
+ module GLI
18
+ extend self
19
+ include CopyOptionsToAliases
20
+
21
+ @@program_name = $0.split(/\//)[-1]
22
+ @@post_block = nil
23
+ @@pre_block = nil
24
+ @@error_block = nil
25
+ @@config_file = nil
26
+ @@use_openstruct = false
27
+ @@version = nil
28
+ @@stderr = $stderr
29
+ @@program_desc = nil
30
+ @@skips_pre = false
31
+ @@skips_post = false
32
+
33
+ # Override the device of stderr; exposed only for testing
34
+ def error_device=(e) #:nodoc:
35
+ @@stderr = e
36
+ end
37
+
38
+ # Reset the GLI module internal data structures; mostly useful for testing
39
+ def reset # :nodoc:
40
+ switches.clear
41
+ flags.clear
42
+ commands.clear
43
+ @@version = nil
44
+ @@config_file = nil
45
+ @@use_openstruct = false
46
+ @@prog_desc = nil
47
+ clear_nexts
48
+ end
49
+
50
+ # Describe the next switch, flag, or command. This should be a
51
+ # short, one-line description
52
+ #
53
+ # +description+:: A String of the short descripiton of the switch, flag, or command following
54
+ def desc(description); @@next_desc = description; end
55
+
56
+ # Describe the overall application/programm. This should be a one-sentence summary
57
+ # of what your program does that will appear in the help output.
58
+ #
59
+ # +description+:: A String of the short description of your program's purpose
60
+ def program_desc(description=nil)
61
+ if description
62
+ @@program_desc = description
63
+ end
64
+ @@program_desc
65
+ end
66
+
67
+ # Use this if the following command should not have the pre block executed.
68
+ # By default, the pre block is executed before each command and can result in
69
+ # aborting the call. Using this will avoid that behavior for the following command
70
+ def skips_pre
71
+ @@skips_pre = true
72
+ end
73
+
74
+ # Use this if the following command should not have the post block executed.
75
+ # By default, the post block is executed after each command.
76
+ # Using this will avoid that behavior for the following command
77
+ def skips_post
78
+ @@skips_post = true
79
+ end
80
+
81
+ # Provide a longer, more detailed description. This
82
+ # will be reformatted and wrapped to fit in the terminal's columns
83
+ #
84
+ # +long_desc+:: A String that is s longer description of the switch, flag, or command following.
85
+ def long_desc(long_desc); @@next_long_desc = long_desc; end
86
+
87
+ # Describe the argument name of the next flag. It's important to keep
88
+ # this VERY short and, ideally, without any spaces (see Example).
89
+ #
90
+ # +name+:: A String that *briefly* describes the argument given to the following command or flag.
91
+ #
92
+ # Example:
93
+ # desc 'Set the filename'
94
+ # arg_name 'file_name'
95
+ # flag [:f,:filename]
96
+ #
97
+ # Produces:
98
+ # -f, --filename=file_name Set the filename
99
+ def arg_name(name); @@next_arg_name = name; end
100
+
101
+ # set the default value of the next flag
102
+ #
103
+ # +val+:: A String reprensenting the default value to be used for the following flag if the user doesn't specify one
104
+ # and, when using a config file, the config also doesn't specify one
105
+ def default_value(val); @@next_default_value = val; end
106
+
107
+ # Create a flag, which is a switch that takes an argument
108
+ #
109
+ # +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names
110
+ # and aliases for this flag.
111
+ #
112
+ # Example:
113
+ #
114
+ # desc 'Set the filename'
115
+ # flag [:f,:filename,'file-name']
116
+ #
117
+ # Produces:
118
+ #
119
+ # -f, --filename, --file-name=arg Set the filename
120
+ def flag(*names)
121
+ names = [names].flatten
122
+ verify_unused(names,flags,switches,"in global options")
123
+ flag = Flag.new(names,@@next_desc,@@next_arg_name,@@next_default_value,@@next_long_desc)
124
+ flags[flag.name] = flag
125
+ clear_nexts
126
+ end
127
+
128
+ # Create a switch, which is a command line flag that takes no arguments (thus, it _switches_ something on)
129
+ #
130
+ # +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names
131
+ # and aliases for this switch.
132
+ def switch(*names)
133
+ names = [names].flatten
134
+ verify_unused(names,flags,switches,"in global options")
135
+ switch = Switch.new(names,@@next_desc,@@next_long_desc)
136
+ switches[switch.name] = switch
137
+ clear_nexts
138
+ end
139
+
140
+ # Sets that this app uses a config file as well as the name of the config file.
141
+ #
142
+ # +filename+:: A String representing the path to the file to use for the config file. If it's an absolute
143
+ # path, this is treated as the path to the file. If it's *not*, it's treated as relative to the user's home
144
+ # directory as produced by <code>Etc.getpwuid.dir</code>.
145
+ def config_file(filename)
146
+ if filename =~ /^\//
147
+ @@config_file = filename
148
+ else
149
+ @@config_file = Etc.getpwuid.dir + '/' + filename
150
+ end
151
+ commands[:initconfig] = InitConfig.new(@@config_file)
152
+ @@config_file
153
+ end
154
+
155
+ # Define a new command. This takes a block that will be given an instance of the Command that was created.
156
+ # You then may call methods on this object to define aspects of that Command.
157
+ #
158
+ # +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names and aliases for this command.
159
+ #
160
+ def command(*names)
161
+ command = Command.new([names].flatten,@@next_desc,@@next_arg_name,@@next_long_desc,@@skips_pre,@@skips_post)
162
+ commands[command.name] = command
163
+ yield command
164
+ clear_nexts
165
+ end
166
+
167
+ # Define a block to run after command line arguments are parsed
168
+ # but before any command is run. If this block raises an exception
169
+ # the command specified will not be executed.
170
+ # The block will receive the global-options,command,options, and arguments
171
+ # If this block evaluates to true, the program will proceed; otherwise
172
+ # the program will end immediately
173
+ def pre(&a_proc)
174
+ @@pre_block = a_proc
175
+ end
176
+
177
+ # Define a block to run after the command was executed, <b>only
178
+ # if there was not an error</b>.
179
+ # The block will receive the global-options,command,options, and arguments
180
+ def post(&a_proc)
181
+ @@post_block = a_proc
182
+ end
183
+
184
+ # Define a block to run if an error occurs.
185
+ # The block will receive any Exception that was caught.
186
+ # It should evaluate to false to avoid the built-in error handling (which basically just
187
+ # prints out a message). GLI uses a variety of exceptions that you can use to find out what
188
+ # errors might've occurred during command-line parsing:
189
+ # * GLI::CustomExit
190
+ # * GLI::UnknownCommandArgument
191
+ # * GLI::UnknownGlobalArgument
192
+ # * GLI::UnknownCommand
193
+ # * GLI::BadCommandLine
194
+ def on_error(&a_proc)
195
+ @@error_block = a_proc
196
+ end
197
+
198
+ # Indicate the version of your application
199
+ #
200
+ # +version+:: String containing the version of your application.
201
+ def version(version)
202
+ @@version = version
203
+ end
204
+
205
+ # Call this with +true+ will cause the +global_options+ and
206
+ # +options+ passed to your code to be wrapped in
207
+ # Options, which is a subclass of +OpenStruct+ that adds
208
+ # <tt>[]</tt> and <tt>[]=</tt> methods.
209
+ #
210
+ # +use_openstruct+:: a Boolean indicating if we should use OpenStruct instead of Hashes
211
+ def use_openstruct(use_openstruct)
212
+ @@use_openstruct = use_openstruct
213
+ end
214
+
215
+ # Runs whatever command is needed based on the arguments.
216
+ #
217
+ # +args+:: the command line ARGV array
218
+ #
219
+ # Returns a number that would be a reasonable exit code
220
+ def run(args) #:nodoc:
221
+ rdoc = RDocCommand.new
222
+ commands[:rdoc] = rdoc if !commands[:rdoc]
223
+ commands[:help] = DefaultHelpCommand.new(@@version,rdoc) if !commands[:help]
224
+ exit_code = 0
225
+ begin
226
+ config = parse_config
227
+ override_defaults_based_on_config(config)
228
+ global_options,command,options,arguments = parse_options(args)
229
+ copy_options_to_aliased_versions(global_options,command,options)
230
+ global_options = convert_to_openstruct?(global_options)
231
+ options = convert_to_openstruct?(options)
232
+ if proceed?(global_options,command,options,arguments)
233
+ command = commands[:help] if !command
234
+ command.execute(global_options,options,arguments)
235
+ if !command.skips_post && @@post_block
236
+ @@post_block.call(global_options,command,options,arguments)
237
+ end
238
+ end
239
+ rescue Exception => ex
240
+
241
+ @@stderr.puts error_message(ex) if regular_error_handling?(ex)
242
+
243
+ exit_code = if ex.respond_to? :exit_code
244
+ ex.exit_code
245
+ else
246
+ -2
247
+ end
248
+ raise ex if ENV['GLI_DEBUG'] == 'true'
249
+ end
250
+ exit_code
251
+ end
252
+
253
+ # True if we should proceed with executing the command; this calls
254
+ # the pre block if it's defined
255
+ def proceed?(global_options,command,options,arguments) #:nodoc:
256
+ if command && command.skips_pre
257
+ true
258
+ elsif @@pre_block
259
+ @@pre_block.call(global_options,command,options,arguments)
260
+ else
261
+ true
262
+ end
263
+ end
264
+
265
+ # Returns true if we should proceed with GLI's basic error handling.
266
+ # This calls the error block if the user provided one
267
+ def regular_error_handling?(ex) #:nodoc:
268
+ if @@error_block
269
+ @@error_block.call(ex)
270
+ else
271
+ true
272
+ end
273
+ end
274
+
275
+ # Returns a String of the error message to show the user
276
+ # +ex+:: The exception we caught that launched the error handling routines
277
+ def error_message(ex) #:nodoc:
278
+ msg = "error: #{ex.message}"
279
+ case ex
280
+ when UnknownCommand
281
+ msg += ". Use '#{program_name} help' for a list of commands"
282
+ when UnknownCommandArgument
283
+ msg += ". Use '#{program_name} help #{ex.command.name}' for a list of command options"
284
+ when UnknownGlobalArgument
285
+ msg += ". Use '#{program_name} help' for a list of global options"
286
+ end
287
+ end
288
+
289
+ # Simpler means of exiting with a custom exit code. This will
290
+ # raise a CustomExit with the given message and exit code, which will ultimatley
291
+ # cause your application to exit with the given exit_code as its exit status
292
+ def exit_now!(message,exit_code)
293
+ raise CustomExit.new(message,exit_code)
294
+ end
295
+
296
+ # Set or get the name of the program, if you don't want the default (which is
297
+ # the name of the command line program). This
298
+ # is only used currently in the help and rdoc commands.
299
+ #
300
+ # +override+:: A String that represents the name of the program to use, other than the default.
301
+ #
302
+ # Returns the current program name, as a String
303
+ def program_name(override=nil)
304
+ if override
305
+ @@program_name = override
306
+ end
307
+ @@program_name
308
+ end
309
+
310
+ alias :d :desc
311
+ alias :f :flag
312
+ alias :s :switch
313
+ alias :c :command
314
+
315
+ # Possibly returns a copy of the passed-in Hash as an instance of GLI::Option.
316
+ # By default, it will *not*. However by putting <tt>use_openstruct true</tt>
317
+ # in your CLI definition, it will
318
+ def convert_to_openstruct?(options) # :nodoc:
319
+ @@use_openstruct ? Options.new(options) : options
320
+ end
321
+
322
+ # Copies all options in both global_options and options to keys for the aliases of those flags.
323
+ # For example, if a flag works with either -f or --flag, this will copy the value from [:f] to [:flag]
324
+ # to allow the user to access the options by any alias
325
+ def copy_options_to_aliased_versions(global_options,command,options) # :nodoc:
326
+ copy_options_to_aliases(global_options)
327
+ command.copy_options_to_aliases(options)
328
+ end
329
+
330
+ def parse_config # :nodoc:
331
+ return nil if @@config_file.nil?
332
+ require 'yaml'
333
+ if File.exist?(@@config_file)
334
+ File.open(@@config_file) { |file| YAML::load(file) }
335
+ else
336
+ {}
337
+ end
338
+ end
339
+
340
+ # Returns an array of four values:
341
+ # * global options (as a Hash)
342
+ # * Command
343
+ # * command options (as a Hash)
344
+ # * arguments (as an Array)
345
+ def parse_options(args) # :nodoc:
346
+ global_options,command,options,arguments = parse_options_helper(args.clone,Hash.new,nil,Hash.new,Array.new)
347
+ flags.each { |name,flag| global_options[name] = flag.default_value if !global_options[name] }
348
+ command.flags.each { |name,flag| options[name] = flag.default_value if !options[name] }
349
+ return [global_options,command,options,arguments]
350
+ end
351
+
352
+ # Finds the index of the first non-flag
353
+ # argument or -1 if there wasn't one.
354
+ def find_non_flag_index(args) # :nodoc:
355
+ args.each_with_index do |item,index|
356
+ return index if item =~ /^[^\-]/
357
+ return index-1 if item =~ /^\-\-$/
358
+ end
359
+ -1
360
+ end
361
+
362
+ def flag_switch_index(args)
363
+ args.each_with_index do |item,index|
364
+ return index if item =~ /^[\-]/
365
+ end
366
+ -1
367
+ end
368
+
369
+ def clear_nexts # :nodoc:
370
+ @@next_desc = nil
371
+ @@next_arg_name = nil
372
+ @@next_default_value = nil
373
+ @@next_long_desc = nil
374
+ @@skips_pre = false
375
+ @@skips_post = false
376
+ end
377
+
378
+ clear_nexts
379
+
380
+ def flags # :nodoc:
381
+ @@flags ||= {}
382
+ end
383
+ def switches # :nodoc:
384
+ @@switches ||= {}
385
+ end
386
+ def commands # :nodoc:
387
+ @@commands ||= {}
388
+ end
389
+
390
+ # Recursive helper for parsing command line options
391
+ # <code>args</code>:: the arguments that have yet to be processed
392
+ # <code>global_options</code>:: the global options hash
393
+ # <code>command</code>:: the Command that has been identified (or nil if not identified yet)
394
+ # <code>command_options</code>:: options for Command
395
+ # <code>arguments</code>:: the arguments for Command
396
+ #
397
+ # This works by finding the first non-switch/flag argument, and taking that sublist and trying to pick out
398
+ # flags and switches. After this is done, one of the following is true:
399
+ # * the sublist is empty - in this case, go again, as there might be more flags to parse
400
+ # * the sublist has a flag left in it - unknown flag; we bail
401
+ # * the sublist has a non-flag left in it - this is the command (or the start of the arguments list)
402
+ #
403
+ # This sort of does the same thing in two phases; in the first phase, the command hasn't been identified, so
404
+ # we are looking for global switches and flags, ending when we get the command.
405
+ #
406
+ # Once the command has been found, we start looking for command-specific flags and switches.
407
+ # When those have been found, we know the rest of the argument list is arguments for the command
408
+ def parse_options_helper(args,global_options,command,command_options,arguments) # :nodoc:
409
+ non_flag_i = find_non_flag_index(args)
410
+ all_flags = false
411
+ if non_flag_i == 0
412
+ # no flags
413
+ if !command
414
+ command_name = args.shift
415
+ command = find_command(command_name)
416
+ raise UnknownCommand.new("Unknown command '#{command_name}'") if !command
417
+ return parse_options_helper(args,
418
+ global_options,
419
+ command,
420
+ Hash.new,
421
+ arguments)
422
+ elsif((index = flag_switch_index(args)) >= 0)
423
+ try_me = args[0..index-1]
424
+ rest = args[index..args.length]
425
+ new_args = rest + try_me
426
+ return parse_options_helper(new_args,
427
+ global_options,
428
+ command,
429
+ Hash.new,
430
+ arguments)
431
+ else
432
+ return global_options,command,command_options,arguments + args
433
+ end
434
+ elsif non_flag_i == -1
435
+ all_flags = true
436
+ end
437
+
438
+ try_me = args[0..non_flag_i]
439
+ rest = args[(non_flag_i+1)..args.length]
440
+ if all_flags
441
+ try_me = args
442
+ rest = []
443
+ end
444
+
445
+ # Suck up whatever options we can
446
+ switch_hash = switches
447
+ flag_hash = flags
448
+ options = global_options
449
+ if command
450
+ switch_hash = command.switches
451
+ flag_hash = command.flags
452
+ options = command_options
453
+ end
454
+
455
+ switch_hash.each do |name,switch|
456
+ value = switch.get_value!(try_me)
457
+ options[name] = value if !options[name]
458
+ end
459
+
460
+ flag_hash.each do |name,flag|
461
+ value = flag.get_value!(try_me)
462
+ # So, there's a case where the first time we request the value for a flag,
463
+ # we get the default and not the user-provided value. The next time we request
464
+ # it, we want to override it with the real value.
465
+ # HOWEVER, sometimes this happens in reverse, so we want to err on taking the
466
+ # user-provided, non-default value where possible.
467
+ if value
468
+ if options[name]
469
+ options[name] = value if options[name] == flag.default_value
470
+ else
471
+ options[name] = value
472
+ end
473
+ end
474
+ end
475
+
476
+ if try_me.empty?
477
+ return [global_options,command,command_options,arguments] if rest.empty?
478
+ # If we have no more options we've parsed them all
479
+ # and rest may have more
480
+ return parse_options_helper(rest,global_options,command,command_options,arguments)
481
+ else
482
+ if command
483
+ check = rest
484
+ check = rest + try_me if all_flags
485
+ check.each() do |arg|
486
+ if arg =~ /^\-\-$/
487
+ try_me.delete arg
488
+ break
489
+ end
490
+ raise UnknownCommandArgument.new("Unknown option #{arg}",command) if arg =~ /^\-/
491
+ end
492
+ return [global_options,command,command_options,try_me + rest]
493
+ else
494
+ # Now we have our command name
495
+ command_name = try_me.shift
496
+ raise UnknownGlobalArgument.new("Unknown option #{command_name}") if command_name =~ /^\-/
497
+
498
+ command = find_command(command_name)
499
+ raise UnknownCommand.new("Unknown command '#{command_name}'") if !command
500
+
501
+ return parse_options_helper(rest,
502
+ global_options,
503
+ command,
504
+ Hash.new,
505
+ arguments)
506
+ end
507
+ end
508
+ end
509
+
510
+ def find_command(name) # :nodoc:
511
+ sym = name.to_sym
512
+ return commands[name.to_sym] if commands[sym]
513
+ commands.each do |command_name,command|
514
+ return command if (command.aliases && command.aliases.include?(sym))
515
+ end
516
+ nil
517
+ end
518
+
519
+ # Checks that the names passed in have not been used in another flag or option
520
+ def verify_unused(names,flags,switches,context) # :nodoc:
521
+ names.each do |name|
522
+ verify_unused_in_option(name,flags,"flag",context)
523
+ verify_unused_in_option(name,switches,"switch",context)
524
+ end
525
+ end
526
+
527
+ private
528
+
529
+ def verify_unused_in_option(name,option_like,type,context) # :nodoc:
530
+ raise ArgumentError.new("#{name} has already been specified as a #{type} #{context}") if option_like[name]
531
+ option_like.each do |one_option_name,one_option|
532
+ if one_option.aliases
533
+ raise ArgumentError.new("#{name} has already been specified as an alias of #{type} #{one_option_name} #{context}") if one_option.aliases.include? name
534
+ end
535
+ end
536
+ end
537
+
538
+ # Sets the default values for flags based on the configuration
539
+ def override_defaults_based_on_config(config)
540
+ config ||= {}
541
+ config['commands'] ||= {}
542
+
543
+ override_default(flags,config)
544
+ override_default(switches,config)
545
+
546
+ commands.each do |command_name,command|
547
+ command_config = config['commands'][command_name] || {}
548
+
549
+ override_default(command.flags,command_config)
550
+ override_default(command.switches,command_config)
551
+ end
552
+ end
553
+
554
+ def override_default(tokens,config)
555
+ tokens.each do |name,token|
556
+ token.default_value=config[name] if config[name]
557
+ end
558
+ end
559
+
560
+ end