bbcloud 0.11.2 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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