ruby-jss 0.6.3
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.
Potentially problematic release.
This version of ruby-jss might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.yardopts +7 -0
- data/CHANGES.md +112 -0
- data/LICENSE.txt +174 -0
- data/README.md +426 -0
- data/THANKS.md +6 -0
- data/bin/cgrouper +485 -0
- data/bin/subnet-update +400 -0
- data/lib/jss-api.rb +2 -0
- data/lib/jss.rb +190 -0
- data/lib/jss/api_connection.rb +410 -0
- data/lib/jss/api_object.rb +616 -0
- data/lib/jss/api_object/advanced_search.rb +389 -0
- data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +95 -0
- data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +96 -0
- data/lib/jss/api_object/advanced_search/advanced_user_search.rb +95 -0
- data/lib/jss/api_object/building.rb +92 -0
- data/lib/jss/api_object/category.rb +147 -0
- data/lib/jss/api_object/computer.rb +852 -0
- data/lib/jss/api_object/creatable.rb +98 -0
- data/lib/jss/api_object/criteriable.rb +189 -0
- data/lib/jss/api_object/criteriable/criteria.rb +231 -0
- data/lib/jss/api_object/criteriable/criterion.rb +228 -0
- data/lib/jss/api_object/department.rb +93 -0
- data/lib/jss/api_object/distribution_point.rb +560 -0
- data/lib/jss/api_object/extendable.rb +221 -0
- data/lib/jss/api_object/extension_attribute.rb +466 -0
- data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +362 -0
- data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +189 -0
- data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +117 -0
- data/lib/jss/api_object/group.rb +380 -0
- data/lib/jss/api_object/group/computer_group.rb +124 -0
- data/lib/jss/api_object/group/mobile_device_group.rb +139 -0
- data/lib/jss/api_object/group/user_group.rb +139 -0
- data/lib/jss/api_object/ldap_server.rb +535 -0
- data/lib/jss/api_object/locatable.rb +286 -0
- data/lib/jss/api_object/matchable.rb +97 -0
- data/lib/jss/api_object/mobile_device.rb +556 -0
- data/lib/jss/api_object/netboot_server.rb +148 -0
- data/lib/jss/api_object/network_segment.rb +414 -0
- data/lib/jss/api_object/osx_configuration_profile.rb +262 -0
- data/lib/jss/api_object/package.rb +839 -0
- data/lib/jss/api_object/peripheral.rb +335 -0
- data/lib/jss/api_object/peripheral_type.rb +295 -0
- data/lib/jss/api_object/policy.rb +898 -0
- data/lib/jss/api_object/purchasable.rb +316 -0
- data/lib/jss/api_object/removable_macaddr.rb +98 -0
- data/lib/jss/api_object/scopable.rb +136 -0
- data/lib/jss/api_object/scopable/scope.rb +621 -0
- data/lib/jss/api_object/script.rb +631 -0
- data/lib/jss/api_object/self_servable.rb +356 -0
- data/lib/jss/api_object/site.rb +93 -0
- data/lib/jss/api_object/software_update_server.rb +109 -0
- data/lib/jss/api_object/updatable.rb +117 -0
- data/lib/jss/api_object/uploadable.rb +138 -0
- data/lib/jss/api_object/user.rb +272 -0
- data/lib/jss/client.rb +504 -0
- data/lib/jss/compatibility.rb +66 -0
- data/lib/jss/composer.rb +185 -0
- data/lib/jss/configuration.rb +306 -0
- data/lib/jss/db_connection.rb +298 -0
- data/lib/jss/exceptions.rb +95 -0
- data/lib/jss/ruby_extensions.rb +35 -0
- data/lib/jss/ruby_extensions/filetest.rb +43 -0
- data/lib/jss/ruby_extensions/hash.rb +79 -0
- data/lib/jss/ruby_extensions/ipaddr.rb +91 -0
- data/lib/jss/ruby_extensions/pathname.rb +77 -0
- data/lib/jss/ruby_extensions/string.rb +59 -0
- data/lib/jss/ruby_extensions/time.rb +63 -0
- data/lib/jss/server.rb +108 -0
- data/lib/jss/utility.rb +478 -0
- data/lib/jss/version.rb +31 -0
- metadata +187 -0
data/THANKS.md
ADDED
data/bin/cgrouper
ADDED
@@ -0,0 +1,485 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
### Copyright 2016 Pixar
|
4
|
+
###
|
5
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
6
|
+
### with the following modification; you may not use this file except in
|
7
|
+
### compliance with the Apache License and the following modification to it:
|
8
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
9
|
+
###
|
10
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
11
|
+
### names, trademarks, service marks, or product names of the Licensor
|
12
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
13
|
+
### the License and to reproduce the content of the NOTICE file.
|
14
|
+
###
|
15
|
+
### You may obtain a copy of the Apache License at
|
16
|
+
###
|
17
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
18
|
+
###
|
19
|
+
### Unless required by applicable law or agreed to in writing, software
|
20
|
+
### distributed under the Apache License with the above modification is
|
21
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
22
|
+
### KIND, either express or implied. See the Apache License for the specific
|
23
|
+
### language governing permissions and limitations under the Apache License.
|
24
|
+
|
25
|
+
|
26
|
+
# Create or change the membership of a computer group in the JSS
|
27
|
+
|
28
|
+
|
29
|
+
# Load in the JSS library
|
30
|
+
require 'jss-api'
|
31
|
+
|
32
|
+
# Load other libs
|
33
|
+
require 'getoptlong'
|
34
|
+
require 'ostruct'
|
35
|
+
|
36
|
+
class App
|
37
|
+
|
38
|
+
#####################################
|
39
|
+
###
|
40
|
+
### Constants
|
41
|
+
###
|
42
|
+
USAGE = "Usage: #{File.basename($0)} [-LsmcdlarRC] [--help] [-n newname]
|
43
|
+
[-S server] [-U user] [-T timeout] [-V] [--debug]
|
44
|
+
group [-f /file/path ] [computer [computer ...]]"
|
45
|
+
|
46
|
+
ACTIONS_NEEDING_GROUP = [ :create_group, :rename_group, :delete_group, :add_members, :remove_members, :remove_all, :list_members]
|
47
|
+
|
48
|
+
ACTIONS_FOR_STATIC_GROUPS_ONLY = [:create_group, :add_members, :remove_members, :remove_all]
|
49
|
+
|
50
|
+
#####################################
|
51
|
+
### Attributes
|
52
|
+
|
53
|
+
attr_reader :debug
|
54
|
+
|
55
|
+
#####################################
|
56
|
+
###
|
57
|
+
### set up
|
58
|
+
###
|
59
|
+
def initialize(args)
|
60
|
+
|
61
|
+
@debug = false
|
62
|
+
|
63
|
+
# define the options
|
64
|
+
cli_opts = GetoptLong.new(
|
65
|
+
[ '--help', '-h', '-H', GetoptLong::NO_ARGUMENT ],
|
66
|
+
[ '--list-groups', '-L', GetoptLong::NO_ARGUMENT ],
|
67
|
+
[ '--list-static', '-s', GetoptLong::NO_ARGUMENT ],
|
68
|
+
[ '--list-smart', '-m', GetoptLong::NO_ARGUMENT ],
|
69
|
+
[ '--create-group', '--create', '-c', GetoptLong::NO_ARGUMENT ],
|
70
|
+
[ '--rename-group', '--rename', '-n', GetoptLong::REQUIRED_ARGUMENT ],
|
71
|
+
[ '--delete-group', '--delete', '-d', GetoptLong::NO_ARGUMENT ],
|
72
|
+
[ '--list-members', '--list-computers', '-l', GetoptLong::NO_ARGUMENT ],
|
73
|
+
[ '--add-members', '--add', '-a', GetoptLong::NO_ARGUMENT ],
|
74
|
+
[ '--remove-members', '--remove', '-r', GetoptLong::NO_ARGUMENT ],
|
75
|
+
[ '--remove-all-members', '-R', GetoptLong::NO_ARGUMENT ],
|
76
|
+
[ '--file', '-f', GetoptLong::REQUIRED_ARGUMENT ],
|
77
|
+
[ '--server', '-S', GetoptLong::OPTIONAL_ARGUMENT],
|
78
|
+
[ '--port', '-P', GetoptLong::OPTIONAL_ARGUMENT],
|
79
|
+
[ '--user', '-U', GetoptLong::OPTIONAL_ARGUMENT],
|
80
|
+
[ '--no-verify-cert', '-V', GetoptLong::NO_ARGUMENT],
|
81
|
+
[ '--timeout', '-T', GetoptLong::OPTIONAL_ARGUMENT],
|
82
|
+
[ '--no-confirm', '-C', GetoptLong::NO_ARGUMENT],
|
83
|
+
[ '--debug', GetoptLong::NO_ARGUMENT]
|
84
|
+
)
|
85
|
+
|
86
|
+
# here's where we hold cmdline args and other user options
|
87
|
+
@options = OpenStruct.new
|
88
|
+
|
89
|
+
# set defaults
|
90
|
+
@options.action = :none
|
91
|
+
|
92
|
+
# if stdin is not a tty, then we must assume
|
93
|
+
# we're being passed a password
|
94
|
+
@options.getpass = $stdin.tty? ? :prompt : :stdin
|
95
|
+
|
96
|
+
# parse the options
|
97
|
+
cli_opts.each do |opt, arg|
|
98
|
+
case opt
|
99
|
+
when '--help'
|
100
|
+
show_help
|
101
|
+
|
102
|
+
when '--list-groups'
|
103
|
+
@options.action = :list_groups
|
104
|
+
|
105
|
+
when '--list-static'
|
106
|
+
@options.action = :list_static
|
107
|
+
|
108
|
+
when '--list-smart'
|
109
|
+
@options.action = :list_smart
|
110
|
+
|
111
|
+
when '--list-members'
|
112
|
+
@options.action = :list_members
|
113
|
+
|
114
|
+
when '--create-group'
|
115
|
+
@options.action = :create_group
|
116
|
+
|
117
|
+
when '--rename-group'
|
118
|
+
@options.action = :rename_group
|
119
|
+
@options.new_name = arg
|
120
|
+
|
121
|
+
when '--delete-group'
|
122
|
+
@options.action = :delete_group
|
123
|
+
|
124
|
+
when '--add-members'
|
125
|
+
@options.action = :add_members
|
126
|
+
|
127
|
+
when '--remove-members'
|
128
|
+
@options.action = :remove_members
|
129
|
+
|
130
|
+
when '--remove-all-members'
|
131
|
+
@options.action = :remove_all
|
132
|
+
|
133
|
+
when '--file'
|
134
|
+
@options.input_file = Pathname.new arg
|
135
|
+
|
136
|
+
when '--server'
|
137
|
+
@options.server = arg
|
138
|
+
|
139
|
+
when '--port'
|
140
|
+
@options.port = arg
|
141
|
+
|
142
|
+
when '--user'
|
143
|
+
@options.user = arg
|
144
|
+
|
145
|
+
when '--no-verify-cert'
|
146
|
+
@options.verify_cert = false
|
147
|
+
|
148
|
+
when '--timeout'
|
149
|
+
@options.timeout = arg
|
150
|
+
|
151
|
+
when '--no-confirm'
|
152
|
+
@options.no_confirm = true
|
153
|
+
|
154
|
+
when '--debug'
|
155
|
+
@debug = true
|
156
|
+
|
157
|
+
end # case
|
158
|
+
end # opts.each
|
159
|
+
|
160
|
+
@options.group = ARGV.shift
|
161
|
+
|
162
|
+
# if we were given a file of computer names, read it in
|
163
|
+
@options.computers = @options.input_file ? get_computers_from_file : []
|
164
|
+
|
165
|
+
# and add any computers on the commandline
|
166
|
+
@options.computers += ARGV
|
167
|
+
|
168
|
+
# will we say anything when finished?
|
169
|
+
@done_msg = nil
|
170
|
+
|
171
|
+
end # init
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
#####################################
|
176
|
+
###
|
177
|
+
### Do It
|
178
|
+
###
|
179
|
+
def run
|
180
|
+
|
181
|
+
if @options.action == :none
|
182
|
+
puts USAGE
|
183
|
+
return
|
184
|
+
end
|
185
|
+
|
186
|
+
# use any config settings defined....
|
187
|
+
@options.user ||= JSS::CONFIG.api_username
|
188
|
+
@options.server ||= JSS::CONFIG.api_server_name
|
189
|
+
|
190
|
+
raise JSS::MissingDataError, "No JSS Username provided or found in the JSS gem config." unless @options.user
|
191
|
+
raise JSS::MissingDataError, "No JSS Server provided or found in the JSS gem config." unless @options.server
|
192
|
+
|
193
|
+
JSS::API.connect( :server => @options.server,
|
194
|
+
:port => @options.port,
|
195
|
+
:verify_cert => @options.verify_cert,
|
196
|
+
:user => @options.user,
|
197
|
+
:pw => @options.getpass,
|
198
|
+
:stdin_line => 1,
|
199
|
+
:timeout => @options.timeout
|
200
|
+
)
|
201
|
+
|
202
|
+
|
203
|
+
if ACTIONS_NEEDING_GROUP.include? @options.action
|
204
|
+
|
205
|
+
raise JSS::MissingDataError, "Please specify a group name" unless @options.group
|
206
|
+
|
207
|
+
# get the group from the API
|
208
|
+
if @options.action == :create_group
|
209
|
+
@group = JSS::ComputerGroup.new :id => :new, :name => @options.group, :type => :static
|
210
|
+
else
|
211
|
+
@group = JSS::ComputerGroup.new :name => @options.group
|
212
|
+
end
|
213
|
+
|
214
|
+
end # if ACTIONS_NEEDING_GROUP
|
215
|
+
|
216
|
+
# smart groups can't have some things done to them
|
217
|
+
raise InvalidTypeError, "You can't do that to a smart group. Use the JSS WebApp if needed." if ACTIONS_FOR_STATIC_GROUPS_ONLY.include? @options.action and @group.smart?
|
218
|
+
|
219
|
+
|
220
|
+
case @options.action
|
221
|
+
|
222
|
+
when :list_groups
|
223
|
+
list_groups
|
224
|
+
|
225
|
+
when :list_static
|
226
|
+
list_groups :static
|
227
|
+
|
228
|
+
when :list_smart
|
229
|
+
list_groups :smart
|
230
|
+
|
231
|
+
when :list_members
|
232
|
+
list_members
|
233
|
+
|
234
|
+
when :create_group
|
235
|
+
create_group
|
236
|
+
|
237
|
+
when :rename_group
|
238
|
+
rename_group
|
239
|
+
|
240
|
+
when :delete_group
|
241
|
+
delete_group
|
242
|
+
|
243
|
+
when :add_members
|
244
|
+
add_members
|
245
|
+
|
246
|
+
when :remove_members
|
247
|
+
remove_members
|
248
|
+
|
249
|
+
when :remove_all
|
250
|
+
remove_all
|
251
|
+
|
252
|
+
end # case @options.action
|
253
|
+
|
254
|
+
puts "Done! #{@done_msg}" if @done_msg
|
255
|
+
|
256
|
+
end # run
|
257
|
+
|
258
|
+
|
259
|
+
#####################################
|
260
|
+
###
|
261
|
+
### Show Help
|
262
|
+
###
|
263
|
+
def show_help
|
264
|
+
puts <<-FULLHELP
|
265
|
+
A tool for working with computer groups in the JSS.
|
266
|
+
|
267
|
+
#{USAGE}
|
268
|
+
|
269
|
+
Options:
|
270
|
+
-L, --list-groups - list all computer groups in the JSS
|
271
|
+
-s, --list-static - list all static computer groups in the JSS
|
272
|
+
-m, --list-smart - list all smart computer groups in the JSS
|
273
|
+
-c, --create-group - create a new static computer group in the JSS
|
274
|
+
-n, --rename newname - rename the specified computer group to newname
|
275
|
+
-d, --delete - delete the specified computer group (static groups only)
|
276
|
+
-l, --list-members - list all the computers in the group specified
|
277
|
+
-a, --add-members - add the specified computer(s) to the specified group
|
278
|
+
-r, --remove-members - remove the specified computer(s) from the specified group
|
279
|
+
-R, --remove-all - remove all computers from the specified group
|
280
|
+
-f, --file /path/... - read computer names/ids from the file at /path/...
|
281
|
+
-S, --server srvr - specify the JSS API server name
|
282
|
+
-P, --port portnum - specify the JSS API port
|
283
|
+
-U, --user username - specify the JSS API user
|
284
|
+
-V, --no-verify-cert - Allow self-signed, unverified SSL certificate
|
285
|
+
-T, --timeout secs - specify the JSS API timeout
|
286
|
+
-C - don't ask for confirmation before acting
|
287
|
+
--debug - show the ruby backtrace when errors occur
|
288
|
+
-H, --help - show this help
|
289
|
+
|
290
|
+
Notes:
|
291
|
+
|
292
|
+
- If no API settings are provided, they will be read from /etc/jss_gem.conf
|
293
|
+
and ~/.jss_gem.conf. See the JSS Gem docs for details.
|
294
|
+
|
295
|
+
- The password for the connection will be read from STDIN or prompted if needed
|
296
|
+
|
297
|
+
- Computers can be specified by name or JSS id number. If a name exists
|
298
|
+
more than once in the JSS, the machine is skipped. Use IDs to avoid this.
|
299
|
+
|
300
|
+
- Only static groups can be modified. Use the JSS WebUI for editing smart groups
|
301
|
+
|
302
|
+
- If a file is used to specify computers, they are combined with any
|
303
|
+
specified on the commandline.
|
304
|
+
|
305
|
+
- Files of computers must be whitespace-separated
|
306
|
+
(spaces, tabs, & returns in any number or combination)
|
307
|
+
|
308
|
+
FULLHELP
|
309
|
+
return
|
310
|
+
end
|
311
|
+
|
312
|
+
#####################################
|
313
|
+
###
|
314
|
+
### Spit out a list of all computer groups
|
315
|
+
###
|
316
|
+
def list_groups(show = :all)
|
317
|
+
case show
|
318
|
+
when :all
|
319
|
+
label = "All"
|
320
|
+
groups_to_show = JSS::ComputerGroup.all
|
321
|
+
when :static
|
322
|
+
label = "Static"
|
323
|
+
groups_to_show = JSS::ComputerGroup.all_static
|
324
|
+
when :smart
|
325
|
+
label = "Smart"
|
326
|
+
groups_to_show = JSS::ComputerGroup.all_smart
|
327
|
+
end #case
|
328
|
+
|
329
|
+
puts "# #{label} computer groups in the JSS"
|
330
|
+
puts "#---------------------------------------------"
|
331
|
+
|
332
|
+
groups_to_show.sort{|a,b| a[:name].downcase <=> b[:name].downcase}.each do |grp|
|
333
|
+
puts grp[:name]
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
#####################################
|
338
|
+
###
|
339
|
+
### Spit out a list of all computers in a group
|
340
|
+
###
|
341
|
+
def list_members
|
342
|
+
puts "# All members of JSS #{@group.smart? ? 'smart' : 'static'} computer group '#{@options.group}'"
|
343
|
+
puts "#--- name (id) ---------------------------------"
|
344
|
+
|
345
|
+
# put them into a tmp array, so that
|
346
|
+
# we can sort by computer name, remembering that
|
347
|
+
# there can be duplicate names.
|
348
|
+
list = []
|
349
|
+
@group.members.each{|mem| list << "#{mem[:name]} (#{mem[:id]})" }
|
350
|
+
puts list.sort #.join("\n")
|
351
|
+
end
|
352
|
+
|
353
|
+
|
354
|
+
#####################################
|
355
|
+
###
|
356
|
+
### Create a new group
|
357
|
+
###
|
358
|
+
def create_group
|
359
|
+
|
360
|
+
return unless confirm "create a new static group named '#{@options.group}'"
|
361
|
+
@group.create
|
362
|
+
|
363
|
+
unless @options.computers.empty?
|
364
|
+
add_members
|
365
|
+
end
|
366
|
+
|
367
|
+
end
|
368
|
+
|
369
|
+
#####################################
|
370
|
+
###
|
371
|
+
### rename a group
|
372
|
+
###
|
373
|
+
def rename_group
|
374
|
+
return unless confirm "rename group '#{@group.name}' to '#{@options.new_name}'"
|
375
|
+
@group.name = @options.new_name
|
376
|
+
@group.update
|
377
|
+
end
|
378
|
+
|
379
|
+
|
380
|
+
#####################################
|
381
|
+
###
|
382
|
+
### delete a group
|
383
|
+
###
|
384
|
+
def delete_group
|
385
|
+
return unless confirm "DELETE group '#{@group.name}'"
|
386
|
+
@group.delete
|
387
|
+
end
|
388
|
+
|
389
|
+
|
390
|
+
#####################################
|
391
|
+
###
|
392
|
+
### add members to a group
|
393
|
+
###
|
394
|
+
def add_members
|
395
|
+
raise JSS::MissingDataError, "No computer names provided" if @options.computers.empty?
|
396
|
+
raise JSS::UnsupportedError, "Smart group members can't be changed." if @group.smart?
|
397
|
+
return unless @options.action == :create_group or confirm "add computers to group '#{@group.name}'"
|
398
|
+
|
399
|
+
@options.computers.each do |c|
|
400
|
+
begin
|
401
|
+
@group.add_member c
|
402
|
+
rescue JSS::NoSuchItemError
|
403
|
+
puts "#{$!} - skipping"
|
404
|
+
end # begin
|
405
|
+
end # each
|
406
|
+
|
407
|
+
@group.update
|
408
|
+
end
|
409
|
+
|
410
|
+
#####################################
|
411
|
+
###
|
412
|
+
### remove members from a group
|
413
|
+
###
|
414
|
+
def remove_members
|
415
|
+
raise JSS::MissingDataError, "No computer names provided" if @options.computers.empty?
|
416
|
+
raise JSS::UnsupportedError, "Smart group members can't be changed." if @group.smart?
|
417
|
+
return unless confirm "remove computers from group '#{@group.name}'"
|
418
|
+
@options.computers.each do |c|
|
419
|
+
begin
|
420
|
+
@group.remove_member c
|
421
|
+
rescue JSS::NoSuchItemError
|
422
|
+
puts "#{$!} - skipping"
|
423
|
+
end
|
424
|
+
end
|
425
|
+
@group.update
|
426
|
+
end
|
427
|
+
|
428
|
+
#####################################
|
429
|
+
###
|
430
|
+
### remove all members from a group
|
431
|
+
###
|
432
|
+
def remove_all
|
433
|
+
raise JSS::UnsupportedError, "Smart group members can't be changed." if @group.smart?
|
434
|
+
return unless confirm "remove ALL computers from group '#{@group.name}'"
|
435
|
+
@group.clear
|
436
|
+
@group.update
|
437
|
+
end
|
438
|
+
|
439
|
+
|
440
|
+
#####################################
|
441
|
+
###
|
442
|
+
### Read computer names from a file
|
443
|
+
### Generally the names should be one per line, but
|
444
|
+
### they can be separated by any whitespace.
|
445
|
+
### Returns an array of computer names from the file.
|
446
|
+
###
|
447
|
+
def get_computers_from_file
|
448
|
+
raise JSS::NoSuchItemError "File #{@options.input_file} isn't a file or isn't readable." unless \
|
449
|
+
@options.input_file.file? and @options.input_file.readable?
|
450
|
+
@options.input_file.read.split(/\s+/)
|
451
|
+
end
|
452
|
+
|
453
|
+
#####################################
|
454
|
+
###
|
455
|
+
### Get confirmation before doing something
|
456
|
+
### Returns true or false
|
457
|
+
###
|
458
|
+
def confirm (action)
|
459
|
+
return true if @options.no_confirm
|
460
|
+
|
461
|
+
print "Really #{action}? (y/n): "
|
462
|
+
$stdin.reopen '/dev/tty'
|
463
|
+
reply = $stdin.gets.strip
|
464
|
+
return true if reply =~ /^y/i
|
465
|
+
return false
|
466
|
+
|
467
|
+
end # confirm
|
468
|
+
|
469
|
+
|
470
|
+
end # class App
|
471
|
+
|
472
|
+
#######################################
|
473
|
+
begin
|
474
|
+
app = App.new(ARGV)
|
475
|
+
app.run
|
476
|
+
|
477
|
+
rescue
|
478
|
+
# handle exceptions not handled elsewhere
|
479
|
+
puts "An error occurred: #{$!}"
|
480
|
+
puts "Backtrace:" if app.debug
|
481
|
+
puts $@ if app.debug
|
482
|
+
|
483
|
+
ensure
|
484
|
+
|
485
|
+
end
|