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.
@@ -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), :connect_timeout => 10
46
- JSS::API.connect :server => JSS::CONFIG.api_server_name, :user => jss_ro_user, :pw => D3::Client.get_ro_pass(:jss), :open_timeout => 10
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}:\n #{$!}", :error
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}:\n #{$!}", :error
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}:\n #{$!}", :error
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}:\n #{$!}", :error
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
- if rcpt.status != pkgdata[:status]
262
- # update the status
263
- rcpt.status = pkgdata[:status]
264
- D3.log "Updating status for #{rcpt.edition} to #{pkgdata[:status]}", :info
265
- rcpt.update
266
- end # if
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
- rcpt.update
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
- rcpt.update
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
- rcpt.update
308
+ need_update = true
291
309
  end # if
292
310
 
293
311
  # expiration
294
312
  if rcpt.removable?
295
313
 
296
- if rcpt.expiration_path.to_s != pkgdata[:expiration_path].to_s
297
- rcpt.expiration_path = pkgdata[:expiration_path]
298
- D3.log "Updating expiration path for #{rcpt.edition}", :info
299
- rcpt.update
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
- rcpt.update
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
- rcpt.update
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
- end # each do basename, rcpt
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}:\n #{$!}", :error
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}:\n #{$!}", :error
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}:\n #{$!}", :error
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 #{ live_pkg_data[:edition]}.", :warn
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}:\n #{$!}", :error
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}:\n #{$!}", :error
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}:\n #{$!}", :error
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 # freeze receipts
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:\n #{$!}", :error
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}:\n #{$!}", :error
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}:\n #{$!}", :error
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}:\n #{$!}", :error
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",
@@ -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
@@ -105,7 +105,7 @@ module D3
105
105
  :pre_remove_script_id,
106
106
  :post_remove_script_id,
107
107
  :expiration,
108
- :expiration_path,
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
- :expiraation => d3_pkg.expiraation,
474
- :expiraation_path => d3_pkg.expiraation_path
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 @expiration_path
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 @expiration_path
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
- @expiration_path = args[:expiration_path]
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
- @expiration_path = d3_pkg.expiration_path
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 expiration_path= (new_val)
864
- @expiration_path = Pathname.new new_val
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 @expiration_path
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: #{@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
- unless @expiration_path
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 @expiration_path
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 @expiration_path
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
- now_in_forground = (fgnd_path.to_s == @expiration_path.to_s.chomp('/'))
1091
+ now_in_foreground = @expiration_paths.select{|p| fgnd_path == p}.length > 0
1090
1092
  else
1091
- now_in_forground = nil
1093
+ now_in_foreground = nil
1092
1094
  end
1093
1095
 
1094
- if now_in_forground
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
- # loop through the plists, get the newest usage time for this
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.select{|k| k.start_with? @expiration_path.to_s }
1126
- all_usages << my_usage_keys.map{|k| usage_times[k].to_time }.max
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.82"
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
- :expiration_path => {
332
+ :expiration_paths => {
329
333
  :field_name => "expiration_app_path",
330
334
  :sql_type => 'varchar(300)',
331
335
  :index => nil,
332
- :to_sql => PATHNAME_TO_STRING,
333
- :to_ruby => STRING_TO_PATHNAME
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
- current = JSS.parse_jss_version(raw)[:version]
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 based upon its severity level,
32
- ### and the current D3::Log.level. Any message more severe than the log level
33
- ### will be logged.
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. If the @@verbosity is :debug
37
- ### the messages to stderr will be prefixed with the message severity.
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 when it's needed
177
- @logger = nil
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
- the_logger.add(D3::Log.check_level(severity), msg, @progname)
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
- the_logger.level = D3::Log.check_level(new_level)
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
- new_format = new_format.to_s
254
- the_logger.datetime_format = new_format
255
- @timestamp_format = new_format
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
- # set the line format
263
- the_logger.formatter = proc do |severity, datetime, progname, msg|
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]