depot3 0.0.0a1 → 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +55 -1
  3. data/bin/d3 +323 -0
  4. data/bin/d3admin +1011 -0
  5. data/bin/d3helper +354 -0
  6. data/bin/puppytime +334 -0
  7. data/data/d3/com.pixar.d3.RepoMan.plist +23 -0
  8. data/data/d3/d3.conf.example +507 -0
  9. data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftAppKit.dylib +0 -0
  10. data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftCore.dylib +0 -0
  11. data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftCoreData.dylib +0 -0
  12. data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftCoreGraphics.dylib +0 -0
  13. data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftCoreImage.dylib +0 -0
  14. data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftDarwin.dylib +0 -0
  15. data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftDispatch.dylib +0 -0
  16. data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftFoundation.dylib +0 -0
  17. data/data/d3/d3RepoMan.app/Contents/Frameworks/libswiftObjectiveC.dylib +0 -0
  18. data/data/d3/d3RepoMan.app/Contents/Info.plist +56 -0
  19. data/data/d3/d3RepoMan.app/Contents/MacOS/d3RepoMan +0 -0
  20. data/data/d3/d3RepoMan.app/Contents/PkgInfo +1 -0
  21. data/data/d3/d3RepoMan.app/Contents/Resources/Base.lproj/MainMenu.nib +0 -0
  22. data/data/d3/d3RepoMan.app/Contents/Resources/last-foreground-times-template.plist +5 -0
  23. data/data/d3/d3RepoMan.app/Contents/_CodeSignature/CodeResources +214 -0
  24. data/data/d3/puppytime/ImageLicenses.txt +165 -0
  25. data/data/d3/puppytime/notification_image +1 -0
  26. data/data/d3/puppytime/opt_out_image +1 -0
  27. data/data/d3/puppytime/slideshow/2008-07-11_White_German_Shepherd_pup_chilling_at_the_Coker_Arboretum.jpg +0 -0
  28. data/data/d3/puppytime/slideshow/2009-04-21_APBT_pup_on_deck.jpg +0 -0
  29. data/data/d3/puppytime/slideshow/A_puppy_Yorkie.jpg +0 -0
  30. data/data/d3/puppytime/slideshow/Alert_Pug_Puppy.jpg +0 -0
  31. data/data/d3/puppytime/slideshow/Australian_Cattle_Dog_puppies_04.JPG +0 -0
  32. data/data/d3/puppytime/slideshow/Beagle_puppy_Cadet.jpg +0 -0
  33. data/data/d3/puppytime/slideshow/Bernese_Mountain_Dog.jpg +0 -0
  34. data/data/d3/puppytime/slideshow/Bloodhound_Puppy.jpg +0 -0
  35. data/data/d3/puppytime/slideshow/Boston_terrier_with_toy.jpg +0 -0
  36. data/data/d3/puppytime/slideshow/Boxer_puppy_fawn_portrai.jpg +0 -0
  37. data/data/d3/puppytime/slideshow/Caracal_kitten.jpg +0 -0
  38. data/data/d3/puppytime/slideshow/Chihuahua_&_Doberman_Pup.jpg +0 -0
  39. data/data/d3/puppytime/slideshow/Cuccioli_di_Margot_a_35_gg_Basenjis.jpg +0 -0
  40. data/data/d3/puppytime/slideshow/Dalmatian_puppy_03.jpg +0 -0
  41. data/data/d3/puppytime/slideshow/GoldenRetrieverPuppyDaisyParker.JPG +0 -0
  42. data/data/d3/puppytime/slideshow/Green_eyed_beige_Chihuahua.jpg +0 -0
  43. data/data/d3/puppytime/slideshow/Let_Sleeping_Dogs_Lie.jpg +0 -0
  44. data/data/d3/puppytime/slideshow/Meatball_-_French_Bulldog_Puppy.jpg +0 -0
  45. data/data/d3/puppytime/slideshow/Oola_-_9_weeks.jpg +0 -0
  46. data/data/d3/puppytime/slideshow/Pancho0008.JPG +0 -0
  47. data/data/d3/puppytime/slideshow/Pomeranian_orange-sable_Coco.jpg +0 -0
  48. data/data/d3/puppytime/slideshow/Pug_puppy_001.jpg +0 -0
  49. data/data/d3/puppytime/slideshow/Puggle_puppy_6_weeks.JPG +0 -0
  50. data/data/d3/puppytime/slideshow/Puli_kan.jpg +0 -0
  51. data/data/d3/puppytime/slideshow/Puppy_French_Bulldog.jpg +0 -0
  52. data/data/d3/puppytime/slideshow/Rocco_the_Bulldog.jpg +0 -0
  53. data/data/d3/puppytime/slideshow/Rottweiler_Face.jpg +0 -0
  54. data/data/d3/puppytime/slideshow/Saint_Bernard_puppy.jpg +0 -0
  55. data/data/d3/puppytime/slideshow/Scottish_froment.jpg +0 -0
  56. data/data/d3/puppytime/slideshow/Shar_pei_puppy_(age_2_months).jpg +0 -0
  57. data/data/d3/puppytime/slideshow/Shiba-Inu_beim_Spielen_im_Schnee.JPG +0 -0
  58. data/data/d3/puppytime/slideshow/Smooth-coat_Border_Collie_puppy..jpg +0 -0
  59. data/data/d3/puppytime/slideshow/Smooth_Dachshund_puppies.jpg +0 -0
  60. data/data/d3/puppytime/slideshow/Snow_dog.jpg +0 -0
  61. data/data/d3/puppytime/slideshow/Taylor_the_Pembroke_Welsh_Corgi.png +0 -0
  62. data/data/d3/puppytime/slideshow/Weim_Pups_001.jpg +0 -0
  63. data/data/d3/puppytime/slideshow/Westie_pups.jpg +0 -0
  64. data/data/d3/puppytime/slideshow/Yellow_Labrador_puppies_(4165737325).jpg +0 -0
  65. data/lib/d3/admin/add.rb +451 -0
  66. data/lib/d3/admin/auth.rb +470 -0
  67. data/lib/d3/admin/edit.rb +297 -0
  68. data/lib/d3/admin/help.rb +396 -0
  69. data/lib/d3/admin/interactive.rb +972 -0
  70. data/lib/d3/admin/options.rb +454 -0
  71. data/lib/d3/admin/prefs.rb +204 -0
  72. data/lib/d3/admin/report.rb +727 -0
  73. data/lib/d3/admin/state.rb +42 -0
  74. data/lib/d3/admin/validate.rb +413 -0
  75. data/lib/d3/admin.rb +42 -0
  76. data/lib/d3/basename.rb +217 -0
  77. data/lib/d3/client/auth.rb +108 -0
  78. data/lib/d3/client/class_methods.rb +766 -0
  79. data/lib/d3/client/class_variables.rb +47 -0
  80. data/lib/d3/client/cli.rb +187 -0
  81. data/lib/d3/client/environment.rb +134 -0
  82. data/lib/d3/client/help.rb +110 -0
  83. data/lib/d3/client/lists.rb +314 -0
  84. data/lib/d3/client/receipt.rb +1173 -0
  85. data/lib/d3/client.rb +45 -0
  86. data/lib/d3/configuration.rb +319 -0
  87. data/lib/d3/constants.rb +60 -0
  88. data/lib/d3/database.rb +488 -0
  89. data/lib/d3/exceptions.rb +44 -0
  90. data/lib/d3/log.rb +271 -0
  91. data/lib/d3/package/aliases.rb +80 -0
  92. data/lib/d3/package/attributes.rb +97 -0
  93. data/lib/d3/package/class_methods.rb +817 -0
  94. data/lib/d3/package/class_variables.rb +46 -0
  95. data/lib/d3/package/client_actions.rb +293 -0
  96. data/lib/d3/package/constants.rb +58 -0
  97. data/lib/d3/package/constructor.rb +191 -0
  98. data/lib/d3/package/getters.rb +164 -0
  99. data/lib/d3/package/mixins.rb +39 -0
  100. data/lib/d3/package/private_methods.rb +227 -0
  101. data/lib/d3/package/questions.rb +95 -0
  102. data/lib/d3/package/server_actions.rb +683 -0
  103. data/lib/d3/package/setters.rb +326 -0
  104. data/lib/d3/package/validate.rb +448 -0
  105. data/lib/d3/package.rb +51 -0
  106. data/lib/d3/puppytime/pending_puppy.rb +108 -0
  107. data/lib/d3/puppytime/puppy_queue.rb +274 -0
  108. data/lib/d3/puppytime.rb +68 -0
  109. data/lib/d3/state.rb +105 -0
  110. data/lib/d3/utility.rb +325 -0
  111. data/lib/d3/version.rb +1 -1
  112. metadata +162 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d625adcf2d799ef5d29936bc7535bc148d0219a1
4
- data.tar.gz: 733b6a4da9b4ac7ff8c6b75f722fa9f88c88d44d
3
+ metadata.gz: b324775776772e84290c9a70c319cd331ff8b36a
4
+ data.tar.gz: 0497c9fe41fbbb93ec8a64d50bf4715f97a4ffb6
5
5
  SHA512:
6
- metadata.gz: f5ad8cd0f965268ca65bf7883a908af90afe47a0010609bdb16744b6388339629fa86b2adb71798d2e6b390d9f96713651070ef52b27ae07cfb6b570138423cb
7
- data.tar.gz: 2e2db8d11eba42b8b912e39ff5d46a12bc9dfd1375fd19436c4789e0aed49da400cc2cd54f0bbe30e073384d289db5ca465126e9aa2e15fb6f2dae04d08491a1
6
+ metadata.gz: e584088d46f4cbc0982bb0bdd39bdc47145c9f0e32bcfcdee79cb333368fc5c169dc7a11cbf6d3c23e141098a1768ad01a9d54141cd2bb5d0b5e662e315b6d11
7
+ data.tar.gz: b9ae548291035fdd3bb88b51c9091038b8de70bf00a2de5317c08374b80bf123e6b897880f2421b1ac8c38d5b8492dee1df65d671092660388ac2ca5b930122f
data/README.md CHANGED
@@ -1,3 +1,57 @@
1
1
  # d3 - Command line package and patch management for Casper
2
2
 
3
- This is a temporary placeholder. We plan to release d3 in early April, 2016.
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/).
5
+
6
+
7
+
8
+ d3 adds these, capabilities and more, to Casper's package handling:
9
+
10
+ * Automatic software updates on clients when new versions are released on the server
11
+ * Pre-release piloting of new packages
12
+ * Customizable slideshow presented during logout/reboot installs
13
+ * Installs and uninstalls are conditional on the exit status of pre-flight scripts
14
+ * Packages can be expired (auto-uninstalled) after a period of disuse
15
+ * Both the client and admin tools are command-line only and fully scriptable
16
+ * Admin command-line options allow integration with developer workflows and package-retrieval tools
17
+
18
+ d3 is written in Ruby and available as a rubygem called ['depot3'](https://rubygems.org/gems/depot3). It interfaces with Casper mostly via it's 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.
19
+
20
+
21
+ Please see the [wiki](https://github.com/PixarAnimationStudios/depot3/wiki) for full documentation
22
+
23
+ The developer documentation for the D3 ruby module is at [http://www.rubydoc.info/gems/depot3](http://www.rubydoc.info/gems/depot3)
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.
26
+
27
+
28
+ ## CONTACT
29
+
30
+ [Email the developer](mailto:d3@pixar.com)
31
+
32
+ [Macadmins Slack Channel](https://macadmins.slack.com/messages/#d3/)
33
+
34
+ ## LICENSE
35
+
36
+ Copyright 2016 Pixar
37
+
38
+ Licensed under the Apache License, Version 2.0 (the "Apache License")
39
+ with the following modification; you may not use d3 except in
40
+ compliance with the Apache License and the following modification to it:
41
+
42
+ Section 6. Trademarks. is deleted and replaced with:
43
+
44
+ 6\. Trademarks. This License does not grant permission to use the trade
45
+ names, trademarks, service marks, or product names of the Licensor
46
+ and its affiliates, except as required to comply with Section 4(c) of
47
+ the License and to reproduce the content of the NOTICE file.
48
+
49
+ You may obtain a copy of the Apache License at
50
+
51
+ http://www.apache.org/licenses/LICENSE-2.0
52
+
53
+ Unless required by applicable law or agreed to in writing, software
54
+ distributed under the Apache License with the above modification is
55
+ distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
56
+ KIND, either express or implied. See the Apache License for the specific
57
+ language governing permissions and limitations under the Apache License.
data/bin/d3 ADDED
@@ -0,0 +1,323 @@
1
+ #!/usr/bin/ruby
2
+ ### Copyright 2016 Pixar
3
+ ###
4
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
5
+ ### with the following modification; you may not use this file except in
6
+ ### compliance with the Apache License and the following modification to it:
7
+ ### Section 6. Trademarks. is deleted and replaced with:
8
+ ###
9
+ ### 6. Trademarks. This License does not grant permission to use the trade
10
+ ### names, trademarks, service marks, or product names of the Licensor
11
+ ### and its affiliates, except as required to comply with Section 4(c) of
12
+ ### the License and to reproduce the content of the NOTICE file.
13
+ ###
14
+ ### You may obtain a copy of the Apache License at
15
+ ###
16
+ ### http://www.apache.org/licenses/LICENSE-2.0
17
+ ###
18
+ ### Unless required by applicable law or agreed to in writing, software
19
+ ### distributed under the Apache License with the above modification is
20
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
+ ### KIND, either express or implied. See the Apache License for the specific
22
+ ### language governing permissions and limitations under the Apache License.
23
+ ###
24
+ ###
25
+
26
+
27
+ ######################################
28
+ # d3 - a commandline interface to Casper package maintenance
29
+ # and Patch Management
30
+ #
31
+ # Copyright 2010 Pixar Animation Studios
32
+ #
33
+ # Chris Lasell chrisl@pixar.com 2010-04-22
34
+
35
+
36
+ # TO DO - add commands for:
37
+ ## immediately remove a receipt
38
+ ## set up configuration on a client
39
+
40
+ ############
41
+ # Modules, Libraries, etc
42
+ ############
43
+
44
+ # Load libraries
45
+ require 'd3'
46
+
47
+ #####################################
48
+ # Script Object
49
+ #####################################
50
+
51
+ class App
52
+
53
+ # the following d3 commands all require one or more arguments to work on
54
+ ACTIONS_NEEDING_ARGS = D3::Client::ACTIONS.select{|k,v| v[:arg] }
55
+
56
+ # the following d3 commands need @admin to be set
57
+ ACTIONS_NEEDING_ADMIN = D3::Client::ACTIONS.select{|k,v| v[:needs_admin] }
58
+
59
+ # the following d3 commands need a connection to the server
60
+ ACTIONS_NEEDING_SERVER = D3::Client::ACTIONS.select{|k,v| v[:needs_connection] }
61
+
62
+ ### set up
63
+ ###
64
+ def initialize(args)
65
+
66
+ D3::LOG.progname = File.basename __FILE__
67
+
68
+ # here's where we hold cmdline args &c
69
+ @options = OpenStruct.new
70
+
71
+ # parse the commandline and populate @action, @options and @targets
72
+ parse_cli
73
+
74
+ # action OK?
75
+ D3::Client::ACTIONS.each do |aname,info|
76
+ @action = aname if @action_from_user == aname
77
+ break if @action
78
+ @action = aname if info[:aka] == @action_from_user
79
+ break if @action
80
+ end
81
+ raise ArgumentError,"Unknown d3 action: #{@action_from_user}. Use -H for help" unless @action
82
+
83
+ # d3 must be run as root - even just listing stuff.
84
+ # (because root is needed to retrieve the passwords for automation)
85
+ if JSS.superuser?
86
+ # make sure some dirs exist
87
+ D3::SUPPORT_DIR.mkpath unless D3::SUPPORT_DIR.directory?
88
+ D3::SUPPORT_DIR.chmod 0755
89
+
90
+ # otherwise, yell if we need to be root.
91
+ else
92
+ raise D3::PermissionError, "You must be root to use d3." unless [:help, :version].include? @action
93
+ end #if root
94
+
95
+ # bail if the jamf binary isn't installed
96
+ unless D3::Client::JAMF_BINARY.executable?
97
+ raise JSS::NoSuchItemError, "The jamf binary isn't installed properly."
98
+ end
99
+
100
+
101
+ # Does this command need the name of an admin for recording who's doing it?
102
+ # The admin name cannot be one of D3::DISALLOWED_ADMINS, currently:
103
+ # [nil, "", "root", "unknown", "auto-installed"]
104
+ # The D3.admin method will try to figure out the real non-root admin name.
105
+ #
106
+ # Syncing doesn't require an admin for auto-installs and updates, but
107
+ # any automated scripts that do a d3 command might need to provide an
108
+ # appropriate admin name. E.g. if a policy runs a script that installs
109
+ # a d3 pkg, it should use something like
110
+ # d3 install some-pkg --admin my-policy-script
111
+ # then the receipt for other-pkg will show that it was installed by
112
+ # 'my-policy-script'. Another useful example is a pre- or post-install script that
113
+ # installs another d3 pkg. That script should use the --admin option to
114
+ # indicate that it did the install
115
+ #
116
+ @options.admin ||= D3.admin
117
+ @options.admin = @options.admin.to_s
118
+ if ACTIONS_NEEDING_ADMIN.keys.include? @action and D3::DISALLOWED_ADMINS.include? @options.admin
119
+ raise ArgumentError, "Cannot determine non-root admin name, please use --admin with '#{@action}'."
120
+ end
121
+ D3::Client.set_env :admin, @options_admin
122
+
123
+ # if we're installing or piloting, and have a custom expiration, it must be
124
+ # a positive integer
125
+ if @action == :install and @options.custom_expiration
126
+ unless @options.custom_expiration =~ /^\d+$/ and @options.custom_expiration.to_i >= 0
127
+ raise ArgumentError, "Expiration periods (in days) must be an integer >= 0"
128
+ end
129
+ @options.custom_expiration = @options.custom_expiration.to_i
130
+ end
131
+
132
+ # tell the client if the admin asked for no puppy notification
133
+ if @options.no_logout_notice
134
+ D3::Client.puppy_notification_ok_with_admin = false
135
+ end
136
+
137
+ # If the action needs targets, and there are none, say so
138
+ if ACTIONS_NEEDING_ARGS.keys.include?(@action) and @targets == 0
139
+ arg_type = D3::Client::ACTIONS[@action][:arg]
140
+ raise ArgumentError, "Action '#{@action}' needs one or more #{arg_type} targets."
141
+ end
142
+
143
+ # connect to d3
144
+ D3::Client.connect if ACTIONS_NEEDING_SERVER.keys.include?(@action)
145
+
146
+ end # init
147
+
148
+ ### Parse the command line - fill @options with our options.
149
+ ###
150
+ def parse_cli
151
+
152
+ # when finished, this leaves the d3 command and its arg in ARGV
153
+ opts = GetoptLong.new( *D3::Client::OPTIONS.values.map{|opt| opt[:cli]} )
154
+
155
+ opts.each do |opt, arg|
156
+ case opt
157
+ when '--help'
158
+ @show_help = :show_help
159
+
160
+ when '--version'
161
+ @show_help = :show_version
162
+
163
+ when '--quiet'
164
+ @options.quiet = true
165
+ D3.verbosity = D3.verbosity + 1
166
+
167
+ when '--verbose'
168
+ @options.verbose = true
169
+ D3.verbosity = D3.verbosity - 1
170
+
171
+ when '--no-puppy-notification'
172
+ @options.no_logout_notice = true
173
+
174
+ when '--puppies'
175
+ @options.puppies = true
176
+
177
+ when '--force'
178
+ @options.force = true
179
+ D3::force
180
+
181
+ when '--freeze'
182
+ @options.freeze_on_install = true
183
+
184
+ when '--admin'
185
+ @options.admin = arg
186
+
187
+ when '--expiration'
188
+ @options.custom_expiration = arg
189
+
190
+ when '--debug'
191
+ @options.debug = true
192
+ @options.verbose = true
193
+ D3.verbosity = :debug
194
+ D3::LOG.level = :debug
195
+ D3::Client.set_env :debug
196
+ end # case
197
+ end # opts.each
198
+
199
+ ARGV.unshift "help" if @show_help
200
+
201
+ # gotta have a least an action....
202
+ if ARGV.empty?
203
+ show_usage
204
+ raise ArgumentError, "action required. Use -H for help"
205
+ end
206
+
207
+ # the gsub makes, eg, 'list-installed' into "list_installed"
208
+ # which are the keys of D3::Client::ACTIONS
209
+ @action_from_user = ARGV.shift.gsub('-','_').to_sym
210
+
211
+ #@targets = ARGV
212
+ @targets = ARGV
213
+
214
+ end # parse args
215
+
216
+ ### Do that d3 thing!
217
+ ###
218
+ def run
219
+ # Process the given d3 command
220
+ case @action
221
+
222
+ when :install then
223
+ D3::Client.install @targets, @options
224
+
225
+ when :uninstall then
226
+ D3::Client.uninstall @targets, @options
227
+
228
+ when :dequeue then
229
+ D3::Client.dequeue_puppies @targets
230
+
231
+ when :sync then
232
+ D3::Client.sync @options
233
+
234
+ when :freeze then
235
+ D3::Client.freeze_receipts @targets
236
+
237
+ when :thaw then
238
+ D3::Client.thaw_receipts @targets
239
+
240
+ when :list_available then
241
+ D3::Client.list_available @options.force
242
+
243
+ when :list_installed then
244
+ D3::Client.list_installed
245
+
246
+ when :list_manual then
247
+ D3::Client.list_manual
248
+
249
+ when :list_pilots then
250
+ D3::Client.list_pilots
251
+
252
+ when :list_frozen then
253
+ D3::Client.list_frozen
254
+
255
+ when :list_puppies then
256
+ D3::Client.list_pending_puppies
257
+
258
+ when :list_details then
259
+ D3::Client.list_details @targets
260
+
261
+ when :list_files then
262
+ D3::Client.list_files @targets
263
+
264
+ when :query_file then
265
+ D3::Client.query_files @targets
266
+
267
+ when :help
268
+ @show_help == :show_version ? show_version : show_help
269
+
270
+ else
271
+ show_usage
272
+ end # case
273
+ end #run
274
+
275
+ ### Show the usage line
276
+ def show_usage
277
+ STDERR.puts D3::Client::Help::USAGE
278
+ end # show_usage
279
+
280
+ ### Show the help message
281
+ ###
282
+ ### @return [void]
283
+ ###
284
+ def show_help
285
+ D3.less_text D3::Client::Help.help_text
286
+ end #show help
287
+
288
+ ### Show the current d3 version
289
+ def show_version
290
+ puts <<-ENDVERS
291
+ D3 module version: #{D3::VERSION}
292
+ JSS module version: #{JSS::VERSION}
293
+ ENDVERS
294
+ end
295
+
296
+
297
+ end # class App
298
+
299
+ ############
300
+ # Do it
301
+ ############
302
+ stty_save = `stty -g`.chomp
303
+ trap("SIGINT") { puts "\nCancelled! Woot!" ; system('stty', stty_save); exit 0 }
304
+
305
+ begin
306
+ # if needed, set debugging even before we make the app
307
+ D3::LOG.level = :debug unless (ARGV & ["--debug", "-d"] ).empty?
308
+
309
+ # make and run d3
310
+ app = App.new(ARGV)
311
+ app.run
312
+
313
+ rescue
314
+ # handle exceptions not handled elsewhere
315
+ D3.log "An error occurred: #{$!.class}: #{$!}", :fatal
316
+ D3.log_backtrace
317
+ exit 1
318
+ ensure
319
+ if JSS::API.connected?
320
+ JSS::DistributionPoint.my_distribution_point.unmount if JSS::DistributionPoint.my_distribution_point.mounted?
321
+ D3::Client.disconnect
322
+ end # if
323
+ end