hammer_cli 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,129 +1,340 @@
1
- Hammer - the CLI tool for Foreman
2
- =================================
1
+ Hammer - the CLI tool (not only) for Foreman
2
+ ============================================
3
3
 
4
- Hammer is a generic [clamp-based](https://github.com/mdub/clamp) CLI framework. Hammer-cli is just a core without any commands.
5
4
 
6
- The core can be extended with plugins and customized according to your application setup. Any Ruby script can be easily turned into a command so possibilities are wide.
5
+ Hammer is a generic [clamp-based](https://github.com/mdub/clamp) CLI framework.
6
+ Hammer-cli provides just the core functionality. The core is extensible using plugins that contain application-specific commands.
7
7
 
8
- Currently available plugins are:
8
+ This architecture allows for easy customization according to your application. Nearly any Ruby script can be turned into a Hammer command, so the possibilities are endless.
9
+
10
+ Available plugins are currently:
9
11
  - [hammer-cli-foreman](https://github.com/theforeman/hammer-cli-foreman) - commands corresponding to Foreman API
10
12
  - [hammer-cli-katello-bridge](https://github.com/theforeman/hammer-cli-katello-bridge) - set of commands provided by Katello CLI
11
13
 
12
- You also can easily add custom commands specific for your use, such as various bulk actions or admin tasks.
13
-
14
+ You also can easily add custom commands for your specific use, such as bulk actions or admin tasks.
14
15
 
15
16
 
16
- Installation instructions
17
- -------------------------
17
+ Installation
18
+ ------------
18
19
 
19
20
  Hammer CLI is packaged for the following RPM based distributions:
20
21
 
21
22
  - RHEL and derivatives, version 6
22
23
  - Fedora 18, 19
24
+ - Debian Wheezy, Squeezy
25
+ - Ubuntu Precise
26
+
27
+ ### Installation from RPMs
28
+
29
+ #### Step 1: setup yum repositories
30
+
31
+ For Foreman 1.3 stable the hammer packages are part of your installation repo and you can skip this step.
32
+
33
+ You can choose from stable or nightly repo. Nightly has more recent version of hammer packages, but it was subject to less testing so there is a higher risk of issues.
34
+ Add the Foreman yum repository to your yum repo files. For Fedora installations replace 'el6' with 'f18' or 'f19' as appropriate.
23
35
 
24
36
 
25
- #### Step 1: setup rpm repositories
26
- Add the Foreman's nightly rpm repository to your yum repo files. For Fedora installations replace 'el6' with 'f18' or 'f19' as appropriate.
37
+ Using stable
27
38
 
28
39
  ```bash
29
- http://yum.theforeman.org/nightly/el6/$basearch/
40
+ yum -y install http://yum.theforeman.org/releases/1.3/el6/x86_64/foreman-release.rpm
41
+ ```
42
+
43
+ or nightly
44
+
45
+ ```bash
46
+ cat > /etc/yum.repos.d/foreman.repo << EOF
47
+ [foreman]
48
+ name=Foreman Nightly
49
+ baseurl=http://yum.theforeman.org/nightly/el6/x86_64
50
+ gpgcheck=0
51
+ enabled=1
52
+ EOF
30
53
  ```
31
54
 
32
55
  On RHEL systems you will also have to add [EPEL repository](https://fedoraproject.org/wiki/EPEL) as it contains some of the required dependencies.
33
56
 
34
57
 
35
58
  #### Step 2: install hammer core
59
+
60
+ ```bash
61
+ yum install rubygem-hammer_cli
62
+ ```
63
+
64
+ #### Step 3: install plugins
65
+ Currently, there are two plugins, both available as rpm packages.
66
+
67
+ - commands for managing foreman
68
+
69
+ ```bash
70
+ yum install rubygem-hammer_cli_foreman
36
71
  ```
37
- $ yum install rubygem-hammer_cli
72
+
73
+ - 1:1 bridge to [katello cli](https://github.com/Katello/katello)
74
+
75
+ ```bash
76
+ yum install rubygem-hammer_cli_katello_bridge
38
77
  ```
39
78
 
79
+ To install any other hammer plugin just make sure the appropriate gem is installed and follow with the configuration.
80
+
81
+
82
+ ### Installation from DEBs
83
+
84
+ #### Step 1: setup apt repositories
85
+
86
+ For Foreman 1.3 stable the hammer packages are part of your installation repo and you can skip this step.
87
+
88
+ You can choose from stable or nightly repo. Nightly has more recent version of hammer packages, but it was subject to less testing so there is a highr risk of issues.
89
+
90
+ Choose stable (don't forget to replace "squeeze" with version name of your system)
91
+
92
+ ```bash
93
+ echo "deb http://deb.theforeman.org/ squeeze stable" > /etc/apt/sources.list.d/foreman.list
94
+ ```
95
+
96
+ or nightly
97
+
98
+ ```bash
99
+ echo "deb http://deb.theforeman.org/ squeeze nightly" > /etc/apt/sources.list.d/foreman.list
100
+ ```
101
+
102
+ and update the keys
103
+
104
+ ```bash
105
+ wget -q http://deb.theforeman.org/foreman.asc -O- | apt-key add -
106
+ ```
107
+
108
+ #### Step 2: install hammer core
109
+
110
+ ```bash
111
+ apt-get update && apt-get install ruby-hammer-cli
112
+ ```
40
113
 
41
114
  #### Step 3: install plugins
42
- Currently, there are two plugins, both available as rpm packages.
115
+ Currently, there are two plugins, both available as deb packages.
43
116
 
44
117
  - commands for managing foreman
118
+
119
+ ```bash
120
+ $ apt-get install ruby-hammer-cli-foreman
45
121
  ```
46
- $ yum install rubygem-hammer_cli_foreman
122
+
123
+ - 1:1 bridge to [katello cli](https://github.com/Katello/katello)
124
+
125
+ ```bash
126
+ $ apt-get install ruby-hammer-cli-katello-bridge
127
+ ```
128
+
129
+ To install any other hammer plugin just make sure the appropriate gem is installed and follow with the configuration.
130
+
131
+
132
+ ### Installation from GEMs
133
+
134
+ Make sure you have ```gem``` command installed on your system
135
+
136
+ #### Step 1: install hammer core
137
+
138
+ ```bash
139
+ $ gem install hammer_cli
140
+ ```
141
+
142
+ #### Step 2: install plugins
143
+ Currently, there are two plugins, both available on rubygems.org
144
+
145
+ - commands for managing foreman
146
+
147
+ ```bash
148
+ $ gem install hammer_cli_foreman
47
149
  ```
48
150
 
49
151
  - 1:1 bridge to [katello cli](https://github.com/Katello/katello)
152
+
153
+ ```bash
154
+ $ gem install hammer_cli_katello_bridge
50
155
  ```
51
- $ yum install rubygem-hammer_cli_katello_bridge
156
+
157
+ To install any other hammer plugin just install the appropriate gem and follow with the configuration.
158
+
159
+
160
+ ### Installation from SOURCE
161
+
162
+ If you can install hammer from git checkouts, you will just need ```rake``` installed on your system.
163
+ Clone and install CLI core
164
+
165
+ ```bash
166
+ $ git clone https://github.com/theforeman/hammer-cli.git
167
+ $ cd hammer-cli
168
+ $ rake install
169
+ $ cd ..
52
170
  ```
53
171
 
54
- Plugins are disabled after the installation. You have to edit the config file and enable them manually.
172
+ clone plugin with foreman commands
55
173
 
174
+ ```bash
175
+ $ git clone https://github.com/theforeman/hammer-cli-foreman.git
176
+ $ cd hammer-cli-foreman
177
+ $ rake install
178
+ $ cd ..
179
+ ```
56
180
 
57
- #### Step 4: configuration
181
+ and optionally other plugins via any of the methods mentioned above.
58
182
 
59
- Edit ```/etc/foreman/cli_config.yml``` or ```~/.foreman/cli_config.yml``` and uncomment lines with names of modules you've just installed to enable them:
60
183
 
61
- ```yaml
62
- :modules:
63
- # - hammer_cli_foreman
64
- # - hammer_cli_katello_bridge
184
+ Configuration
185
+ -------------
186
+
187
+ ### Format and locations
188
+
189
+ Configuration is set based on the following files, loaded in this order:
190
+
191
+ - ```/etc/foreman/cli_config.yml```.
192
+ - ```~/.foreman/cli_config.yml```
193
+ - ```./config/cli_config.yml``` (config dir in CWD)
194
+ - custom location specified on command line - ```-c CONF_FILE_PATH```
195
+
196
+ Later files have precedence if they redefines the same option.
197
+
198
+ Hammer uses yaml formatting for its configuration. The config file template is contained in the hammer_cli gem
199
+
200
+ ```bash
201
+ gem contents hammer_cli|grep cli_config.template.yml
65
202
  ```
203
+ and can be copied to one of the locations above and changed as needed. The packaged version of hammer copies the template to /etc for you.
204
+
66
205
 
67
- Confirm your setup by running ```$ hammer -h``` and see if the desired commands are listed.
206
+ ### Plugins
68
207
 
69
- You will also most likely want to change the url of the Foreman server.
208
+ Plugins are disabled by default. You have to edit the config file and enable them manually under ```modules``` option, as can be seen in the sample config below.
209
+
210
+ Plugin specific configuration should be nested under plugin's name.
211
+
212
+ ### Options
213
+
214
+ - ```:log_dir: <path>``` - directory where the logs are stored. The default is ```/var/log/foreman/``` and the log file is named ```hammer.log```
215
+ - ```:log_level: <level>``` - logging level. One of ```debug```, ```info```, ```warning```, ```error```, ```fatal```
216
+ - ```:log_owner: <owner>``` - logfile owner
217
+ - ```:log_group: <group>``` - logfile group
218
+ - ```:log_size: 1048576``` - size in bytes, when exceeded the log rotates. Default is 1MB
219
+ - ```:watch_plain: false``` - turn on/off syntax highlighting of data being logged in debug mode
220
+
221
+ ### Sample config
70
222
 
71
223
  ```yaml
224
+ :modules:
225
+ - hammer_cli_foreman
226
+ - hammer_cli_katello_bridge
227
+
72
228
  :foreman:
73
229
  :host: 'https://localhost/'
74
230
  :username: 'admin'
75
231
  :password: 'changeme'
76
- ```
77
232
 
78
- Done. Your hammer client is configured and ready to use.
233
+ :katello_bridge:
234
+ :cli_description: '/home/mbacovsk/work/theforeman/hammer-cli-katello-bridge/katello.json'
79
235
 
80
- #### Git installation
81
- Optionally you can install hammer from git checkouts. You will need ```rake``` and ```bundler```.
82
- Clone and install CLI core
83
-
84
- $ git clone git@github.com:theforeman/hammer-cli.git
85
- $ cd hammer-cli
86
- $ rake install
87
- $ cd ..
88
236
 
237
+ :log_dir: '/var/log/foreman/'
238
+ :log_level: 'debug'
239
+ ```
89
240
 
90
- clone plugin with foreman commands
91
-
92
- $ git clone git@github.com:theforeman/hammer-cli-foreman.git
93
- $ cd hammer-cli-foreman
94
- $ rake install
95
- $ cd ..
96
-
97
- and configure. Configuration is by default looked for in ```~/.foreman/``` or in ```/etc/foreman/```.
98
- Optionally you can put your configuration in ```./config/``` or point hammer
99
- to some other location using ```-c CONF_FILE``` option
241
+ Use the hammer
242
+ --------------
100
243
 
101
- You can start with config file template we created for you and update it to suit your needs. E.g.:
244
+ Confirm your setup by running ```$ hammer -h``` and check that the desired commands are listed.
102
245
 
103
- $ cp hammer-cli/config/cli_config.template.yaml ~/.foreman/cli_config.yml
246
+ ```
247
+ $ hammer -h
248
+ Usage:
249
+ hammer [OPTIONS] SUBCOMMAND [ARG] ...
250
+
251
+ Parameters:
252
+ SUBCOMMAND subcommand
253
+ [ARG] ... subcommand arguments
254
+
255
+ Subcommands:
256
+ architecture Manipulate Foreman's architectures.
257
+ global_parameter Manipulate Foreman's global parameters.
258
+ compute_resource Manipulate Foreman's compute resources.
259
+ domain Manipulate Foreman's domains.
260
+ fact Search Foreman's facts.
261
+ report Browse and read reports.
262
+ puppet_class Browse and read reports.
263
+ host Manipulate Foreman's hosts.
264
+ hostgroup Manipulate Foreman's hostgroups.
265
+ location Manipulate Foreman's locations.
266
+ medium Manipulate Foreman's installation media.
267
+ model Manipulate Foreman's hardware models.
268
+ os Manipulate Foreman's operating system.
269
+ organization Manipulate Foreman's organizations.
270
+ partition_table Manipulate Foreman's partition tables.
271
+ proxy Manipulate Foreman's smart proxies.
272
+ subnet Manipulate Foreman's subnets.
273
+ template Manipulate Foreman's config templates.
274
+ about status of the katello server and its subcomponents
275
+ activation_key activation key specific actions in the katello server
276
+ admin various administrative actions
277
+ changeset changeset specific actions in the katello server
278
+ client client specific actions in the katello server
279
+ content content namespace command
280
+ distribution repo specific actions in the katello server
281
+ distributor distributor specific actions in the katello server
282
+ environment environment specific actions in the katello server
283
+ errata errata specific actions in the katello server
284
+ gpg_key GPG key specific actions in the katello server
285
+ node node specific actions in the katello server
286
+ org organization specific actions in the katello server
287
+ package package specific actions in the katello server
288
+ package_group package group specific actions in the katello server
289
+ permission permission specific actions in the katello server
290
+ ping get the status of the katello server
291
+ product product specific actions in the katello server
292
+ provider provider specific actions in the katello server
293
+ puppet_module puppet module specific actions in the katello server
294
+ repo repo specific actions in the katello server
295
+ shell run the cli as a shell
296
+ sync_plan synchronization plan specific actions in the katello server
297
+ system system specific actions in the katello server
298
+ system_group system group specific actions in the katello server
299
+ task commands for retrieving task information
300
+ user user specific actions in the katello server
301
+ user_role user role specific actions in the katello server
302
+ version get the version of the katello server
303
+
304
+ Options:
305
+ -v, --verbose be verbose
306
+ -c, --config CFG_FILE path to custom config file
307
+ -u, --username USERNAME username to access the remote system
308
+ -p, --password PASSWORD password to access the remote system
309
+ --version show version
310
+ --show-ids Show ids of associated resources
311
+ --csv Output as CSV (same as --adapter=csv)
312
+ --output ADAPTER Set output format. One of [base, table, silent, csv]
313
+ --csv-separator SEPARATOR Character to separate the values
314
+ -P, --ask-pass Ask for password
315
+ --autocomplete LINE Get list of possible endings
316
+ -h, --help print help
317
+ ```
104
318
 
105
319
 
320
+ And you are Done. Your hammer client is configured and ready to use.
106
321
 
107
322
 
108
323
  Autocompletion
109
324
  --------------
110
325
 
111
- It is necessary to copy script hammer_cli_complete to the bash_completion.d directory.
326
+ It is necessary to copy the hammer_cli_complete script to the bash_completion.d directory.
112
327
 
113
328
  $ sudo cp hammer-cli/hammer_cli_complete /etc/bash_completion.d/
114
329
 
115
- Then in new shell the completion should work.
116
-
117
-
118
- How to test
119
- ------------
120
-
121
- Development of almost all the code was test driven.
330
+ Then after starting a new shell the completion should work.
122
331
 
123
- $ bundle install
124
- $ bundle exec "rake test"
125
332
 
126
- should work in any of the cli related repos. Generated coverage reports are stored in ./coverage directory.
333
+ Further reading
334
+ ---------------
335
+ If you're interested in hammer and want to develop some plugins for Foreman
336
+ or use it as a base for your own cli, read
337
+ [the developer docs](doc/developer_docs.md#hammer-developer-docs).
127
338
 
128
339
  License
129
340
  -------
@@ -0,0 +1,613 @@
1
+ Hammer Developer Docs
2
+ =====================
3
+
4
+ Hammer is a generic clamp-based CLI framework. It uses existing clamp features and adds some extra utilities.
5
+ We recommend to get familiar with the [Clamp documentation](https://github.com/mdub/clamp/#quick-start)
6
+ before creating some hammer specific plugins.
7
+
8
+
9
+ Writing your own Hammer plugin
10
+ ------------------------------
11
+
12
+ In this tutorial we will create a simple hello world plugin.
13
+
14
+ Hammer plugins are nothing but gems. Details on how to build a gem can be found for example at [rubygems.org](http://guides.rubygems.org/make-your-own-gem/).
15
+ In the first part of this tutorial we will briefly guide you through the process of creating a very simple gem. First of all you will need rubygems package installed on your system.
16
+
17
+ Create the basic gem structure in a project subdirectory of your choice:
18
+ ```
19
+ $ cd ./my_first_hammer_plugin/
20
+ $ touch Gemfile
21
+ $ touch hammer_cli_hello.gemspec
22
+ $ mkdir -p lib/hammer_cli_hello
23
+ $ touch lib/hammer_cli_hello.rb
24
+ $ touch lib/hammer_cli_hello/version.rb
25
+ ```
26
+
27
+ Example `Gemfile`:
28
+ ```ruby
29
+ source "https://rubygems.org"
30
+
31
+ gemspec
32
+ ```
33
+
34
+ Example `hammer_cli_hello.gemspec` file:
35
+ ```ruby
36
+ $:.unshift File.expand_path("../lib", __FILE__)
37
+ require "hammer_cli_hello/version"
38
+
39
+ Gem::Specification.new do |s|
40
+
41
+ s.name = "hammer_cli_hello"
42
+ s.authors = ["Me"]
43
+ s.version = HammerCLIHello.version.dup
44
+ s.platform = Gem::Platform::RUBY
45
+ s.summary = %q{Hello world commands for Hammer}
46
+
47
+ s.files = Dir['lib/**/*.rb']
48
+ s.require_paths = ["lib"]
49
+
50
+ s.add_dependency 'hammer_cli', '>= 0.0.6'
51
+ end
52
+ ```
53
+ More details about the gemspec structure is again at [rubygems.org](http://guides.rubygems.org/specification-reference/).
54
+
55
+ We'll have to specify the plugins version in `lib/hammer_cli_hello/version.rb`:
56
+ ```ruby
57
+ module HammerCLIHello
58
+ def self.version
59
+ @version ||= Gem::Version.new '0.0.1'
60
+ end
61
+ end
62
+ ```
63
+
64
+ This should be enough for creating a minimalist gem. Let's build and install it.
65
+ ```
66
+ $ gem build ./hammer_cli_hello.gemspec
67
+ $ gem install hammer_cli_hello-0.0.1.gem
68
+ ```
69
+
70
+ Update the hammer config to enable your plugin.
71
+ ```yaml
72
+ :modules:
73
+ - hammer_cli_hello
74
+ # - hammer_cli_foreman
75
+ # - hammer_cli_katello_bridge
76
+ ```
77
+
78
+
79
+ Verify the installation by running:
80
+ ```
81
+ $ hammer -v > /dev/null
82
+ ```
83
+
84
+ You should see a message saying that your module was loaded (second line in the sample output).
85
+ ```
86
+ [ INFO 2013-10-16 11:19:06 Init] Configuration from the file /etc/foreman/cli_config.yml has been loaded
87
+ [ INFO 2013-10-16 11:19:06 Init] Extension module hammer_cli_hello loaded
88
+ [ INFO 2013-10-16 11:19:06 HammerCLI::MainCommand] Called with options: {"verbose"=>true}
89
+ ```
90
+
91
+ Done. Your first hammer plugin is installed. Unfortunatelly it does not contain any commands yet. So let's start adding some to finally enjoy real results.
92
+
93
+ Optionally you can add a Rakefile and build and install the gem with `rake install`
94
+ ```ruby
95
+ # ./Rakefile
96
+ require 'bundler/gem_tasks'
97
+ ```
98
+
99
+
100
+ Create your first command
101
+ -------------------------
102
+
103
+ We will create a simple command called `hello` that will print a sentence "Hello World!" to stdout.
104
+
105
+ ### Declare the command
106
+
107
+ ```
108
+ touch ./lib/hammer_cli_hello/hello_world.rb
109
+ ```
110
+
111
+ ```ruby
112
+ # ./lib/hammer_cli_hello/hello_world.rb
113
+ require 'hammer_cli'
114
+
115
+ # it's a good practise to nest commands into modules
116
+ module HammerCLIHello
117
+
118
+ # hammer commands must be descendants of AbstractCommand
119
+ class HelloCommand < HammerCLI::AbstractCommand
120
+
121
+ # execute is the heart of the command
122
+ def execute
123
+ # we use print_message instead of simple puts
124
+ # the reason will be described later in the part called Output
125
+ print_message "Hello World!"
126
+ end
127
+ end
128
+
129
+ # now plug your command into the hammer's main command
130
+ HammerCLI::MainCommand.subcommand
131
+ 'hello', # command's name
132
+ "Say Hello World!", # description
133
+ HammerCLIHello::HelloCommand # the class
134
+ end
135
+ ```
136
+
137
+ The last bit is to require the file with your command in `hammer_cli_hello.rb`.
138
+ Hammer actually loads this file and this is how the commands from plugins get loaded
139
+ into hammer.
140
+ ```ruby
141
+ # ./lib/hammer_cli_hello.rb
142
+ require 'hammer_cli_hello/hello_world'
143
+ ```
144
+
145
+ Rebuild and reinstall your plugin and see the results of `hammer -h`
146
+ ```
147
+ gem build ./hammer_cli_hello.gemspec && gem install hammer_cli_hello-0.0.1.gem
148
+ ```
149
+
150
+
151
+ ```
152
+ $ hammer -h
153
+ Usage:
154
+ hammer [OPTIONS] SUBCOMMAND [ARG] ...
155
+
156
+ Parameters:
157
+ SUBCOMMAND subcommand
158
+ [ARG] ... subcommand arguments
159
+
160
+ Subcommands:
161
+ shell Interactive Shell
162
+ hello Say Hello World!
163
+
164
+ Options:
165
+ -v, --verbose be verbose
166
+ -c, --config CFG_FILE path to custom config file
167
+ -u, --username USERNAME username to access the remote system
168
+ -p, --password PASSWORD password to access the remote system
169
+ --version show version
170
+ --show-ids Show ids of associated resources
171
+ --csv Output as CSV (same as --adapter=csv)
172
+ --output ADAPTER Set output format. One of [csv, table, base, silent]
173
+ --csv-separator SEPARATOR Character to separate the values
174
+ -P, --ask-pass Ask for password
175
+ --autocomplete LINE Get list of possible endings
176
+ -h, --help print help
177
+ ```
178
+
179
+ Now try running the command.
180
+
181
+ ```
182
+ $ hammer hello
183
+ Hello World!
184
+ Error: exit code must be integer
185
+ ```
186
+
187
+ What's wrong here? Hammer requires integer exit codes as return values from the method `execute`.
188
+ It's usually just `HammerCLI::EX_OK`. Add it as the very last line of `execute`, rebuild and the
189
+ command should run fine.
190
+
191
+ See [exit_codes.rb](https://github.com/theforeman/hammer-cli/blob/master/lib/hammer_cli/exit_codes.rb)
192
+ for the full list of available exit codes.
193
+
194
+
195
+ ### Declaring options
196
+ Our new command has only one option so far. It's `-h` which is built in for every command by default.
197
+ Option declaration is the same as in clamp so please read it's
198
+ [documentation](https://github.com/mdub/clamp/#declaring-options)
199
+ on that topic.
200
+
201
+ Example option usage could go like this:
202
+ ```ruby
203
+ class HelloCommand < HammerCLI::AbstractCommand
204
+
205
+ option '--name', "NAME", "Name of the person you want to greet"
206
+
207
+ def execute
208
+ print_message "Hello %s!" % (name || "World")
209
+ HammerCLI::EX_OK
210
+ end
211
+ end
212
+ ```
213
+
214
+ ```
215
+ $ hammer hello -h
216
+ Usage:
217
+ hammer hello [OPTIONS]
218
+
219
+ Options:
220
+ --name NAME Name of the person you want to greet
221
+ -h, --help print help
222
+ ```
223
+
224
+ ```
225
+ $ hammer hello --name 'Foreman'
226
+ Hello Foreman!
227
+ ```
228
+
229
+
230
+ ### Option validation
231
+ Hammer provides extended functionality for validating options.
232
+
233
+ #### DSL
234
+ First of all there is a dsl for validating combinations of options:
235
+ ```ruby
236
+ validate_options do
237
+ all(:name, :surname).required # requires all the options
238
+ option(:age).required # requires a single option,
239
+ # equivalent of :required => true in option declaration
240
+ any(:email, :phone).required # requires at least one of the options
241
+
242
+ # Tt is possible to create more complicated constructs.
243
+ # This example requires either the full address or nothing
244
+ if any(:street, :city, :zip).exist?
245
+ all(:street, :city, :zip).required
246
+ end
247
+
248
+ # Here you can reject all address related option when --no-address is passed
249
+ if option(:no_address).exist?
250
+ all(:street, :city, :zip).rejected
251
+ end
252
+ end
253
+
254
+ ```
255
+
256
+ #### Option formatters
257
+ Another option-related feature is a set of formatters for specific option types:
258
+
259
+ * _HammerCLI::OptionFormatters.list_
260
+
261
+ Parses comma separated strings to a list of values.
262
+
263
+ Usage:
264
+ ```ruby
265
+ option "--users", "USER_NAMES", "List of user names", &HammerCLI::OptionFormatters.method(:list)
266
+ ```
267
+ `--users='J.R.,Gary,Bobby'` -> `['J.R.', 'Gary', 'Bobby']`
268
+
269
+ * _HammerCLI::OptionFormatters.file_
270
+
271
+ Loads contents of a file and returns it as a value of the option.
272
+
273
+ Usage:
274
+ ```ruby
275
+ option "--poem", "PATH_TO_POEM", "File containing the text of your poem", &HammerCLI::OptionFormatters.method(:file)
276
+ ```
277
+ `--poem=~/verlaine/les_poetes_maudits.txt` -> content of the file
278
+
279
+
280
+ ### Adding subcommands
281
+ Commands in the cli can be structured into a tree of parent commands (nodes) and subcommands (leaves).
282
+ Neither the number of subcommands nor the nesting is limited. Please note that no parent command
283
+ can perform any action and therefore it's useless to define `execute` method for them. This limit
284
+ comes from Clamp's implementation of the command hierarchy.
285
+
286
+ We've already used command nesting for plugging the `HelloCommand` command into the main command.
287
+ But let's create a new command `say` and show how to connect it with others to be more demonstrative.
288
+
289
+ ```ruby
290
+ module HammerCLIHello
291
+
292
+ # a new parent command 'say'
293
+ class SayCommand < HammerCLI::AbstractCommand
294
+
295
+ # subcommand 'hello' remains the same
296
+ class HelloCommand < HammerCLI::AbstractCommand
297
+
298
+ option '--name', "NAME", "Name of the person you want to greet"
299
+
300
+ def execute
301
+ print_message "Hello %s!" % (name || "World")
302
+ HammerCLI::EX_OK
303
+ end
304
+ end
305
+
306
+ # plug the original command into 'say'
307
+ subcommand 'hello', "Say Hello World!", HammerCLIHello::SayCommand::HelloCommand
308
+ end
309
+
310
+ # plug the 'say' command into the main command
311
+ HammerCLI::MainCommand.subcommand 'say', "Say something", HammerCLIHello::SayCommand
312
+ end
313
+ ```
314
+
315
+ The result will be:
316
+ ```
317
+ $ hammer say hello
318
+ Hello World!
319
+ ```
320
+
321
+ This is very typical usage of subcommands. When you create more of them it may feel a bit
322
+ duplicit to always define the subcommand structure at the end of the class definition.
323
+ Hammer provides utility methods for subcommand autoloading. This is handy especially
324
+ when you have growing number of subcommands. See how it works in the following example:
325
+
326
+ ```ruby
327
+ module HammerCLIHello
328
+
329
+ class SayCommand < HammerCLI::AbstractCommand
330
+
331
+ class HelloCommand < HammerCLI::AbstractCommand
332
+ command_name 'hello' # name and description moves to the command's class
333
+ desc 'Say Hello World!'
334
+ # ...
335
+ end
336
+
337
+ class HiCommand < HammerCLI::AbstractCommand
338
+ command_name 'hi'
339
+ desc 'Say Hi World!'
340
+ # ...
341
+ end
342
+
343
+ class ByeCommand < HammerCLI::AbstractCommand
344
+ command_name 'bye'
345
+ desc 'Say Bye World!'
346
+ # ...
347
+ end
348
+
349
+ autoload_subcommands
350
+ end
351
+
352
+ HammerCLI::MainCommand.subcommand 'say', "Say something", HammerCLIHello::SayCommand
353
+ end
354
+ ```
355
+
356
+ ```
357
+ $ hammer say
358
+ Usage:
359
+ hammer say [OPTIONS] SUBCOMMAND [ARG] ...
360
+
361
+ Parameters:
362
+ SUBCOMMAND subcommand
363
+ [ARG] ... subcommand arguments
364
+
365
+ Subcommands:
366
+ hi Say Hi World!
367
+ hello Say Hello World!
368
+ bye Say Bye World!
369
+
370
+ Options:
371
+ -h, --help print help
372
+ ```
373
+
374
+
375
+ ### Conflicting subcommands
376
+ It can happen that two different plugins define subcommands with the same name by accident.
377
+ In such situations `subcommand` will throw an exception. If this is intentional and you
378
+ want to redefine the existing command, use `subcommand!`.
379
+ This method does not throw exceptions, replaces the original subcommand, and leaves
380
+ a message in a log for debugging purposes.
381
+
382
+
383
+ ### Printing some output
384
+ We've mentioned above that it's not recommended practice to print output
385
+ directly with `puts` in Hammer. The reason is we separate definition
386
+ of the output from its interpretation. Hammer uses so called _output adapters_
387
+ that can modify the output format.
388
+
389
+ Hammer comes with four basic output adapters:
390
+ * __base__ - simple output, structured records
391
+ * __table__ - records printed in tables, ideal for printing lists of records
392
+ * __csv__ - comma separated output, ideal for scripting and grepping
393
+ * __silent__ - no output, used for testing
394
+
395
+ The detailed documentation on creating adapters is coming soon.
396
+
397
+ #### Printing messages
398
+ Very simple, just call
399
+ ```ruby
400
+ print_message(msg)
401
+ ```
402
+
403
+ #### Printing hash records
404
+ Typical usage of a cli is interaction with some api. In many cases it's listing
405
+ some records returned by the api.
406
+
407
+ Hammer comes with support for selecting and formatting of hash record fields.
408
+ You first create so called _output definition_ that you apply on your data. The result
409
+ is a collection of fields each having its type. The collection is then passed to some
410
+ _output adapter_ which handles the actuall formatting and printing.
411
+
412
+ Hammer provides a DSL for defining the output. Next rather complex example will
413
+ explain how to use it in action.
414
+
415
+ Imagine there's an API of some service that returns list of users:
416
+ ```ruby
417
+ [{
418
+ :id => 1,
419
+ :email => 'tom@email.com',
420
+ :phone => '123456111',
421
+ :first_name => 'Tom',
422
+ :last_name => 'Sawyer',
423
+ :roles => ['Admin', 'Editor'],
424
+ :timestamps => {
425
+ :created => '2012-12-18T15:24:42Z',
426
+ :updated => '2012-12-18T15:24:42Z'
427
+ }
428
+ },{
429
+ :id => 2,
430
+ :email => 'huckleberry@email.com',
431
+ :phone => '123456222',
432
+ :first_name => 'Huckleberry',
433
+ :last_name => 'Finn',
434
+ :roles => ['Admin'],
435
+ :timestamps => {
436
+ :created => '2012-12-18T15:25:00Z',
437
+ :updated => '2012-12-20T14:00:15Z'
438
+ }
439
+ }]
440
+ ```
441
+
442
+ We can create an output definition that selects and formats some of the fields:
443
+ ```ruby
444
+ dsl = HammerCLI::Output::Dsl.new
445
+ dsl.build do
446
+
447
+ # Simple field with a label. The first parameter is key in the printed hash.
448
+ field :id, 'ID'
449
+
450
+ # Fields can have types. The type determines how the field is printed.
451
+ # All available types are listed below.
452
+ # Here we want the roles to act as list.
453
+ field :roles, 'System Roles', Fields::List
454
+
455
+ # Label is used for grouping fields.
456
+ label 'Contacts' do
457
+ field :email, 'Email'
458
+ field :phone, 'Phone No.'
459
+ end
460
+
461
+ # From is used for accessing nested fields.
462
+ from :timestamps do
463
+ # See how date gets formatted in the output
464
+ field :created, 'Created At', Fields::Date
465
+ end
466
+ end
467
+
468
+ definition = HammerCLI::Output::Definition.new
469
+ definition.append(dsl.fields)
470
+
471
+ print_records(definition, data)
472
+
473
+ ```
474
+
475
+ Using the base adapter the output will look like:
476
+ ```
477
+ ID: 1
478
+ System Roles: Admin, Editor
479
+ Name: Tom Sawyer
480
+ Contacts:
481
+ Email: tom@email.com
482
+ Phone No.: 123456111
483
+ Created At: 2012/12/18 15:24:42
484
+
485
+ ID: 2
486
+ System Roles: Admin
487
+ Name: Huckleberry Finn
488
+ Contacts:
489
+ Email: huckleberry@email.com
490
+ Phone No.: 123456222
491
+ Created At: 2012/12/18 15:25:00
492
+ ```
493
+
494
+ All Hammer field types are:
495
+ * __Date__
496
+ * __Id__ - Used to mark ID values, current print adapters have support for turning id printing on/off.
497
+ See hammer's parameter `--show-ids`.
498
+ * __List__
499
+ * __KeyValue__ - Formats hashes containing `:name` and `:value`
500
+ * __Collection__ - Enables to render subcollections. Takes a block with another output definition.
501
+
502
+ The default adapter for every command is Base adapter. It is possible to override
503
+ the default one by redefining command's method `adapter`.
504
+
505
+ ```ruby
506
+ def adapter
507
+ # return :base, :table, :csv or name of your own adapter here
508
+ :table
509
+ end
510
+ ```
511
+
512
+
513
+ Other useful command features
514
+ -----------------------------
515
+
516
+ #### Logging
517
+ Hammer provides integrated [logger](https://github.com/TwP/logging)
518
+ with broad setting options (use hammer's config file):
519
+
520
+ ```yaml
521
+ :log_dir: '<path>' # - directory where the logs are stored.
522
+ # The default is /var/log/foreman/ and the log file is named hammer.log
523
+ :log_level: '<level>' # - logging level. One of debug, info, warning, error, fatal
524
+ :log_owner: '<owner>' # - logfile owner
525
+ :log_group: '<group>' # - logfile group
526
+ :log_size: 1048576 # - size in bytes, when exceeded the log rotates. Default is 1MB
527
+ :watch_plain: false # - turn on/off syntax highlighting of data being logged in debug mode
528
+ ```
529
+
530
+ Example usage in commands:
531
+ ```ruby
532
+ # Get a logger instance
533
+ logger('Logger name')
534
+
535
+ # It uses a command class name as the logger's name by default
536
+ logger
537
+
538
+ # Log a message at corresponding log level
539
+ logger.debug("...")
540
+ logger.error("...")
541
+ logger.info("...")
542
+ logger.fatal("...")
543
+ logger.warn("...")
544
+
545
+ # Writes an awesome print dump of a value to the log
546
+ logger.watch('Some label', value)
547
+ ```
548
+
549
+ #### Exception handling
550
+ Exception handling in Hammer is centralized by
551
+ [ExceptionHandler](https://github.com/theforeman/hammer-cli/blob/master/lib/hammer_cli/exception_handler.rb).
552
+ Each plugin, module or even a command can have a separate exception handler. The exception handler class
553
+ is looked up in the module structure from a command to the top level.
554
+
555
+ Define method `self.exception_handler_class` in your plugin's module to use a custom exception handler:
556
+ ```ruby
557
+ # ./lib/hammer_cli_hello.rb
558
+
559
+ module HammerCLIHello
560
+
561
+ def self.exception_handler_class
562
+ HammerCLIHello::CustomExceptionHandler
563
+ end
564
+ end
565
+
566
+ require 'hammer_cli_hello/hello_world'
567
+ ```
568
+
569
+ Centralized exception handling implies that you should raise exceptions on error states in your command
570
+ rather than handle it and return error codes. This approach guarrantees that error messages are logged and
571
+ printed consistently and correct exit codes are returned.
572
+
573
+
574
+ #### Configuration
575
+ Values form config files are accesible via class `HammerCLI::Settings`.
576
+ It's method `get` returns either the value or nil when it's not found.
577
+
578
+ Config values belonging to a specific plugin must be nested under
579
+ the plugin's name in config files.
580
+
581
+ ```yaml
582
+ #cli_config.yml
583
+ :log_dir: /var/log/hammer/
584
+ :hello_world:
585
+ :name: John
586
+ ```
587
+
588
+ ```ruby
589
+ HammerCLI::Settings.get(:log_dir) # get a value
590
+ HammerCLI::Settings.get(:hello_world, :name) # get a nested value
591
+ ```
592
+
593
+ There's more ways where to place your config file for hammer.
594
+ Read more in [the settings howto](https://github.com/theforeman/hammer-cli#configuration).
595
+
596
+ Creating commands for RESTful API with ApiPie
597
+ ---------------------------------------------
598
+ Coming soon...
599
+
600
+
601
+ <!--
602
+ - this part is valid for foreman
603
+ - what is apipie
604
+ - apipie bindings
605
+ - apipie, read and write commands
606
+ - define ids a resources
607
+ - apipie support, apipie_options
608
+ -->
609
+
610
+
611
+
612
+
613
+
@@ -32,7 +32,9 @@ module HammerCLI
32
32
  def parse(arguments)
33
33
  super
34
34
  validate_options
35
- logger.info "Called with options: %s" % options.inspect
35
+ safe_options = options.dup
36
+ safe_options.keys.each { |k| safe_options[k] = '***' if k.end_with?('password') }
37
+ logger.info "Called with options: %s" % safe_options.inspect
36
38
  rescue HammerCLI::Validator::ValidationError => e
37
39
  signal_usage_error e.message
38
40
  end
@@ -50,7 +50,11 @@ module Fields
50
50
 
51
51
  def symbolize_hash_keys(h)
52
52
  if h.is_a? Hash
53
- return h.inject({}){|result,(k,v)| result.update k.to_sym => symbolize_hash_keys(v)}
53
+ return h.inject({}) do |result,(k,v)|
54
+ # symbolizing empty string fails in ruby 1.8
55
+ result.update k.to_sym => symbolize_hash_keys(v) unless k.to_s.empty?
56
+ result
57
+ end
54
58
  elsif h.is_a? Array
55
59
  return h.collect{|item| symbolize_hash_keys(item)}
56
60
  else
@@ -1,5 +1,5 @@
1
1
  module HammerCLI
2
2
  def self.version
3
- @version ||= Gem::Version.new '0.0.7'
3
+ @version ||= Gem::Version.new '0.0.8'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hammer_cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Martin Bačovský
@@ -9,94 +10,107 @@ authors:
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2013-10-09 00:00:00.000000000 Z
13
+ date: 2013-10-29 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: clamp
16
17
  requirement: !ruby/object:Gem::Requirement
18
+ none: false
17
19
  requirements:
18
- - - '>='
20
+ - - ! '>='
19
21
  - !ruby/object:Gem::Version
20
22
  version: '0'
21
23
  type: :runtime
22
24
  prerelease: false
23
25
  version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
24
27
  requirements:
25
- - - '>='
28
+ - - ! '>='
26
29
  - !ruby/object:Gem::Version
27
30
  version: '0'
28
31
  - !ruby/object:Gem::Dependency
29
32
  name: rest-client
30
33
  requirement: !ruby/object:Gem::Requirement
34
+ none: false
31
35
  requirements:
32
- - - '>='
36
+ - - ! '>='
33
37
  - !ruby/object:Gem::Version
34
38
  version: '0'
35
39
  type: :runtime
36
40
  prerelease: false
37
41
  version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
38
43
  requirements:
39
- - - '>='
44
+ - - ! '>='
40
45
  - !ruby/object:Gem::Version
41
46
  version: '0'
42
47
  - !ruby/object:Gem::Dependency
43
48
  name: logging
44
49
  requirement: !ruby/object:Gem::Requirement
50
+ none: false
45
51
  requirements:
46
- - - '>='
52
+ - - ! '>='
47
53
  - !ruby/object:Gem::Version
48
54
  version: '0'
49
55
  type: :runtime
50
56
  prerelease: false
51
57
  version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
52
59
  requirements:
53
- - - '>='
60
+ - - ! '>='
54
61
  - !ruby/object:Gem::Version
55
62
  version: '0'
56
63
  - !ruby/object:Gem::Dependency
57
64
  name: awesome_print
58
65
  requirement: !ruby/object:Gem::Requirement
66
+ none: false
59
67
  requirements:
60
- - - '>='
68
+ - - ! '>='
61
69
  - !ruby/object:Gem::Version
62
70
  version: '0'
63
71
  type: :runtime
64
72
  prerelease: false
65
73
  version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
66
75
  requirements:
67
- - - '>='
76
+ - - ! '>='
68
77
  - !ruby/object:Gem::Version
69
78
  version: '0'
70
79
  - !ruby/object:Gem::Dependency
71
80
  name: table_print
72
81
  requirement: !ruby/object:Gem::Requirement
82
+ none: false
73
83
  requirements:
74
- - - '>='
84
+ - - ! '>='
75
85
  - !ruby/object:Gem::Version
76
86
  version: '0'
77
87
  type: :runtime
78
88
  prerelease: false
79
89
  version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
80
91
  requirements:
81
- - - '>='
92
+ - - ! '>='
82
93
  - !ruby/object:Gem::Version
83
94
  version: '0'
84
95
  - !ruby/object:Gem::Dependency
85
96
  name: highline
86
97
  requirement: !ruby/object:Gem::Requirement
98
+ none: false
87
99
  requirements:
88
- - - '>='
100
+ - - ! '>='
89
101
  - !ruby/object:Gem::Version
90
102
  version: '0'
91
103
  type: :runtime
92
104
  prerelease: false
93
105
  version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
94
107
  requirements:
95
- - - '>='
108
+ - - ! '>='
96
109
  - !ruby/object:Gem::Version
97
110
  version: '0'
98
- description: |
99
- Hammer cli provides universal extendable CLI interface for ruby apps
111
+ description: ! 'Hammer cli provides universal extendable CLI interface for ruby apps
112
+
113
+ '
100
114
  email: mbacovsk@redhat.com
101
115
  executables:
102
116
  - hammer
@@ -108,39 +122,40 @@ extra_rdoc_files:
108
122
  - config/cli_config.template.yml
109
123
  - doc/design.png
110
124
  - doc/design.uml
125
+ - doc/developer_docs.md
111
126
  files:
112
- - lib/hammer_cli/logger_watch.rb
113
- - lib/hammer_cli/apipie/write_command.rb
114
- - lib/hammer_cli/apipie/resource.rb
115
- - lib/hammer_cli/apipie/read_command.rb
116
- - lib/hammer_cli/apipie/options.rb
117
- - lib/hammer_cli/apipie/command.rb
118
- - lib/hammer_cli/logger.rb
127
+ - lib/hammer_cli.rb
119
128
  - lib/hammer_cli/messages.rb
120
- - lib/hammer_cli/option_formatters.rb
121
- - lib/hammer_cli/abstract.rb
122
- - lib/hammer_cli/apipie.rb
123
- - lib/hammer_cli/version.rb
124
- - lib/hammer_cli/exception_handler.rb
125
- - lib/hammer_cli/output.rb
126
- - lib/hammer_cli/autocompletion.rb
127
- - lib/hammer_cli/shell.rb
129
+ - lib/hammer_cli/output/fields.rb
130
+ - lib/hammer_cli/output/formatters.rb
128
131
  - lib/hammer_cli/output/adapter/table.rb
129
132
  - lib/hammer_cli/output/adapter/base.rb
130
133
  - lib/hammer_cli/output/adapter/abstract.rb
131
134
  - lib/hammer_cli/output/adapter/silent.rb
132
135
  - lib/hammer_cli/output/adapter/csv.rb
133
- - lib/hammer_cli/output/definition.rb
134
136
  - lib/hammer_cli/output/adapter.rb
135
- - lib/hammer_cli/output/dsl.rb
136
- - lib/hammer_cli/output/formatters.rb
137
137
  - lib/hammer_cli/output/output.rb
138
- - lib/hammer_cli/output/fields.rb
139
- - lib/hammer_cli/settings.rb
138
+ - lib/hammer_cli/output/dsl.rb
139
+ - lib/hammer_cli/output/definition.rb
140
+ - lib/hammer_cli/abstract.rb
141
+ - lib/hammer_cli/shell.rb
142
+ - lib/hammer_cli/autocompletion.rb
143
+ - lib/hammer_cli/logger_watch.rb
144
+ - lib/hammer_cli/logger.rb
145
+ - lib/hammer_cli/apipie.rb
146
+ - lib/hammer_cli/apipie/command.rb
147
+ - lib/hammer_cli/apipie/options.rb
148
+ - lib/hammer_cli/apipie/resource.rb
149
+ - lib/hammer_cli/apipie/write_command.rb
150
+ - lib/hammer_cli/apipie/read_command.rb
140
151
  - lib/hammer_cli/validator.rb
152
+ - lib/hammer_cli/version.rb
141
153
  - lib/hammer_cli/exit_codes.rb
154
+ - lib/hammer_cli/output.rb
155
+ - lib/hammer_cli/exception_handler.rb
142
156
  - lib/hammer_cli/main.rb
143
- - lib/hammer_cli.rb
157
+ - lib/hammer_cli/option_formatters.rb
158
+ - lib/hammer_cli/settings.rb
144
159
  - bin/hammer
145
160
  - README.md
146
161
  - LICENSE
@@ -148,29 +163,31 @@ files:
148
163
  - config/cli_config.template.yml
149
164
  - doc/design.png
150
165
  - doc/design.uml
166
+ - doc/developer_docs.md
151
167
  homepage: http://github.com/theforeman/hammer-cli
152
168
  licenses:
153
169
  - GPL-3
154
- metadata: {}
155
170
  post_install_message:
156
171
  rdoc_options: []
157
172
  require_paths:
158
173
  - lib
159
174
  required_ruby_version: !ruby/object:Gem::Requirement
175
+ none: false
160
176
  requirements:
161
- - - '>='
177
+ - - ! '>='
162
178
  - !ruby/object:Gem::Version
163
179
  version: '0'
164
180
  required_rubygems_version: !ruby/object:Gem::Requirement
181
+ none: false
165
182
  requirements:
166
- - - '>='
183
+ - - ! '>='
167
184
  - !ruby/object:Gem::Version
168
185
  version: '0'
169
186
  requirements: []
170
187
  rubyforge_project:
171
- rubygems_version: 2.0.8
188
+ rubygems_version: 1.8.24
172
189
  signing_key:
173
- specification_version: 4
190
+ specification_version: 3
174
191
  summary: Universal command-line interface
175
192
  test_files: []
176
193
  has_rdoc:
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 1f5774b64875357f58a29b8f41584e1257696886
4
- data.tar.gz: f1643f5fb4d1e545646e50ab663765b173684823
5
- SHA512:
6
- metadata.gz: 8ecb458b3c3cf2705a513431c718e5f2bac89c8528f7f11fe1f7364e32c66f20431801787a9d501dbef713b3f9f031750aa24c5f51465bd91778bd129cc867f4
7
- data.tar.gz: eec75c3547ddbe73e9ac5a772f617bb440da9f3ae425c330b7b53eaa9bd0841c246b09c4e3b085b1d9f9ea91754f6d955667816bd8fcce2108c3faed69f1c42f