depot3 3.0.9 → 3.0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/d3 +18 -2
- data/bin/d3admin +55 -85
- data/bin/d3helper +1 -1
- data/lib/d3/admin/add.rb +11 -2
- data/lib/d3/admin/auth.rb +20 -3
- data/lib/d3/admin/edit.rb +1 -1
- data/lib/d3/admin/help.rb +13 -12
- data/lib/d3/admin/interactive.rb +17 -17
- data/lib/d3/admin/options.rb +10 -10
- data/lib/d3/admin/report.rb +23 -6
- data/lib/d3/admin/validate.rb +12 -0
- data/lib/d3/basename.rb +16 -1
- data/lib/d3/client/auth.rb +2 -2
- data/lib/d3/client/class_methods.rb +83 -45
- data/lib/d3/client/cli.rb +11 -0
- data/lib/d3/client/help.rb +1 -0
- data/lib/d3/client/receipt.rb +25 -22
- data/lib/d3/database.rb +10 -5
- data/lib/d3/log.rb +34 -38
- data/lib/d3/package/constructor.rb +4 -1
- data/lib/d3/package/getters.rb +1 -1
- data/lib/d3/package/private_methods.rb +1 -1
- data/lib/d3/package/questions.rb +1 -1
- data/lib/d3/package/server_actions.rb +9 -9
- data/lib/d3/package/setters.rb +37 -10
- data/lib/d3/package/validate.rb +25 -6
- data/lib/d3/version.rb +1 -1
- metadata +2 -2
data/lib/d3/client/auth.rb
CHANGED
@@ -42,8 +42,8 @@ module D3
|
|
42
42
|
db_ro_user = D3::CONFIG.client_db_ro_user
|
43
43
|
db_ro_user ||= JSS::CONFIG.db_username
|
44
44
|
|
45
|
-
JSS::DB_CNX.connect :server => JSS::CONFIG.db_server_name, :user => db_ro_user, :pw => D3::Client.get_ro_pass(:db)
|
46
|
-
JSS::API.connect :server => JSS::CONFIG.api_server_name, :user => jss_ro_user, :pw => D3::Client.get_ro_pass(:jss)
|
45
|
+
JSS::DB_CNX.connect :server => JSS::CONFIG.db_server_name, :user => db_ro_user, :pw => D3::Client.get_ro_pass(:db)
|
46
|
+
JSS::API.connect :server => JSS::CONFIG.api_server_name, :user => jss_ro_user, :pw => D3::Client.get_ro_pass(:jss)
|
47
47
|
|
48
48
|
D3::Database.check_schema_version
|
49
49
|
end # connect
|
@@ -57,6 +57,10 @@ module D3
|
|
57
57
|
raise JSS::NoSuchItemError, "No d3 package matching #{pkg_to_search}" unless desired_pkg
|
58
58
|
raise D3::InstallError, "The package for #{desired_pkg.edition} is missing from the JSS" if desired_pkg.missing?
|
59
59
|
|
60
|
+
if options.custom_expiration
|
61
|
+
raise "Sorry #{desired_pkg.edition} is not expirable. A d3 admin needs to add an expiration path." if desired_pkg.expiration_paths.empty?
|
62
|
+
end
|
63
|
+
|
60
64
|
curr_rcpt = D3::Client::Receipt.all[desired_pkg.basename]
|
61
65
|
|
62
66
|
# many things can be forced
|
@@ -101,14 +105,13 @@ module D3
|
|
101
105
|
D3.log "Finished installing #{desired_pkg.edition}(#{desired_pkg.status})", :info
|
102
106
|
|
103
107
|
rescue JSS::MissingDataError, JSS::NoSuchItemError, JSS::InvalidDataError, D3::InstallError
|
104
|
-
D3.log "Skipping installation of #{pkg_to_search}
|
108
|
+
D3.log "Skipping installation of #{pkg_to_search}: #{$!}", :error
|
105
109
|
D3.log_backtrace
|
106
110
|
rescue D3::PreInstallError
|
107
|
-
D3.log "There was an error with the pre-install script for #{desired_pkg.edition}
|
111
|
+
D3.log "There was an error with the pre-install script for #{desired_pkg.edition}: #{$!}", :error
|
108
112
|
D3.log_backtrace
|
109
113
|
rescue D3::PostInstallError
|
110
|
-
D3.log "There was an error with the post-install script for #{desired_pkg.edition}
|
111
|
-
D3.log " NOTE: it was installed, but may have problems.", :error
|
114
|
+
D3.log "There was an error with the post-install script for #{desired_pkg.edition}: #{$!} NOTE: it was installed, but may have problems.", :error
|
112
115
|
D3.log_backtrace
|
113
116
|
end # begin
|
114
117
|
end # args.each
|
@@ -133,7 +136,7 @@ module D3
|
|
133
136
|
D3.log "Finished uninstalling #{rcpt.edition}.", :info
|
134
137
|
|
135
138
|
rescue JSS::MissingDataError, D3::UninstallError, JSS::InvalidDataError
|
136
|
-
D3.log "Skipping uninstall of #{rcpt_to_remove}
|
139
|
+
D3.log "Skipping uninstall of #{rcpt_to_remove}: #{$!}", :error
|
137
140
|
D3.log_backtrace
|
138
141
|
next
|
139
142
|
end # begin
|
@@ -223,6 +226,13 @@ module D3
|
|
223
226
|
# expirations
|
224
227
|
do_expirations
|
225
228
|
|
229
|
+
# removie receipts w/ missing packages on the server
|
230
|
+
# This must happen AFTER update_installed_pkgs
|
231
|
+
# so that the basename gets any updates on the server
|
232
|
+
# before removing the recetip (which wouild prevent
|
233
|
+
# updates)
|
234
|
+
clean_missing_receipts
|
235
|
+
|
226
236
|
D3.log "Finished sync", :warn
|
227
237
|
ensure
|
228
238
|
D3::Client.unset_env :sync
|
@@ -256,27 +266,35 @@ module D3
|
|
256
266
|
rcpt.update
|
257
267
|
next
|
258
268
|
end
|
269
|
+
need_update = false
|
270
|
+
|
271
|
+
# Are we rolling back to a prev version?
|
272
|
+
# If the pkgdata[:status] is :pilot and the
|
273
|
+
# rcpt.status is NOT :pilot, then we are.
|
274
|
+
rolling_back = (pkgdata[:status] == :pilot) && (rcpt.status != :pilot)
|
259
275
|
|
260
276
|
# status
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
277
|
+
unless rolling_back
|
278
|
+
if rcpt.status != pkgdata[:status]
|
279
|
+
# update the status
|
280
|
+
rcpt.status = pkgdata[:status]
|
281
|
+
D3.log "Updating status for #{rcpt.edition} to #{pkgdata[:status]}", :info
|
282
|
+
need_update = true
|
283
|
+
end # if
|
284
|
+
end # unless
|
267
285
|
|
268
286
|
# pre-remove script
|
269
287
|
if rcpt.pre_remove_script_id != pkgdata[:pre_remove_script_id]
|
270
288
|
rcpt.pre_remove_script_id = pkgdata[:pre_remove_script_id]
|
271
289
|
D3.log "Updating pre-remove script for #{rcpt.edition}", :info
|
272
|
-
|
290
|
+
need_update = true
|
273
291
|
end # if
|
274
292
|
|
275
293
|
# post-remove script
|
276
294
|
if rcpt.post_remove_script_id != pkgdata[:post_remove_script_id]
|
277
295
|
rcpt.post_remove_script_id = pkgdata[:post_remove_script_id]
|
278
296
|
D3.log "Updating post-remove script for #{rcpt.edition}", :info
|
279
|
-
|
297
|
+
need_update = true
|
280
298
|
end # if
|
281
299
|
|
282
300
|
# removability
|
@@ -287,22 +305,22 @@ module D3
|
|
287
305
|
rcpt.expiration = 0
|
288
306
|
D3.log "#{rcpt.edition} is not expirable now that it's not removable", :info
|
289
307
|
end
|
290
|
-
|
308
|
+
need_update = true
|
291
309
|
end # if
|
292
310
|
|
293
311
|
# expiration
|
294
312
|
if rcpt.removable?
|
295
313
|
|
296
|
-
|
297
|
-
rcpt.
|
298
|
-
D3.log "Updating expiration path for #{rcpt.edition}", :info
|
299
|
-
|
314
|
+
unless rcpt.expiration_paths_match? pkgdata[:expiration_paths]
|
315
|
+
rcpt.expiration_paths = pkgdata[:expiration_paths]
|
316
|
+
D3.log "Updating expiration path(s) for #{rcpt.edition}", :info
|
317
|
+
need_update = true
|
300
318
|
end # if
|
301
|
-
|
319
|
+
|
302
320
|
if (rcpt.expiration != pkgdata[:expiration].to_i) and (not rcpt.custom_expiration)
|
303
321
|
rcpt.expiration = pkgdata[:expiration].to_i
|
304
322
|
D3.log "Updating expiration for #{rcpt.edition}", :info
|
305
|
-
|
323
|
+
need_update = true
|
306
324
|
end # if
|
307
325
|
end # if removable
|
308
326
|
|
@@ -310,18 +328,12 @@ module D3
|
|
310
328
|
if rcpt.prohibiting_process.to_s != pkgdata[:prohibiting_process].to_s
|
311
329
|
rcpt.prohibiting_process = pkgdata[:prohibiting_process]
|
312
330
|
D3.log "Updating prohibiting_process for #{rcpt.edition}", :info
|
313
|
-
|
331
|
+
need_update = true
|
314
332
|
end # if
|
315
333
|
|
316
|
-
# last usage
|
317
|
-
# this will update the last_usage value stored in the rcpt (for reporting only)
|
318
|
-
# (expiration only looks at current usage data)
|
319
|
-
if rcpt.expiration_path
|
320
|
-
rcpt.last_usage
|
321
|
-
rcpt.update
|
322
|
-
end
|
323
334
|
|
324
|
-
|
335
|
+
rcpt.update if need_update
|
336
|
+
end # each do basename, rcpt
|
325
337
|
end # update
|
326
338
|
|
327
339
|
### remove any invalid puppies from the queue
|
@@ -399,14 +411,13 @@ module D3
|
|
399
411
|
)
|
400
412
|
D3.log "Auto-installed #{new_pkg.basename}", :warn
|
401
413
|
rescue JSS::MissingDataError, JSS::InvalidDataError, D3::InstallError
|
402
|
-
D3.log "Skipping auto-install of #{new_pkg.edition}
|
414
|
+
D3.log "Skipping auto-install of #{new_pkg.edition}: #{$!}", :error
|
403
415
|
D3.log_backtrace
|
404
416
|
rescue D3::PreInstallError
|
405
|
-
D3.log "There was an error with the pre-install script for #{new_pkg.edition}
|
417
|
+
D3.log "There was an error with the pre-install script for #{new_pkg.edition}: #{$!}", :error
|
406
418
|
D3.log_backtrace
|
407
419
|
rescue D3::PostInstallError
|
408
|
-
D3.log "There was an error with the post-install script for #{new_pkg.edition}
|
409
|
-
D3.log " NOTE: #{new_pkg.edition} was installed, but may not work.", :error
|
420
|
+
D3.log "There was an error with the post-install script for #{new_pkg.edition}: #{$!} NOTE: #{new_pkg.edition} was installed, but may not work.", :error
|
410
421
|
D3.log_backtrace
|
411
422
|
end #begin
|
412
423
|
end # live_ids_for_group.each do |live_id|
|
@@ -416,6 +427,18 @@ module D3
|
|
416
427
|
end
|
417
428
|
end
|
418
429
|
|
430
|
+
### remove any receipts for packages that are missing from the server
|
431
|
+
###
|
432
|
+
###
|
433
|
+
def self.clean_missing_receipts
|
434
|
+
D3.log "Checking for receipts no longer in d3", :warn
|
435
|
+
D3::Client::Receipt.all.values.select{|r| r.status == :missing}.each do |mrcpt|
|
436
|
+
D3.log "Removing receipt for missing edition #{mrcpt.edition}", :info
|
437
|
+
D3::Client::Receipt.remove_receipt mrcpt.basename
|
438
|
+
D3.log "Removed receipt for missing edition #{mrcpt.edition}", :info
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
419
442
|
### Update any currently installed basenames to the currently live one
|
420
443
|
### skipping any basenames currently frozen
|
421
444
|
###
|
@@ -480,7 +503,9 @@ module D3
|
|
480
503
|
|
481
504
|
# mention rollbacks
|
482
505
|
if rollback
|
483
|
-
D3.log "Rolling back #{rcpt.edition} (#{rcpt.status}) to older live #{
|
506
|
+
D3.log "Rolling back #{rcpt.edition} (#{rcpt.status}) to older live #{live_pkg_data[:edition]}.", :warn
|
507
|
+
else
|
508
|
+
D3.log "Updating #{rcpt.edition} (#{rcpt.status}) to #{live_pkg_data[:edition]} (#{live_pkg_data[:status]})", :warn
|
484
509
|
end
|
485
510
|
|
486
511
|
# are we bringing over a custom expiration period?
|
@@ -488,7 +513,6 @@ module D3
|
|
488
513
|
|
489
514
|
# heres the pkg
|
490
515
|
live_pkg = D3::Package.new :id => live_basenames_to_ids[rcpt.basename]
|
491
|
-
D3.log "Updating #{rcpt.edition} (#{rcpt.status}) to #{live_pkg.edition} (#{live_pkg.status})", :warn
|
492
516
|
|
493
517
|
begin
|
494
518
|
live_pkg.install(
|
@@ -501,14 +525,13 @@ module D3
|
|
501
525
|
)
|
502
526
|
D3.log "Done updating #{rcpt.edition} (#{rcpt.status}) to #{live_pkg.edition} (#{live_pkg.status})", :info
|
503
527
|
rescue JSS::MissingDataError, JSS::InvalidDataError, D3::InstallError
|
504
|
-
D3.log "Skipping update of #{rcpt.edition} to #{live_pkg.edition}
|
528
|
+
D3.log "Skipping update of #{rcpt.edition} to #{live_pkg.edition}: #{$!}", :error
|
505
529
|
D3.log_backtrace
|
506
530
|
rescue D3::PreInstallError
|
507
|
-
D3.log "There was an error with the pre-install script for #{live_pkg.edition}
|
531
|
+
D3.log "There was an error with the pre-install script for #{live_pkg.edition}: #{$!}", :error
|
508
532
|
D3.log_backtrace
|
509
533
|
rescue D3::PostInstallError
|
510
|
-
D3.log "There was an error with the post-install script for #{live_pkg.edition}
|
511
|
-
D3.log " NOTE: #{live_pkg.edition} was installed, but may not work.", :error
|
534
|
+
D3.log "There was an error with the post-install script for #{live_pkg.edition}: #{$!} NOTE: #{live_pkg.edition} was installed, but may not work.", :error
|
512
535
|
D3.log_backtrace
|
513
536
|
end # begin
|
514
537
|
end # D3::Client::Receipt.all.values.each
|
@@ -555,7 +578,23 @@ module D3
|
|
555
578
|
rcpt.update
|
556
579
|
D3.log "Thawing receipt for #{rcpt.edition}, will resume auto-update during sync", :warn
|
557
580
|
end
|
558
|
-
end #
|
581
|
+
end # thaw_receipts
|
582
|
+
|
583
|
+
### forget one or more receipts, and their matching apple pkg receipts
|
584
|
+
###
|
585
|
+
### @param basenames[Array] the basenames of the rcpts to forget
|
586
|
+
###
|
587
|
+
### @return [void]
|
588
|
+
###
|
589
|
+
def self.forget_receipts (basenames)
|
590
|
+
basenames.each do |bn|
|
591
|
+
rcpt = D3::Client::Receipt.all[bn]
|
592
|
+
next unless rcpt
|
593
|
+
rcpt.apple_pkg_ids.each{|ar| system "/usr/sbin/pkgutil --forget '#{ar}'" }
|
594
|
+
D3::Client::Receipt.remove_receipt bn
|
595
|
+
D3.log "Receipt for #{rcpt.edition} has been forgotten", :warn
|
596
|
+
end
|
597
|
+
end # thaw_receipts
|
559
598
|
|
560
599
|
### Do any pending puppy installs right now, because we're
|
561
600
|
### syncing and --puppies option was given
|
@@ -583,14 +622,13 @@ module D3
|
|
583
622
|
D3.log_backtrace
|
584
623
|
D3::PUPPY_Q - puppy
|
585
624
|
rescue JSS::MissingDataError, JSS::InvalidDataError, D3::InstallError
|
586
|
-
D3.log "Skipping install of #{new_pkg.edition} from queue
|
625
|
+
D3.log "Skipping install of #{new_pkg.edition} from queue: #{$!}", :error
|
587
626
|
D3.log_backtrace
|
588
627
|
rescue D3::PreInstallError
|
589
|
-
D3.log "There was an error with the pre-install script for #{new_pkg.edition}
|
628
|
+
D3.log "There was an error with the pre-install script for #{new_pkg.edition}: #{$!}", :error
|
590
629
|
D3.log_backtrace
|
591
630
|
rescue D3::PostInstallError
|
592
|
-
D3.log "There was an error with the post-install script for #{new_pkg.edition}
|
593
|
-
D3.log " NOTE: #{new_pkg.edition} was installed, but may not work.", :error
|
631
|
+
D3.log "There was an error with the post-install script for #{new_pkg.edition}: #{$!} NOTE: #{new_pkg.edition} was installed, but may not work.", :error
|
594
632
|
D3.log_backtrace
|
595
633
|
D3::PUPPY_Q - puppy
|
596
634
|
end # begin
|
@@ -634,7 +672,7 @@ module D3
|
|
634
672
|
expired_edition = rcpt.expire verbose, force
|
635
673
|
@@editions_expired << expired_edition if expired_edition
|
636
674
|
rescue
|
637
|
-
D3.log "There was an error expiring #{rcpt.edition}
|
675
|
+
D3.log "There was an error expiring #{rcpt.edition}: #{$!}", :error
|
638
676
|
D3.log_backtrace
|
639
677
|
end
|
640
678
|
end
|
data/lib/d3/client/cli.rb
CHANGED
@@ -67,6 +67,12 @@ module D3
|
|
67
67
|
:needs_connection => false,
|
68
68
|
:arg => :basename
|
69
69
|
},
|
70
|
+
forget: {
|
71
|
+
:aka => :fg,
|
72
|
+
:help => "Remove receipt but don't try uninstalling.",
|
73
|
+
:needs_connection => false,
|
74
|
+
:arg => :basename
|
75
|
+
},
|
70
76
|
list_available: {
|
71
77
|
:aka => :la,
|
72
78
|
:help => "list all available live installers on the server",
|
@@ -97,6 +103,11 @@ module D3
|
|
97
103
|
:help => "list any queued pkgs awaiting puppytime at logout",
|
98
104
|
:needs_root => false
|
99
105
|
},
|
106
|
+
list_queue: {
|
107
|
+
:aka => :lq,
|
108
|
+
:help => "list any queued pkgs awaiting puppytime at logout",
|
109
|
+
:needs_root => false
|
110
|
+
},
|
100
111
|
list_details: {
|
101
112
|
:aka => :ld,
|
102
113
|
:help => "show detailed info about packages in d3",
|
data/lib/d3/client/help.rb
CHANGED
@@ -58,6 +58,7 @@ Actions:
|
|
58
58
|
uninstall u <basename> - Uninstall packages
|
59
59
|
freeze f <basename> - Stop auto-updates of this basename
|
60
60
|
thaw t <basename> - Resume auto-updates of this basename
|
61
|
+
forget fg <basename> - Remove receipt without uninstalling
|
61
62
|
dequeue dq <basename> - Remove a pending logout install
|
62
63
|
sync s - Update receipt data, do auto-installs
|
63
64
|
update installed software & uninstall
|
data/lib/d3/client/receipt.rb
CHANGED
@@ -105,7 +105,7 @@ module D3
|
|
105
105
|
:pre_remove_script_id,
|
106
106
|
:post_remove_script_id,
|
107
107
|
:expiration,
|
108
|
-
:
|
108
|
+
:expiration_paths,
|
109
109
|
:prohibiting_process
|
110
110
|
]
|
111
111
|
|
@@ -148,6 +148,7 @@ module D3
|
|
148
148
|
self.get_datastore_lock(lock_timeout) if rw
|
149
149
|
|
150
150
|
@@installed_rcpts = DATASTORE.file? ? YAML.load(DATASTORE.read) : {}
|
151
|
+
@@installed_rcpts ||= {}
|
151
152
|
|
152
153
|
D3.log "Receipts loaded", :debug
|
153
154
|
end # seld.load_receipts
|
@@ -162,7 +163,7 @@ module D3
|
|
162
163
|
###
|
163
164
|
### @return [void]
|
164
165
|
###
|
165
|
-
def self.reload_receipts(rw = false, lock_timeout = DATASTORE_LOCK_TIMEOUT)
|
166
|
+
def self.reload_receipts (rw = false, lock_timeout = DATASTORE_LOCK_TIMEOUT)
|
166
167
|
|
167
168
|
# if we haven't loaded them at all yet, just do that.
|
168
169
|
unless @@installed_rcpts
|
@@ -183,6 +184,7 @@ module D3
|
|
183
184
|
|
184
185
|
# reload it
|
185
186
|
@@installed_rcpts = DATASTORE.file? ? YAML.load(DATASTORE.read) : {}
|
187
|
+
@@installed_rcpts ||= {}
|
186
188
|
D3.log "Receipts reloaded", :debug
|
187
189
|
end # self.reload_receipts
|
188
190
|
|
@@ -470,8 +472,8 @@ module D3
|
|
470
472
|
:removable => d3_pkg.removable,
|
471
473
|
:pre_remove_script_id => d3_pkg.pre_remove_script_id,
|
472
474
|
:post_remove_script_id => d3_pkg.post_remove_script_id,
|
473
|
-
:
|
474
|
-
:
|
475
|
+
:expiration => d3_pkg.expiration,
|
476
|
+
:expiration_paths => d3_pkg.expiration_paths
|
475
477
|
)
|
476
478
|
|
477
479
|
end # .each do |d3_pkg|
|
@@ -519,11 +521,11 @@ module D3
|
|
519
521
|
attr_accessor :frozen
|
520
522
|
|
521
523
|
# @return [Time, nil] When was this app last used.
|
522
|
-
# nil if never checked, or no @
|
524
|
+
# nil if never checked, or no @expiration_paths
|
523
525
|
attr_reader :last_usage
|
524
526
|
|
525
527
|
# @return [Time, nil] When was @last_usage updated?
|
526
|
-
# nil if never checked, or no @
|
528
|
+
# nil if never checked, or no @expiration_paths
|
527
529
|
attr_reader :last_usage_as_of
|
528
530
|
|
529
531
|
################# Constructor #################
|
@@ -579,7 +581,7 @@ module D3
|
|
579
581
|
@post_remove_script_id = args[:post_remove_script_id]
|
580
582
|
|
581
583
|
@expiration = args[:expiration].to_i
|
582
|
-
@
|
584
|
+
@expiration_paths = args[:expiration_paths]
|
583
585
|
@custom_expiration = args[:custom_expiration]
|
584
586
|
|
585
587
|
@manually_installed = (@admin != D3::AUTO_INSTALL_ADMIN)
|
@@ -807,7 +809,7 @@ module D3
|
|
807
809
|
@manually_installed = (@admin != D3::AUTO_INSTALL_ADMIN)
|
808
810
|
@package_type = @jamf_rcpt_file.end_with?(".dmg") ? :dmg : :pkg
|
809
811
|
@expiration = d3_pkg.expiration
|
810
|
-
@
|
812
|
+
@expiration_paths = d3_pkg.expiration_paths
|
811
813
|
|
812
814
|
end # repair rcpt
|
813
815
|
|
@@ -860,8 +862,8 @@ module D3
|
|
860
862
|
###
|
861
863
|
### @return [void]
|
862
864
|
###
|
863
|
-
def
|
864
|
-
@
|
865
|
+
def expiration_paths= (new_val)
|
866
|
+
@expiration_paths = new_val
|
865
867
|
end
|
866
868
|
|
867
869
|
### Set a new prohibiting process
|
@@ -930,7 +932,7 @@ Post-remove script: #{post_name}
|
|
930
932
|
Apple.pkg ids: #{@apple_pkg_ids.join(', ')}
|
931
933
|
END_DEETS
|
932
934
|
end
|
933
|
-
if @
|
935
|
+
if @expiration_paths
|
934
936
|
if @expiration.to_i > 0
|
935
937
|
lu = last_usage
|
936
938
|
if lu.nil?
|
@@ -943,7 +945,7 @@ Apple.pkg ids: #{@apple_pkg_ids.join(', ')}
|
|
943
945
|
|
944
946
|
deets += <<-END_DEETS
|
945
947
|
Expiration period: #{@expiration} days#{@custom_expiration ? ' (custom)' : ''}
|
946
|
-
Expiration path: #{@
|
948
|
+
Expiration path(s): #{D3::Database::ARRAY_OF_PATHNAMES_TO_COMMA_STRING.call @expiration_paths}
|
947
949
|
Last brought to foreground: #{last_usage_display}
|
948
950
|
END_DEETS
|
949
951
|
end # if exp > 0
|
@@ -970,8 +972,8 @@ Last brought to foreground: #{last_usage_display}
|
|
970
972
|
return false if @expiration.nil? or @expiration == 0
|
971
973
|
|
972
974
|
# gotta have an expiration path
|
973
|
-
|
974
|
-
D3.log "Not expiring #{edition} because: No Expiration Path for #{edition}", :debug
|
975
|
+
if @expiration_paths.empty?
|
976
|
+
D3.log "Not expiring #{edition} because: No Expiration Path(s) for #{edition}", :debug
|
975
977
|
return false
|
976
978
|
end
|
977
979
|
|
@@ -1048,7 +1050,7 @@ Last brought to foreground: #{last_usage_display}
|
|
1048
1050
|
return deleted? ? edition : nil
|
1049
1051
|
end # expire
|
1050
1052
|
|
1051
|
-
### Return the number of days since the last usage for the @
|
1053
|
+
### Return the number of days since the last usage for the @expiration_paths
|
1052
1054
|
### for this receipt
|
1053
1055
|
###s
|
1054
1056
|
### Returns nil if last_usage is nil
|
@@ -1079,19 +1081,19 @@ Last brought to foreground: #{last_usage_display}
|
|
1079
1081
|
### expiration path or the data wasn't retrievable.
|
1080
1082
|
###
|
1081
1083
|
def last_usage
|
1082
|
-
return nil unless @
|
1084
|
+
return nil unless @expiration_paths
|
1083
1085
|
|
1084
1086
|
now = Time.now
|
1085
1087
|
|
1086
1088
|
# if it's in the foreground right now, return [now, 0]
|
1087
1089
|
fgnd_path = D3::Client.foreground_executable_path
|
1088
1090
|
if fgnd_path
|
1089
|
-
|
1091
|
+
now_in_foreground = @expiration_paths.select{|p| fgnd_path == p}.length > 0
|
1090
1092
|
else
|
1091
|
-
|
1093
|
+
now_in_foreground = nil
|
1092
1094
|
end
|
1093
1095
|
|
1094
|
-
if
|
1096
|
+
if now_in_foreground
|
1095
1097
|
@last_usage = now
|
1096
1098
|
@last_usage_as_of = now
|
1097
1099
|
return @last_usage
|
@@ -1117,13 +1119,14 @@ Last brought to foreground: #{last_usage_display}
|
|
1117
1119
|
return nil
|
1118
1120
|
end
|
1119
1121
|
|
1120
|
-
|
1122
|
+
# loop through the plists, get the newest usage time for this
|
1121
1123
|
# expiration path, and append it to all_usages
|
1122
1124
|
all_usages = []
|
1123
1125
|
plists.each do |plist|
|
1124
1126
|
usage_times = D3.parse_plist plist
|
1125
|
-
my_usage_keys = usage_times.keys.
|
1126
|
-
|
1127
|
+
my_usage_keys = usage_times.keys.map{|p| Pathname.new(p)}
|
1128
|
+
exp_paths_with_usage = @expiration_paths & my_usage_keys
|
1129
|
+
exp_paths_with_usage.each{|p| all_usages << usage_times[p] }
|
1127
1130
|
end # do plist
|
1128
1131
|
|
1129
1132
|
@last_usage = all_usages.compact.max
|
data/lib/d3/database.rb
CHANGED
@@ -42,7 +42,7 @@ module D3
|
|
42
42
|
MIN_SCHEMA_VERSION = "9.4"
|
43
43
|
|
44
44
|
# the minimum JSS schema version allower
|
45
|
-
MAX_SCHEMA_VERSION = "9.
|
45
|
+
MAX_SCHEMA_VERSION = "9.93"
|
46
46
|
|
47
47
|
### these Proc objects allow us to encapsulate and pass around various
|
48
48
|
### blocks of code more easily for converting data between their mysql
|
@@ -59,6 +59,10 @@ module D3
|
|
59
59
|
|
60
60
|
### Some values are stored as comma-separated strings, but used as Arrays
|
61
61
|
COMMA_STRING_TO_ARRAY = Proc.new{|v| JSS.to_s_and_a(v)[:arrayform] }
|
62
|
+
|
63
|
+
### Some values are stored as comma-separated strings, but used as Arrays of Pathnames
|
64
|
+
COMMA_STRING_TO_ARRAY_OF_PATHNAMES = Proc.new{|v| JSS.to_s_and_a(v)[:arrayform].map{|p| Pathname.new(p)} }
|
65
|
+
ARRAY_OF_PATHNAMES_TO_COMMA_STRING = Proc.new{|v| v.join(", ")}
|
62
66
|
|
63
67
|
### Some values are used as Arrays but stored as comma-separated strings
|
64
68
|
ARRAY_TO_COMMA_STRING = Proc.new{|v| JSS.to_s_and_a(v)[:stringform] }
|
@@ -325,12 +329,12 @@ module D3
|
|
325
329
|
:to_ruby => STRING_TO_INT
|
326
330
|
},
|
327
331
|
|
328
|
-
:
|
332
|
+
:expiration_paths => {
|
329
333
|
:field_name => "expiration_app_path",
|
330
334
|
:sql_type => 'varchar(300)',
|
331
335
|
:index => nil,
|
332
|
-
:to_sql =>
|
333
|
-
:to_ruby =>
|
336
|
+
:to_sql => ARRAY_OF_PATHNAMES_TO_COMMA_STRING,
|
337
|
+
:to_ruby => COMMA_STRING_TO_ARRAY_OF_PATHNAMES
|
334
338
|
}
|
335
339
|
},
|
336
340
|
|
@@ -404,7 +408,8 @@ module D3
|
|
404
408
|
### Raise an exception if JSS schema is to old or too new
|
405
409
|
def self.check_schema_version
|
406
410
|
raw = JSS::DB_CNX.db.query("SELECT version FROM #{SCHEMA_TABLE}").fetch[0]
|
407
|
-
|
411
|
+
simmered = raw.split('.')[0..1].join('.')
|
412
|
+
current = JSS.parse_jss_version(simmered)[:version]
|
408
413
|
min = JSS.parse_jss_version(MIN_SCHEMA_VERSION)[:version]
|
409
414
|
max = JSS.parse_jss_version(MAX_SCHEMA_VERSION)[:version]
|
410
415
|
raise JSS::InvalidConnectionError, "Invalid JSS database schema version: #{raw}, min: #{MIN_SCHEMA_VERSION}, max: #{MAX_SCHEMA_VERSION}" if current < min or current > max
|
data/lib/d3/log.rb
CHANGED
@@ -28,13 +28,16 @@ module D3
|
|
28
28
|
|
29
29
|
### Log a message to the d3 log, possibly sending it to stderr as well.
|
30
30
|
###
|
31
|
-
### The message will appear in the log
|
32
|
-
###
|
33
|
-
###
|
31
|
+
### The message will appear in the log:
|
32
|
+
### - if the log is writable by the current user
|
33
|
+
### - based upon its severity level, and the current D3::Log.level.
|
34
|
+
### Any message more severe than the log level will be logged.
|
34
35
|
###
|
35
|
-
### The message will appear on stderr if the message severity is
|
36
|
-
### at or higher than the current @@verbosity.
|
37
|
-
###
|
36
|
+
### The message will also appear on stderr if the message severity is
|
37
|
+
### at or higher than the current @@verbosity.
|
38
|
+
###
|
39
|
+
### If the @@verbosity is :debug the messages to stderr will be prefixed with
|
40
|
+
### the message severity.
|
38
41
|
###
|
39
42
|
### In the d3 command, @@verbosity is controlled with the -v, -q and -d
|
40
43
|
### options
|
@@ -62,12 +65,8 @@ module D3
|
|
62
65
|
end
|
63
66
|
end #
|
64
67
|
|
65
|
-
# can't write to the log unless we're super user
|
66
|
-
return unless JSS.superuser?
|
67
|
-
|
68
68
|
# send to the logger
|
69
69
|
D3::Log.instance.log msg, severity
|
70
|
-
|
71
70
|
end
|
72
71
|
|
73
72
|
### Log the lines of backtrace from the most recent exception
|
@@ -173,31 +172,25 @@ module D3
|
|
173
172
|
@level = D3::CONFIG.log_level if D3::CONFIG.log_level
|
174
173
|
@timestamp_format = D3::CONFIG.log_timestamp_format if D3::CONFIG.log_timestamp_format
|
175
174
|
|
176
|
-
# the logger will be created
|
177
|
-
|
178
|
-
|
175
|
+
# the logger will be created if the file is writable
|
176
|
+
writable = if @log_file.file?
|
177
|
+
@log_file.writable?
|
178
|
+
else
|
179
|
+
@log_file.parent.writable?
|
180
|
+
end
|
179
181
|
|
182
|
+
if writable
|
183
|
+
@logger = Logger.new @log_file
|
184
|
+
@logger.level = D3::Log.check_level(@level)
|
185
|
+
set_format
|
186
|
+
else
|
187
|
+
@logger = nil
|
188
|
+
end
|
180
189
|
|
181
190
|
end # init
|
182
191
|
|
183
192
|
################# Public Instance Methods #################
|
184
193
|
|
185
|
-
### Access the logger, creating it if needed.
|
186
|
-
### We don't make it when the instance is created because it
|
187
|
-
### might want to write to a place we don't have permissions.
|
188
|
-
### So anything that uses it will call this to create it when
|
189
|
-
### its needed.
|
190
|
-
def the_logger
|
191
|
-
return @logger if @logger
|
192
|
-
# make logger if needed
|
193
|
-
unless @logger
|
194
|
-
@logger = Logger.new @log_file
|
195
|
-
set_format
|
196
|
-
end
|
197
|
-
@logger.level = D3::Log.check_level @level
|
198
|
-
return @logger
|
199
|
-
end
|
200
|
-
|
201
194
|
### Send a message to be logged
|
202
195
|
### If the severity is less severe than the current level,
|
203
196
|
### the message won't be written to the log.
|
@@ -215,7 +208,8 @@ module D3
|
|
215
208
|
### @return [Boolean] the message was handled appropriately, or not
|
216
209
|
###
|
217
210
|
def log (msg, severity = DFT_LOG_LEVEL)
|
218
|
-
|
211
|
+
return nil unless @logger
|
212
|
+
@logger.add(D3::Log.check_level(severity), msg, @progname)
|
219
213
|
end
|
220
214
|
|
221
215
|
### Set a new severity-level for logging.
|
@@ -226,8 +220,9 @@ module D3
|
|
226
220
|
### @return [void]
|
227
221
|
###
|
228
222
|
def level= (new_level)
|
229
|
-
|
230
|
-
@level = new_level
|
223
|
+
return nil unless @logger
|
224
|
+
@level = D3::Log.check_level(new_level)
|
225
|
+
@logger.level = @level
|
231
226
|
end
|
232
227
|
|
233
228
|
|
@@ -250,20 +245,21 @@ module D3
|
|
250
245
|
### @return [void]
|
251
246
|
###
|
252
247
|
def timestamp_format= (new_format)
|
253
|
-
|
254
|
-
|
255
|
-
@
|
248
|
+
return nil unless @logger
|
249
|
+
@timestamp_format = new_format.to_s
|
250
|
+
@logger.datetime_format = @timestamp_format
|
256
251
|
end # timestamp_format=
|
257
252
|
|
258
253
|
private
|
259
254
|
|
260
255
|
### set up the log line format
|
261
256
|
def set_format
|
262
|
-
|
263
|
-
|
257
|
+
return nil unless @logger
|
258
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
264
259
|
"#{datetime.strftime @timestamp_format} #{progname} [#{$$}]: #{severity}: #{msg}\n"
|
265
260
|
end #
|
266
|
-
end
|
261
|
+
end # set format
|
262
|
+
|
267
263
|
end # class Log
|
268
264
|
|
269
265
|
# the singleton instance of our logger
|
@@ -167,7 +167,7 @@ module D3
|
|
167
167
|
|
168
168
|
# if we have a setter method for this key, call it to set the attribute.
|
169
169
|
setter = "#{fld_key}=".to_sym
|
170
|
-
send(setter, fld_val) if self.respond_to?(setter, true) # the 'true' makes respond_to? look at private methods also
|
170
|
+
self.send(setter, fld_val) if self.respond_to?(setter, true) # the 'true' makes respond_to? look at private methods also
|
171
171
|
|
172
172
|
end # PFIELDS.each
|
173
173
|
end # if d3pkg_data
|
@@ -175,6 +175,9 @@ module D3
|
|
175
175
|
# some nil-values shouldn't be nil
|
176
176
|
@auto_groups ||= []
|
177
177
|
@excluded_groups ||= []
|
178
|
+
|
179
|
+
# expiration_paths should always be an array
|
180
|
+
@expiration_paths ||= []
|
178
181
|
|
179
182
|
# these don't come from the table def.
|
180
183
|
@admin = args[:admin]
|