depot3 3.0.9 → 3.0.11
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.
- 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]
|