depot3 3.0.15 → 3.0.20

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e483eb6fd0aae3cf4d824414f9cf8c1e7d78bec
4
- data.tar.gz: 2dc642d46f5adc58ca5b6c980492ba71e8b3d93e
3
+ metadata.gz: d3d60e7335e71cc42cfc47dc4e475f0a4b5237de
4
+ data.tar.gz: 85731430c8d7fbdc501a8ab72ef2dc68b7936594
5
5
  SHA512:
6
- metadata.gz: a7b6a499e95d949397c4091b1314a7321c84054cf69d7ee60eda10a02feef3740dd5e02038fb99cf5e5c5b938924b410f1323ec02d29071963019ddac924ae2a
7
- data.tar.gz: c98a7abc85aded9092ad66cb7657deba7b18bf665e4b182eaa88e99fa47919a1d7123d0e08d9a0bed109ebec492bfafdb88ed948617066fb2022faa27a0f6d55
6
+ metadata.gz: 7d8c26bddb9d57ead819dce286f3f2977fd96054a221cdd10e7f0b7ca21b1050c23f3a98bcc841b2146eb25daa02f8f6b017605d6ffe6959dcc1eabd4007aece
7
+ data.tar.gz: 9792ad3083342ab81257eace8ab0f0d9413fcbb94152a3e19ef62ee5f987c15ac76bb60c3d361de642e98e5edb8a0e663ce9bb92534844578207bde3621aa034
data/CHANGES.md CHANGED
@@ -1,6 +1,26 @@
1
1
  # Change History
2
2
 
3
- ## v3.0.14 - 2017-02-28
3
+ ## v3.0.20 - 2018-06-27
4
+ - Added: validate that a pkg is available via cloud before trying to install it that way
5
+ - Change: better backtrace logging
6
+ - Change: better error reporting when client passwd retrieval fails
7
+ - Fix: bug preventing puppies to install from the puppy queue
8
+
9
+ ## v3.0.19 - 2018-03-31
10
+ - Added: signing identity and signing prefs to d3admin add, when building .pkgs
11
+ - Added: A default description editer (e.g. vi, emacs, pico) can be saved in admin prefs
12
+ - Fix: return nil when asked for current foreground application on client, and there is none.
13
+
14
+ ## v3.0.18 - 2017-12-01
15
+ - Change: D3::Client.install: freeze prev. installed rcpts when 'freeze on install' requested.
16
+
17
+ ## v3.0.17 - 2017-07-14
18
+ - Fix: D3::Package.upload_master_file, call #update after #super
19
+
20
+ ## v3.0.16 - 2017-04-10
21
+ - Update: Max DB schema version bumped for 9.98 and 9.99
22
+
23
+ ## v3.0.15 - 2017-02-28
4
24
  - Bugfix: now correctly finds the most recent timestamp for an expiration path coming to the foreground
5
25
 
6
26
  ## v3.0.14 - 2016-12-08
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # d3 - Command line package and patch management for Casper
2
2
 
3
- d3 is a package deployment and patch management system for OS X that enhances the
4
- [Casper Suite](http://www.jamfsoftware.com/products/casper-suite/), an enterprise-level management system for Apple devices from [JAMF Software](http://www.jamfsoftware.com/). It was created by [Pixar Animation Studios](http://www.pixar.com/).
3
+ d3 (a.k.a. depot3) is a package deployment and patch management system for OS X that enhances
4
+ [Jamf Pro](https://www.jamf.com/products/jamf-pro/), an enterprise-level management system for Apple devices from [JAMF Software](http://www.jamf.com/). It was created by [Pixar Animation Studios](http://www.pixar.com/).
5
5
 
6
6
 
7
- d3 adds these capabilities and more to Casper's package handling:
7
+ d3 adds these capabilities and more to Jamf Pro's package handling:
8
8
 
9
9
  * Automatic software updates on clients when new versions are released on the server
10
10
  * Pre-release piloting of new packages
@@ -14,7 +14,7 @@ d3 adds these capabilities and more to Casper's package handling:
14
14
  * Both the client and admin tools are command-line only and fully scriptable
15
15
  * Admin command-line options allow integration with developer workflows and package-retrieval tools
16
16
 
17
- d3 is written in Ruby and available as a rubygem called ['depot3'](https://rubygems.org/gems/depot3). It interfaces with Casper via its REST API using [ruby-jss](https://github.com/PixarAnimationStudios/ruby-jss), a ruby module that provides simple and powerful access to the API. It also uses Casper's backend MySQL database directly to provide enhanced features.
17
+ d3 is written in Ruby and available as a rubygem called ['depot3'](https://rubygems.org/gems/depot3). It interfaces with Jamf Pro via its REST API using [ruby-jss](https://github.com/PixarAnimationStudios/ruby-jss), a ruby module that provides simple and powerful access to the API. It also uses Jamf Pro's backend MySQL database directly to provide enhanced features.
18
18
 
19
19
  ## DOCUMENTATION
20
20
 
@@ -22,7 +22,7 @@ Full user/administrator documentation is available at the [GitHub project's wiki
22
22
 
23
23
  The developer documentation for the D3 ruby module is at [http://www.rubydoc.info/gems/depot3](http://www.rubydoc.info/gems/depot3).
24
24
 
25
- Also check out [ruby-jss](https://github.com/PixarAnimationStudios/ruby-jss), which is used by d3, but is useful for working with the Casper REST API in any project.
25
+ Also check out [ruby-jss](https://github.com/PixarAnimationStudios/ruby-jss), which is used by d3, but is useful for working with the Jamf Pro REST API in any project.
26
26
 
27
27
 
28
28
  ## CONTACT
@@ -33,7 +33,7 @@ Also check out [ruby-jss](https://github.com/PixarAnimationStudios/ruby-jss), wh
33
33
 
34
34
  ## LICENSE
35
35
 
36
- Copyright 2016 Pixar
36
+ Copyright 2017 Pixar
37
37
 
38
38
  Licensed under the Apache License, Version 2.0 (the "Apache License")
39
39
  with the following modification; you may not use d3 except in
data/bin/d3 CHANGED
@@ -332,10 +332,10 @@ begin
332
332
  app = App.new(ARGV)
333
333
  app.run
334
334
 
335
- rescue
335
+ rescue => e
336
336
  # handle exceptions not handled elsewhere
337
- D3.log "An error occurred: #{$!.class}: #{$!}", :fatal
338
- D3.log_backtrace
337
+ D3.log "An error occurred: #{e.class}: #{e}", :fatal
338
+ D3.log_backtrace e
339
339
  exit 1
340
340
  ensure
341
341
  if JSS::API.connected?
@@ -44,8 +44,6 @@
44
44
  # Load libraries
45
45
  require 'd3'
46
46
 
47
-
48
-
49
47
  ######################
50
48
  # The Script Object
51
49
  ######################
@@ -53,19 +51,16 @@ class App
53
51
 
54
52
  ### Setup
55
53
  def initialize
56
-
57
54
  ### parse the commandline
58
55
  parse_commandline
59
56
 
60
57
  # can't be run as root other than help, search or report - no keychain, among other things
61
- raise "d3admin can't make server changes as root" if JSS.superuser? and (not @action =~ /^[hsr]/)
62
-
63
- end #initialize
58
+ raise "d3admin can't make server changes as root" if JSS.superuser? && (!@action =~ /^[hsr]/)
59
+ end # initialize
64
60
 
65
61
  ### Run
66
62
  def run
67
-
68
- if @action == "help"
63
+ if @action == 'help'
69
64
  show_help @options.helptype
70
65
  return
71
66
  end
@@ -73,7 +68,7 @@ class App
73
68
  # run config if it hasn't ever run
74
69
  unless D3::Admin::Prefs.prefs[:last_config] || JSS.superuser?
75
70
  puts
76
- puts "******** INITIAL D3ADMIN CONFIGURATION ********"
71
+ puts '******** INITIAL D3ADMIN CONFIGURATION ********'
77
72
  puts
78
73
  config
79
74
  # but dont run it again if that's the action chosen
@@ -84,12 +79,12 @@ class App
84
79
  @admin = @options.admin || ENV['USER']
85
80
 
86
81
  # admin can't be a badmin
87
- if D3.badmins.include? @admin and D3::Admin::ACTIONS_NEEDING_ADMIN.include? @action
82
+ if (D3.badmins.include? @admin) && (D3::Admin::ACTIONS_NEEDING_ADMIN.include? @action)
88
83
  raise D3::PermissionError, "d3admin cannot do '#{@action}' as #{@admin}."
89
84
  end
90
85
 
91
86
  # config before connecting
92
- if @action =~ /^c/ and !JSS.superuser?
87
+ if @action =~ /^c/ && !JSS.superuser?
93
88
  config
94
89
  return
95
90
  end
@@ -103,43 +98,40 @@ class App
103
98
 
104
99
  case @action
105
100
 
106
- when /^a/ then
107
- add_pilot_package
101
+ when /^a/ then
102
+ add_pilot_package
108
103
 
109
- when /^e/ then
110
- edit_package
104
+ when /^e/ then
105
+ edit_package
111
106
 
112
- when /^l/ then
113
- make_package_live
107
+ when /^l/ then
108
+ make_package_live
114
109
 
115
- when /^d/ then
116
- delete_package
110
+ when /^d/ then
111
+ delete_package
117
112
 
118
- when /^i/ then
119
- show_package_info
113
+ when /^i/ then
114
+ show_package_info
120
115
 
121
- when /^s/ then
122
- search
116
+ when /^s/ then
117
+ search
123
118
 
124
- when /^r/ then
125
- show_report
119
+ when /^r/ then
120
+ show_report
126
121
 
127
- else
128
- raise ArgumentError, "#{D3::Admin::Help::USAGE}\nUnknown action, must be one of #{D3::Admin::ACTIONS.join(', ')}"
122
+ else
123
+ raise ArgumentError, "#{D3::Admin::Help::USAGE}\nUnknown action, must be one of #{D3::Admin::ACTIONS.join(', ')}"
129
124
 
130
125
  end # case
131
-
132
-
133
- end #run
126
+ end # run
134
127
 
135
128
  ### Parse the command line
136
129
  ###
137
130
  ### @return [void]
138
131
  ###
139
132
  def parse_commandline
140
-
141
133
  # Debugging file? if so, always set debug.
142
- ARGV << "--debug" if D3::DEBUG_FILE.exist?
134
+ ARGV << '--debug' if D3::DEBUG_FILE.exist?
143
135
 
144
136
  # this holds everything that comes from the commandline
145
137
  # or from prompting the user
@@ -153,145 +145,144 @@ class App
153
145
  @options.status = []
154
146
 
155
147
  ### see Admin::CLIOpts
156
- opt_arry = D3::Admin::OPTIONS.values.map{|o| o[:cli] }
157
- opts = GetoptLong.new *opt_arry
148
+ opt_arry = D3::Admin::OPTIONS.values.map { |o| o[:cli] }
149
+ opts = GetoptLong.new(*opt_arry)
158
150
 
159
151
  opts.each do |opt, arg|
160
152
  case opt
161
153
 
162
- #general
163
- when '--help'
164
- @action = "help"
165
- @options.helptype = :help
166
- return
167
- when '--extended-help'
168
- @action = "help"
169
- @options.helptype = :extended_help
170
- return
171
- when '--debug'
172
- D3::Admin.debug = true
173
-
174
- when '--d3-version'
175
- @action = "help"
176
- @options.helptype = :show_d3_version
177
- return
178
-
179
- when '--walkthru'
180
- @options.walkthru = true
181
- when '--auto-confirm'
182
- @options.auto_confirm = true
183
-
184
- when '--admin'
185
- @options.admin = arg
186
-
187
- # search and report
188
- when '--status'
189
- @options.status += arg.split(/,\s*/)
190
- when '--queue'
191
- @options.report_q = true
192
- when '--frozen'
193
- @options.report_frozen = true
194
- when '--computers'
195
- @options.report_computers = true
196
- when '--groups'
197
- @options.search_groups = true
198
- # add/edit
199
- when '--import'
200
- @options.import = true
201
- @options.import_from = arg.empty? ? nil : arg
202
- when '--no-inherit'
203
- @options.no_inherit = true
204
- when '--basename'
205
- @options.basename = arg
206
- when '--version'
207
- @options.version = arg
208
- when '--revision'
209
- @options.revision = arg
210
- when '--description'
211
- @options.description = arg
212
- when '--package-name'
213
- @options.package_name = arg
214
- when '--filename'
215
- @options.filename = arg
216
- when '--edition'
217
- @options.edition = arg
218
- when '--source-path'
219
- @options.source_path = arg
220
- when '--dmg'
221
- @options.package_build_type = 'd'
222
- when '--preserve-owners'
223
- @options.pkg_preserve_owners = 'y'
224
- when '--pkg-id'
225
- @options.pkg_identifier = arg
226
- when '--workspace'
227
- @options.workspace = arg
228
- when '--pre-install'
229
- @options.pre_install = arg
230
- when '--post-install'
231
- @options.post_install = arg
232
- when '--pre-remove'
233
- @options.pre_remove = arg
234
- when '--post-remove'
235
- @options.post_remove = arg
236
- when '--auto-groups'
237
- @options.auto_groups = arg
238
- when '--excluded-groups'
239
- @options.excluded_groups = arg
240
- when '--prohibiting-processes'
241
- @options.prohibiting_processes = arg
242
- when '--cpu_type'
243
- @options.cpu_type = arg
244
- when '--category'
245
- @options.category = arg
246
-
247
- when '--reboot'
248
- # dft is no, so if arg is empty or /^n(o)$/i, it should be nil,
249
- # otherwise must be /^y(es)$/i
250
- if arg.empty? or arg =~ /^no?$/i
251
- @options.reboot = "n"
252
- elsif arg =~ /^y(es)?$/i
253
- @options.reboot = "y"
254
- else
255
- raise ArgumentError, "--reboot must be 'y' or 'n'"
256
- end
154
+ # General
155
+ when '--help'
156
+ @action = 'help'
157
+ @options.helptype = :help
158
+ break
159
+ when '--extended-help'
160
+ @action = 'help'
161
+ @options.helptype = :extended_help
162
+ break
163
+ when '--debug'
164
+ D3::Admin.debug = true
165
+ when '--d3-version'
166
+ @action = 'help'
167
+ @options.helptype = :show_d3_version
168
+ break
169
+ when '--walkthru'
170
+ @options.walkthru = true
171
+ when '--auto-confirm'
172
+ @options.auto_confirm = true
173
+ when '--admin'
174
+ @options.admin = arg
175
+
176
+ # Search and Report
177
+ when '--status'
178
+ @options.status += arg.split(/,\s*/)
179
+ when '--queue'
180
+ @options.report_q = true
181
+ when '--frozen'
182
+ @options.report_frozen = true
183
+ when '--computers'
184
+ @options.report_computers = true
185
+ when '--groups'
186
+ @options.search_groups = true
187
+
188
+ # Add/Edit
189
+ when '--import'
190
+ @options.import = true
191
+ @options.import_from = arg.empty? ? nil : arg
192
+ when '--no-inherit'
193
+ @options.no_inherit = true
194
+ when '--basename'
195
+ @options.basename = arg
196
+ when '--version'
197
+ @options.version = arg
198
+ when '--revision'
199
+ @options.revision = arg
200
+ when '--description'
201
+ @options.description = arg
202
+ when '--package-name'
203
+ @options.package_name = arg
204
+ when '--filename'
205
+ @options.filename = arg
206
+ when '--edition'
207
+ @options.edition = arg
208
+ when '--source-path'
209
+ @options.source_path = arg
210
+ when '--dmg'
211
+ @options.package_build_type = 'd'
212
+ when '--preserve-owners'
213
+ @options.pkg_preserve_owners = 'y'
214
+ when '--pkg-id'
215
+ @options.pkg_identifier = arg
216
+ when '--workspace'
217
+ @options.workspace = arg
218
+ when '--pre-install'
219
+ @options.pre_install = arg
220
+ when '--post-install'
221
+ @options.post_install = arg
222
+ when '--pre-remove'
223
+ @options.pre_remove = arg
224
+ when '--post-remove'
225
+ @options.post_remove = arg
226
+ when '--auto-groups'
227
+ @options.auto_groups = arg
228
+ when '--excluded-groups'
229
+ @options.excluded_groups = arg
230
+ when '--prohibiting-processes'
231
+ @options.prohibiting_processes = arg
232
+ when '--cpu_type'
233
+ @options.cpu_type = arg
234
+ when '--category'
235
+ @options.category = arg
236
+
237
+ when '--reboot'
238
+ # dft is no, so if arg is empty or /^n(o)$/i, it should be nil,
239
+ # otherwise must be /^y(es)$/i
240
+ if arg.empty? || arg =~ /^no?$/i
241
+ @options.reboot = 'n'
242
+ elsif arg =~ /^y(es)?$/i
243
+ @options.reboot = 'y'
244
+ else
245
+ raise ArgumentError, "--reboot must be 'y' or 'n'"
246
+ end
257
247
 
258
- when '--remove-first'
259
- # dft is no, so if arg is empty or /^n(o)$/i, it should be nil,
260
- # otherwise must be /^y(es)$/i
261
- if arg.empty? or arg =~ /^no?$/i
262
- @options.remove_first = "n"
263
- elsif arg =~ /^y(es)?$/i
264
- @options.remove_first = "y"
265
- else
266
- raise ArgumentError, "--remove-first must be 'y' or 'n'"
267
- end
248
+ when '--remove-first'
249
+ # dft is no, so if arg is empty or /^n(o)$/i, it should be nil,
250
+ # otherwise must be /^y(es)$/i
251
+ if arg.empty? || arg =~ /^no?$/i
252
+ @options.remove_first = 'n'
253
+ elsif arg =~ /^y(es)?$/i
254
+ @options.remove_first = 'y'
255
+ else
256
+ raise ArgumentError, "--remove-first must be 'y' or 'n'"
257
+ end
268
258
 
269
- when '--removable'
270
- # dft is yes, so if arg is empty or /^y(es)$/i, it should be nil,
271
- # otherwise must be /^n(o)$/i
272
- if arg.empty? or arg =~ /^y(es)?$/i
273
- @options.removable = "y"
274
- elsif arg =~ /^no?$/i
275
- @options.removable = "n"
276
- else
277
- raise ArgumentError, "--removable must be 'y' or 'n'"
278
- end
259
+ when '--removable'
260
+ # dft is yes, so if arg is empty or /^y(es)$/i, it should be nil,
261
+ # otherwise must be /^n(o)$/i
262
+ if arg.empty? || arg =~ /^y(es)?$/i
263
+ @options.removable = 'y'
264
+ elsif arg =~ /^no?$/i
265
+ @options.removable = 'n'
266
+ else
267
+ raise ArgumentError, "--removable must be 'y' or 'n'"
268
+ end
279
269
 
280
- when '--oses'
281
- @options.oses = arg
282
- when '--expiration'
283
- @options.expiration = arg
284
- when '--expiration-path', '--expiration_paths'
285
- @options.expiration_paths = arg
270
+ when '--oses'
271
+ @options.oses = arg
272
+ when '--expiration'
273
+ @options.expiration = arg
274
+ when '--expiration-path', '--expiration_paths'
275
+ @options.expiration_paths = arg
286
276
 
287
- # delete
288
- when '--keep-scripts'
289
- @options.keep_scripts = 'y'
290
- when '--keep-in-jss'
291
- @options.keep_in_jss = 'y'
277
+ # Delete
278
+ when '--keep-scripts'
279
+ @options.keep_scripts = 'y'
280
+ when '--keep-in-jss'
281
+ @options.keep_in_jss = 'y'
292
282
 
293
283
  end # case
294
284
  end # opts.each
285
+ return if @action == 'help'
295
286
 
296
287
  # the action is always the first thing in ARGV
297
288
  # after the options have been removed
@@ -302,40 +293,39 @@ class App
302
293
  end
303
294
 
304
295
  # one or more letters is all we need to specify the action...
305
- @action = D3::Admin::ACTIONS.select{|a| a.start_with? action_arg}.first
296
+ @action = D3::Admin::ACTIONS.select { |a| a.start_with? action_arg }.first
306
297
 
307
- unless @action and D3::Admin::ACTIONS.include? @action
298
+ unless @action && (D3::Admin::ACTIONS.include? @action)
308
299
  raise ArgumentError, "#{D3::Admin::Help::USAGE}\nAction, must be one of #{D3::Admin::ACTIONS.join(', ')}"
309
300
  end
310
301
 
311
302
  # anything remaining in ARGV is one or more targets
312
303
  # to work on.
313
304
  @targets = ARGV
314
-
315
305
  end # parse_commandline
316
306
 
317
307
  ### Show the help message
318
308
  ###
319
309
  ### @return [void]
320
310
  ###
321
- def show_help (type)
311
+ def show_help(type)
322
312
  text = case type
323
313
  when :help
324
- D3::Admin::Help.help_text
314
+ D3::Admin::Help.help_text
325
315
  when :extended_help
326
316
  D3::Admin::Help.extended_help_text
327
317
  when :show_d3_version
328
318
  d3_version_text
329
319
  end
330
320
  D3.less_text text
331
- return true
332
- end #show help
321
+ true
322
+ end # show help
333
323
 
334
324
  ### the d3 version text to spew
335
325
  ###
336
326
  ### @return [String] the text
337
327
  def d3_version_text
338
- <<-ENDVERS
328
+ <<-ENDVERS
339
329
  D3 module version: #{D3::VERSION}
340
330
  JSS module version: #{JSS::VERSION}
341
331
  ENDVERS
@@ -344,22 +334,20 @@ ENDVERS
344
334
  ### Add a new pilot package from an existing
345
335
  ### JSS package
346
336
  def import_pilot_pkg_from_jss
347
-
348
337
  if @options.walkthru
349
338
  @options.import_from = D3::Admin::Interactive.get_value :import unless @options.import_from
350
339
  @options.version = D3::Admin::Interactive.get_value :version
351
340
  @options.revision = D3::Admin::Interactive.get_value :revision
352
341
  else
353
- raise JSS::MissingDataError, "A version must be provided with --version" unless @options.version
354
- raise JSS::MissingDataError, "A revision must be provided with --revision" unless @options.revision
342
+ raise JSS::MissingDataError, 'A version must be provided with --version' unless @options.version
343
+ raise JSS::MissingDataError, 'A revision must be provided with --revision' unless @options.revision
355
344
  end # if walk thru
356
345
 
357
- imported_pkg = D3::Package.import( @options.import_from,
358
- basename: @options.basename,
359
- version: @options.version,
360
- revision: @options.revision,
361
- dist_pw: D3::Admin::Auth.rw_credentials(:dist)[:password]
362
- )
346
+ imported_pkg = D3::Package.import(@options.import_from,
347
+ basename: @options.basename,
348
+ version: @options.version,
349
+ revision: @options.revision,
350
+ dist_pw: D3::Admin::Auth.rw_credentials(:dist)[:password])
363
351
  imported_pkg.admin = @admin
364
352
  edit_package imported_pkg
365
353
  end
@@ -376,13 +364,12 @@ ENDVERS
376
364
  ### @return [void]
377
365
  ###
378
366
  def add_pilot_package
379
-
380
367
  ## we must have a basename before going farther
381
368
  @options.basename = @targets.first
382
369
  if @options.walkthru
383
370
  @options.basename ||= D3::Admin::Interactive.get_basename
384
371
  else
385
- raise ArgumentError, "A basename must be provided as a target. Use -H for help" unless @options.basename
372
+ raise ArgumentError, 'A basename must be provided as a target. Use -H for help' unless @options.basename
386
373
  end
387
374
 
388
375
  if @options.import
@@ -390,7 +377,7 @@ ENDVERS
390
377
  return
391
378
  end
392
379
 
393
- puts "Adding a new pilot package to d3..."
380
+ puts 'Adding a new pilot package to d3...'
394
381
 
395
382
  # this holds the validated data used for making the new pkg
396
383
  new_package_options = OpenStruct.new
@@ -408,7 +395,7 @@ ENDVERS
408
395
 
409
396
  # if we were given a new version but not a new revision,
410
397
  # set the new revision to 1
411
- if @options[:version] and @options[:version] != default_options[:version]
398
+ if @options[:version] && @options[:version] != default_options[:version]
412
399
  @options[:revision] ||= 1
413
400
  @options[:edition] ||= "#{@options.basename}-#{@options[:version]}-#{@options[:revision]}"
414
401
  @options.package_name ||= @options[:edition]
@@ -419,7 +406,6 @@ ENDVERS
419
406
  # for any options that weren't given on the commandline, use the defaults
420
407
  default_options.each_pair { |opt, val| @options[opt] ||= val }
421
408
 
422
-
423
409
  new_package_options = D3::Admin::Add.add_pilot_cli(@options)
424
410
 
425
411
  ##########################
@@ -436,7 +422,7 @@ ENDVERS
436
422
  opts_to_confirm += D3::Admin::Add::BUILD_OPTIONS if new_package_options.package_build_type
437
423
  opts_to_confirm += D3::Admin::Add::PKG_OPTIONS if new_package_options.package_build_type == :pkg
438
424
 
439
- #D3::Admin::Add::NEW_PKG_OPTIONS.each do |opt|
425
+ # D3::Admin::Add::NEW_PKG_OPTIONS.each do |opt|
440
426
  opts_to_confirm.each do |opt|
441
427
  lbl = D3::Admin::OPTIONS[opt][:label]
442
428
  if D3::Admin::OPTIONS[opt][:display_conversion]
@@ -444,11 +430,11 @@ ENDVERS
444
430
  else
445
431
  disp = new_package_options[opt]
446
432
  end
447
- lines << "#{lbl}: #{disp}"
433
+ lines << "#{lbl}: #{disp}"
448
434
  end
449
435
  settings_conf_disp = "\n******* New d3 Package Settings *******\n"
450
- settings_conf_disp += "Edition: #{ new_package_options.edition}\n"
451
- settings_conf_disp += "Basename: #{ new_package_options.basename}\n"
436
+ settings_conf_disp += "Edition: #{new_package_options.edition}\n"
437
+ settings_conf_disp += "Basename: #{new_package_options.basename}\n"
452
438
  settings_conf_disp += lines.join "\n"
453
439
  settings_conf_disp += "\n"
454
440
  puts settings_conf_disp
@@ -459,10 +445,9 @@ ENDVERS
459
445
 
460
446
  D3::Admin::Add.add_new_package new_package_options
461
447
 
462
- puts "Done!"
448
+ puts 'Done!'
463
449
  puts "To pilot it, run 'sudo d3 install #{new_package_options.edition}' on a test machine."
464
450
  puts "To make it live, run 'd3admin live #{new_package_options.edition}' on your machine."
465
-
466
451
  end # add pilot
467
452
 
468
453
  ### Make a package live.
@@ -470,11 +455,10 @@ ENDVERS
470
455
  ### @return [void]
471
456
  ###
472
457
  def make_package_live
473
-
474
458
  pkg_id = get_pkg_from_cli_or_prompt
475
459
 
476
460
  if pkg_id.nil?
477
- puts "No edition given to make live or no matching package found"
461
+ puts 'No edition given to make live or no matching package found'
478
462
  return
479
463
  end
480
464
  pkg = D3::Package.new id: pkg_id
@@ -485,33 +469,33 @@ ENDVERS
485
469
  end
486
470
 
487
471
  # is this a rollback?
488
- rollback_warning = ""
489
- if pkg.skipped? or pkg.deprecated?
472
+ rollback_warning = ''
473
+ if pkg.skipped? || pkg.deprecated?
490
474
  rollback_warning = "\n\nWARNING: You're rolling back to an older edition!\n"
491
475
  rollback_warning += "ALL non-frozen installs of '#{pkg.basename}' will be downgraded to this edition! \n"
492
476
  end
493
477
 
494
478
  # is the prev. live pkg in use in any policies?
495
- policy_warning = ""
479
+ policy_warning = ''
496
480
  pkg_id_being_deprecated = D3::Package.basenames_to_live_ids[pkg.basename]
497
481
  if pkg_id_being_deprecated
498
482
  outgoing_pkg = D3::Package.new(id: pkg_id_being_deprecated)
499
- pols_used_by_old_pkg = outgoing_pkg.policy_ids
483
+ pols_used_by_old_pkg = outgoing_pkg.policy_ids
500
484
  unless pols_used_by_old_pkg.empty?
501
- names = pols_used_by_old_pkg.map{|pid| JSS::Policy.map_all_ids_to(:name)[pid]}.join(', ')
485
+ names = pols_used_by_old_pkg.map { |pid| JSS::Policy.map_all_ids_to(:name)[pid] }.join(', ')
502
486
  policy_warning = "\n\nWARNING: the current live package is in use by these Casper Policies:\n"
503
487
  policy_warning += " #{names}\n"
504
- policy_warning += "You might want to update them to use the new live package."
488
+ policy_warning += 'You might want to update them to use the new live package.'
505
489
  end # unless empty
506
490
  end # if pkg_id_being_deprecated
507
491
 
508
- confirm "Make #{pkg.edition} live for basename '#{pkg.basename}'#{rollback_warning}#{policy_warning}" , ""
492
+ confirm "Make #{pkg.edition} live for basename '#{pkg.basename}'#{rollback_warning}#{policy_warning}", ''
509
493
 
510
494
  pkg.make_live @admin
511
495
 
512
- puts "Done!"
496
+ puts 'Done!'
513
497
  puts "New installs of basename '#{pkg.basename}' will get #{pkg.version}-#{pkg.revision}"
514
- puts "Existing installs will be updated at the next d3 sync."
498
+ puts 'Existing installs will be updated at the next d3 sync.'
515
499
  end
516
500
 
517
501
  ### Edit an existing or importing package
@@ -521,23 +505,20 @@ ENDVERS
521
505
  ###
522
506
  ### @return [void]
523
507
  ###
524
- def edit_package (pkg=nil)
525
-
508
+ def edit_package(pkg = nil)
526
509
  unless pkg
527
510
  pkg_id = get_pkg_from_cli_or_prompt
528
511
  pkg = pkg_id ? D3::Package.new(id: pkg_id) : nil
529
512
  end
530
513
  if pkg.nil?
531
- puts "No targets given to edit or no matching package found"
514
+ puts 'No targets given to edit or no matching package found'
532
515
  return
533
516
  end
534
517
 
535
-
536
518
  if @options.walkthru
537
519
  changes_to_make = D3::Admin::Edit.loop_thru_editing_walkthru pkg
538
520
  else
539
-
540
- changes_to_make = D3::Admin::Edit.validate_cli_edits (@options)
521
+ changes_to_make = D3::Admin::Edit.validate_cli_edits(@options)
541
522
  end # if @options.walkthru
542
523
 
543
524
  # Confirm the edition is still good if vers or rev changed
@@ -546,20 +527,19 @@ ENDVERS
546
527
  # Confirm the auto and excl groups don't conflict with each other
547
528
  D3::Admin::Edit.check_for_new_group_overlaps pkg, changes_to_make
548
529
 
549
-
550
530
  # exit if no changes on edit
551
- if changes_to_make.empty? and not @options.import
552
- puts "No changes to make!"
553
- return
531
+ if changes_to_make.empty? && !@options.import
532
+ puts 'No changes to make!'
533
+ return
554
534
  end
555
535
 
556
536
  # confirm
557
537
  if @options.import
558
538
  confirm_heading = "Import #{pkg.edition}, JSS id #{pkg.id}, into d3"
559
- conf_deets = "with these non-default settings..."
539
+ conf_deets = 'with these non-default settings...'
560
540
  else
561
541
  confirm_heading = "Make changes to #{pkg.edition}, JSS id #{pkg.id}"
562
- conf_deets = "Here are the changes..."
542
+ conf_deets = 'Here are the changes...'
563
543
  end
564
544
 
565
545
  D3::Admin::Edit::EDITING_OPTIONS.each do |opt|
@@ -583,8 +563,7 @@ ENDVERS
583
563
  # make the changes
584
564
  D3::Admin::Edit.process_edits pkg, changes_to_make
585
565
 
586
- puts @options.import ? "Done: the package has been imported to d3." : "Done! Your changes have been saved."
587
-
566
+ puts @options.import ? 'Done: the package has been imported to d3.' : 'Done! Your changes have been saved.'
588
567
  end # edit_pkg
589
568
 
590
569
  ### delete a pkg, optionallay archiving it
@@ -592,41 +571,39 @@ ENDVERS
592
571
  ### @return [void]
593
572
  ###
594
573
  def delete_package
595
-
596
574
  pkg_id = get_pkg_from_cli_or_prompt
597
575
 
598
576
  if pkg_id.nil?
599
- puts "No targets given to delete or no matching package found"
577
+ puts 'No targets given to delete or no matching package found'
600
578
  return
601
579
  end
602
580
 
603
581
  # check to see if the pkg is missing
604
- if D3::Package.package_data[pkg_id][:status] == :missing || (not JSS::Package.all_ids.include? pkg_id)
582
+ if D3::Package.package_data[pkg_id][:status] == :missing || (!JSS::Package.all_ids.include? pkg_id)
605
583
  delete_missing_package pkg_id
606
584
  return
607
585
  else
608
586
  pkg = D3::Package.new id: pkg_id
609
587
  end
610
588
 
611
- got_scripts = (not pkg.script_ids.values.empty?)
589
+ got_scripts = !pkg.script_ids.values.empty?
612
590
 
613
591
  if got_scripts
614
592
 
615
593
  if @options.walkthru
616
- @options.keep_scripts = D3::Admin::Interactive.get_value(:get_keep_scripts, default = 'n', check_method = :validate_yes_no)
594
+ @options.keep_scripts = D3::Admin::Interactive.get_value(:get_keep_scripts, default = 'n', check_method = :validate_yes_no)
617
595
 
618
596
  @options.keep_in_jss = D3::Admin::Interactive.get_value(:get_keep_in_jss, default = 'n', check_method = :validate_yes_no)
619
597
  end # if @options.walkthru
620
598
 
621
-
622
599
  if @options.keep_scripts
623
- deets = " - Keeping pre- or post- scripts in the JSS"
600
+ deets = ' - Keeping pre- or post- scripts in the JSS'
624
601
  else
625
- deets = " - Deleting pre- or post- scripts not used elsewhere"
602
+ deets = ' - Deleting pre- or post- scripts not used elsewhere'
626
603
  end # if @options.keep_scripts
627
604
 
628
605
  else
629
- deets = " - No pre- or post- scripts to delete"
606
+ deets = ' - No pre- or post- scripts to delete'
630
607
  end # if got_scripts
631
608
 
632
609
  if @options.keep_in_jss
@@ -638,22 +615,21 @@ ENDVERS
638
615
  confirm "DELETE #{pkg.edition}, JSS id #{pkg.id}\nDist.Point Filename: #{pkg.filename}", deets
639
616
 
640
617
  if @options.keep_scripts && got_scripts
641
- puts "Scanning for other packages or policies using pre- or post- scripts before deleting..."
618
+ puts 'Scanning for other packages or policies using pre- or post- scripts before deleting...'
642
619
  end
643
620
 
644
621
  script_actions = pkg.delete(
645
- admin: @admin,
646
- keep_scripts: @options.keep_scripts,
647
- keep_in_jss: @options.keep_in_jss,
648
- rwpw: D3::Admin::Auth.rw_credentials(:dist)[:password]
649
- )
622
+ admin: @admin,
623
+ keep_scripts: @options.keep_scripts,
624
+ keep_in_jss: @options.keep_in_jss,
625
+ rwpw: D3::Admin::Auth.rw_credentials(:dist)[:password]
626
+ )
650
627
 
651
628
  unless script_actions.empty?
652
- puts "Here' what happened to the scripts:"
629
+ puts "Here's what happened to the scripts:"
653
630
  puts script_actions.join "\n"
654
631
  end
655
632
  puts "Done! #{pkg.edition} has been deleted"
656
-
657
633
  end # delete package
658
634
 
659
635
  ### Delete a package that's missing from the JSS
@@ -661,15 +637,15 @@ ENDVERS
661
637
  ###
662
638
  def delete_missing_package (pkgid)
663
639
  pkg_data = D3::Package.package_data[pkgid]
664
- script_ids = [pkg_data[:pre_install_script_id], pkg_data[:post_install_script_id], pkg_data[:pre_remove_script_id], pkg_data[:post_remove_script_id] ].compact
640
+ script_ids = [pkg_data[:pre_install_script_id], pkg_data[:post_install_script_id], pkg_data[:pre_remove_script_id], pkg_data[:post_remove_script_id]].compact
665
641
 
666
642
  if script_ids.empty?
667
- deets = " - No pre- or post- scripts to delete"
643
+ deets = ' - No pre- or post- scripts to delete'
668
644
  else
669
645
  if @options.keep_scripts
670
- deets = " - Keeping pre- or post- scripts in the JSS"
646
+ deets = ' - Keeping pre- or post- scripts in the JSS'
671
647
  else
672
- deets = " - Deleting pre- or post- scripts not in use elsewhere"
648
+ deets = ' - Deleting pre- or post- scripts not in use elsewhere'
673
649
  end # if @options.keep_scripts
674
650
  end # if script_ids.empty?
675
651
 
@@ -678,8 +654,8 @@ ENDVERS
678
654
  JSS::DB_CNX.db.query "DELETE FROM #{D3::Database::PACKAGE_TABLE[:table_name]} WHERE package_id = #{pkgid}"
679
655
  puts "Package #{pkg_data[:edition]} deleted."
680
656
 
681
- if (not @options.keep_scripts) && (not script_ids.empty?)
682
- puts "Scanning for other packages or policies using pre- or post- scripts before deleting..."
657
+ if !@options.keep_scripts && !script_ids.empty?
658
+ puts 'Scanning for other packages or policies using pre- or post- scripts before deleting...'
683
659
  policy_scripts = D3.policy_scripts
684
660
  script_ids.each do |victim_script_id|
685
661
  next unless JSS::Script.all_ids.include? victim_script_id
@@ -693,15 +669,14 @@ ENDVERS
693
669
  end
694
670
  end # policy scripts.each
695
671
  d3_users = (D3::Package.packages_for_script(victim_script_id) - [pkgid])
696
- d3_users.each{|pkgid| puts "Script '#{victim_script_name}' in use by d3 edition '#{D3::Package.ids_to_editions[pkgid]}'" }
697
- if pol_users.empty? and d3_users.empty?
672
+ d3_users.each { |pid| puts "Script '#{victim_script_name}' in use by d3 edition '#{D3::Package.ids_to_editions[pid]}'" }
673
+ if pol_users.empty? && d3_users.empty?
698
674
  JSS::Script.new(id: victim_script_id).delete
699
675
  puts "Deleted script '#{victim_script_name}'"
700
676
  end
701
677
  end # do script id
702
678
  end # if @options.keep_scripts && (not script_ids.empty?)
703
-
704
- end # delete_missing_package (pkgid)
679
+ end # delete_missing_package(pkgid)
705
680
 
706
681
  ### Get an existing pkg id from the user via prompt (if walkthru) or the
707
682
  ### first thing listed in @targets. We don't instantiate the pkg here
@@ -710,11 +685,11 @@ ENDVERS
710
685
  ### @return [Ingeter, nil] an existing d3 pkg id if one was chosen
711
686
  ###
712
687
  def get_pkg_from_cli_or_prompt
713
- if @options.walkthru and @targets.first.nil?
688
+ if @options.walkthru && @targets.first.nil?
714
689
  D3::Admin::Interactive.get_value :get_existing_package, nil, :validate_existing_package
715
690
  else
716
691
  pkg_data = D3::Package.find_package(@targets.first, :hash)
717
- return pkg_data ? pkg_data[:id] : nil
692
+ pkg_data ? pkg_data[:id] : nil
718
693
  end
719
694
  end
720
695
 
@@ -729,21 +704,20 @@ ENDVERS
729
704
  ### @param details[String] The details requireing confirmation
730
705
  ###
731
706
  ###
732
- def confirm (action, details = nil)
733
-
707
+ def confirm(action, details = nil)
734
708
  puts
735
- puts "*****************************************"
709
+ puts '*****************************************'
736
710
  puts "Ahoy there! You are about to:\n#{action}"
737
- puts "*****************************************"
711
+ puts '*****************************************'
738
712
  puts details if details
739
713
 
740
714
  if @options.auto_confirm
741
- puts "auto-confirmed! Here we go....."
715
+ puts 'auto-confirmed! Here we go.....'
742
716
  else
743
717
  puts
744
- reply = Readline.readline("Are you SURE? (y/n): ", false)
718
+ reply = Readline.readline('Are you SURE? (y/n): ', false)
745
719
  return true if reply =~ /^y/i
746
- puts "Cancelled - wise choice!"
720
+ puts 'Cancelled - wise choice!'
747
721
  exit 0
748
722
  end # if autoconfirm
749
723
  end # confirm
@@ -753,11 +727,10 @@ ENDVERS
753
727
  ### @return [void]
754
728
  ###
755
729
  def show_package_info
756
-
757
730
  pkg_id = get_pkg_from_cli_or_prompt
758
731
 
759
732
  if pkg_id.nil?
760
- puts "No targets given or no matching package found"
733
+ puts 'No targets given or no matching package found'
761
734
  return
762
735
  end
763
736
 
@@ -772,10 +745,10 @@ ENDDEETS
772
745
  pkg_deets += "Basename: #{pkg.basename}\n"
773
746
  pkg_deets += "Version: #{pkg.version}\n"
774
747
  pkg_deets += "Revision: #{pkg.revision}\n"
775
- pkg_deets += "Added to on: #{pkg.added_date.strftime "%Y-%m-%d"}\n"
748
+ pkg_deets += "Added to on: #{pkg.added_date.strftime '%Y-%m-%d'}\n"
776
749
  pkg_deets += "Added by: #{pkg.added_by}\n"
777
750
  if pkg.release_date
778
- pkg_deets += "Released on: #{pkg.release_date.strftime "%Y-%m-%d"}\n"
751
+ pkg_deets += "Released on: #{pkg.release_date.strftime '%Y-%m-%d'}\n"
779
752
  pkg_deets += "Released by: #{pkg.released_by}\n"
780
753
  end
781
754
 
@@ -784,15 +757,14 @@ ENDDEETS
784
757
  next if done.include? opt
785
758
  label = D3::Admin::OPTIONS[opt][:label]
786
759
  if D3::Admin::OPTIONS[opt][:display_conversion]
787
- val_display = D3::Admin::OPTIONS[opt][:display_conversion].call(pkg.send opt)
760
+ val_display = D3::Admin::OPTIONS[opt][:display_conversion].call(pkg.send(opt))
788
761
  else
789
- val_display = pkg.send opt
762
+ val_display = pkg.send opt
790
763
  end
791
- val_display = val_display.to_s.empty? ? "none" : val_display
764
+ val_display = val_display.to_s.empty? ? 'none' : val_display
792
765
  pkg_deets += "#{label}: #{val_display}\n"
793
766
  end
794
767
 
795
-
796
768
  puts pkg_deets
797
769
  puts
798
770
  end # show_package_info
@@ -806,22 +778,22 @@ ENDDEETS
806
778
 
807
779
  if @options.walkthru
808
780
  # prompt for search type?
809
- search_for = D3::Admin::Interactive.prompt_for_data(
810
- desc: "SEARCH PACKAGES BY?\nAre you searching for packages by basename, or by scoped groups?\nEnter 'b' or 'g'",
811
- prompt: "Basenames or Groups",
812
- default: 'b',
813
- required: false
814
- )
781
+ search_for = D3::Admin::Interactive.prompt_for_data(
782
+ desc: "SEARCH PACKAGES BY?\nAre you searching for packages by basename, or by scoped groups?\nEnter 'b' or 'g'",
783
+ prompt: 'Basenames or Groups',
784
+ default: 'b',
785
+ required: false
786
+ )
815
787
  @options.search_groups = true if search_for =~ /^g/i
816
788
 
817
789
  @targets = [D3::Admin::Interactive.get_search_target] if @targets.empty?
818
790
  @options.status = D3::Admin::Interactive.get_status_for_filter.split(/,\s*/) if @options.status.empty?
819
- end #if @options.walkthru
791
+ end # if @options.walkthru
820
792
 
821
- @options.status = [] if @options.status.include? "all"
793
+ @options.status = [] if @options.status.include? 'all'
822
794
 
823
795
  # show all pkgs or group scope
824
- if @targets.empty? or @targets.include? "all"
796
+ if @targets.empty? || @targets.include?('all')
825
797
  if @options.search_groups
826
798
  D3::Admin::Report.list_all_pkgs_with_scope @options.status
827
799
  else
@@ -832,14 +804,13 @@ ENDDEETS
832
804
 
833
805
  # show specific basenames or group scopes
834
806
  @targets.each do |search_target|
835
-
836
- # groups?
807
+ # Groups?
837
808
  if @options.search_groups
838
- found_groups = JSS::ComputerGroup.all_names.select{|gn| gn =~ /#{search_target}/}
809
+ found_groups = JSS::ComputerGroup.all_names.select { |gn| gn =~ /#{search_target}/ }
839
810
  if found_groups.empty?
840
811
  puts "No computer groups in Casper match '#{search_target}'"
841
812
  else
842
- found_groups.each {|fgn|
813
+ found_groups.each { |fgn|
843
814
  D3::Admin::Report.list_scoped_installs fgn, @options.status, :auto
844
815
  D3::Admin::Report.list_scoped_installs fgn, @options.status, :excluded
845
816
  } # found_groups.each
@@ -847,11 +818,11 @@ ENDDEETS
847
818
 
848
819
  # basenames
849
820
  else
850
- found_basenames = D3::Package.all_basenames.select{|bn| bn =~ /#{search_target}/}
821
+ found_basenames = D3::Package.all_basenames.select { |bn| bn =~ /#{search_target}/ }
851
822
  if found_basenames.empty?
852
823
  puts "No basenames in d3 match '#{search_target}'"
853
824
  else
854
- found_basenames.each {|fbn| D3::Admin::Report.list_packages fbn, @options.status }
825
+ found_basenames.each { |fbn| D3::Admin::Report.list_packages fbn, @options.status }
855
826
  end # if found_basenames.empty?
856
827
  end # if @options.search_groups
857
828
  end # @targets.each do |search_target|
@@ -872,13 +843,13 @@ ENDDEETS
872
843
  if @targets.empty?
873
844
  one_or_all = D3::Admin::Interactive.prompt_for_data(
874
845
  desc: "ALL COMPUTERS?\nAre you reporting for a single computer or all computers?\nEnter 'all' for all computers, '1' for one",
875
- prompt: "All or 1",
846
+ prompt: 'All or 1',
876
847
  default: 'all',
877
848
  required: false
878
849
  )
879
850
 
880
851
  # basename report across computers
881
- if one_or_all == "all"
852
+ if one_or_all == 'all'
882
853
  @targets = [(D3::Admin::Interactive.get_value :get_basename, nil, :validate_basename)]
883
854
 
884
855
  # reporting single computers
@@ -891,34 +862,32 @@ ENDDEETS
891
862
 
892
863
  # prompt for rcpts or puppies
893
864
  rcpts_or_pups = D3::Admin::Interactive.prompt_for_data(
894
- desc: "RECEIPTS OR PUPPIES?\nShould the report list receipts or pending puppytime installs?\nEnter 'r' for receipts, 'p' for puppies",
895
- prompt: "Receipts or puppies",
896
- required: false,
897
- default: 'r'
865
+ desc: "RECEIPTS OR PUPPIES?\nShould the report list receipts or pending puppytime installs?\nEnter 'r' for receipts, 'p' for puppies",
866
+ prompt: 'Receipts or puppies',
867
+ required: false,
868
+ default: 'r'
898
869
  )
899
- @options.report_q = rcpts_or_pups =~ /^p/i ? true : false
870
+ @options.report_q = rcpts_or_pups =~ /^p/i ? true : false
900
871
 
901
872
  # prompt for status or frozen
902
873
  @options.status = D3::Admin::Interactive.get_status_for_filter(:with_frozen).split(/,\s*/) if @options.status.empty?
903
874
 
904
- end #if @options.walkthru
875
+ end # if @options.walkthru
905
876
 
906
- @options.status = [] if @options.status.include? "all"
877
+ @options.status = [] if @options.status.include? 'all'
907
878
 
908
879
  # pass the --frozen option with the --status options, since
909
880
  # its treated like a pseudo-status, and thats where walkthru puts it too
910
- @options.status << "frozen" if @options.report_frozen
881
+ @options.status << 'frozen' if @options.report_frozen
911
882
 
912
883
  reporting = @options.report_q ? :puppies : :receipts
913
884
 
914
-
915
885
  if @targets.empty?
916
- puts "No basename or computer name given for report"
886
+ puts 'No basename or computer name given for report'
917
887
  return
918
888
  end
919
889
 
920
890
  @targets.each do |target|
921
-
922
891
  # report puppies
923
892
  if reporting == :puppies
924
893
  if @options.report_computers
@@ -951,7 +920,6 @@ ENDDEETS
951
920
  ### @return [void]
952
921
  ###
953
922
  def config
954
-
955
923
  if @targets.include? 'display'
956
924
  D3::Admin::Prefs.display_config
957
925
  else
@@ -959,16 +927,12 @@ ENDDEETS
959
927
  end
960
928
  end # config
961
929
 
962
-
963
930
  end # class App
964
931
 
965
-
966
-
967
-
968
932
  ### save terminal state incase user interrupts during readline or less
969
933
  if $stdin.tty?
970
934
  stty_save = `stty -g`.chomp
971
- trap("SIGINT") do
935
+ trap('SIGINT') do
972
936
  puts "\nCancelled! Woot!"
973
937
  system('stty', stty_save)
974
938
  exit 0
@@ -979,8 +943,8 @@ begin
979
943
  app = App.new
980
944
  app.run
981
945
  rescue
982
- puts "An error occurred: #{$!.class}: #{$!}"
983
- puts $@ if D3::Admin.debug
946
+ puts "An error occurred: #{$ERROR_INFO.class}: #{$ERROR_INFO}!"
947
+ puts $ERROR_POSITION if D3::Admin.debug
984
948
  exit 1
985
949
  ensure
986
950
  if D3::Admin::Auth.connected?