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
@@ -0,0 +1,972 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+
26
+ module D3
27
+ module Admin
28
+
29
+ ### This module contains methods for interacting with the user in the terminal
30
+ ### prompting for data related to administering d3 packages.
31
+ ###
32
+ ### These methods all return a string of user input, possibly an empty string.
33
+ ###
34
+ module Interactive
35
+ require 'readline'
36
+ extend self
37
+
38
+ # Set up readline
39
+ # no spaces at the end of readline completion
40
+ Readline.completion_append_character = ""
41
+ # names may contain spaces
42
+ Readline.basic_word_break_characters = ""
43
+ # this appends a / to directories as we auto-complete paths.
44
+ Readline.completion_proc = Proc.new do |str|
45
+ files = Dir.glob(str + "*")
46
+ files.map {|f| File.directory?(f) ? "#{f}/" : f }
47
+ end
48
+
49
+
50
+ UNSET = "n"
51
+
52
+ DFT_EDITOR = "/usr/bin/nano -L"
53
+
54
+ ### Display a menu of numbered choices, and return the user's choice,
55
+ ### or 'x' if the user is done choosing.
56
+ ###
57
+ ### @param header[String] The text to show above the numbered menu
58
+ ###
59
+ ### @param items[Array<String>] the items of the menu, in order.
60
+ ###
61
+ ### @return [Integer, String] The index of the chosen chosen, or 'x'
62
+ ###
63
+ def get_menu_choice (header, items)
64
+
65
+ # add a 1-based number and ) to the start of each line, like 1), and 2)...
66
+ items.each_index{|i| items[i] = "#{i +1}) #{items[i]}"}
67
+ menu_count = items.count
68
+ menu_count_display = "(1-#{menu_count}, x=done, ^c=cancel)"
69
+
70
+ menu = "#{header}\n#{items.join("\n")}"
71
+
72
+ # clear the screen between displays of the menu, so its always at the top.
73
+ system "clear" or system "cls"
74
+ puts menu
75
+ choice = ""
76
+ while choice == ""
77
+ choice = Readline.readline("Which to change? #{menu_count_display}: ", false)
78
+ break if choice == 'x'
79
+
80
+ # they chose a number..
81
+ if choice =~ /^\d+$/
82
+ # map it to one of the editing options
83
+ choice = (choice.to_i) - 1
84
+ # but they might have chosen a higher number than allowws
85
+ choice = "" unless (0..(menu_count - 1)).include? choice
86
+ else
87
+ choice = ""
88
+ end
89
+
90
+ # tell them they made a bad choice
91
+ if choice == ""
92
+ puts "\n******* Sorry, invalid choice.\n"
93
+ next
94
+ end
95
+ end # while choice == ""
96
+
97
+ return choice
98
+ end # get_menu_choice
99
+
100
+ ### Call one of the get_ methods and do the matching validity check,
101
+ ### if desired, repeatedly until a valid value is supplied.
102
+ ###
103
+ ### @param option_or_get_method[Symbol] a key of the OPTIONS hash, or the symbol representing the 'get' method
104
+ ### to call
105
+ ###
106
+ ### @param default[String] the default value when the user hits return
107
+ ###
108
+ ### @param validate_method[Symbol] the symbol representing the Admin::Validate method
109
+ ### to use in validating the input. This method must raise an exeption
110
+ ### if the input is invalid, and return the (possibly modified) value
111
+ ### when it's valid.
112
+ ###
113
+ ### @return [Object] the validated data from the user
114
+ ###
115
+ def get_value(option_or_get_method, default = nil, validate_method = nil)
116
+
117
+ # if the option_or_get_method is one of the keys in OPTIONS, then use OPTIONS[get_method][:get] if it exists
118
+ if D3::Admin::OPTIONS.keys.include?(option_or_get_method)
119
+ option_to_get = option_or_get_method
120
+ get_method = D3::Admin::OPTIONS[option_or_get_method][:get]
121
+ # if we weren't giving a validate method, get it from the OPTIONS
122
+ validate_method ||= D3::Admin::OPTIONS[option_or_get_method][:validate]
123
+ end
124
+ # otherwise we should have been given a symbolic method name.
125
+ get_method ||= option_or_get_method
126
+
127
+ valid = :start
128
+ validated = nil
129
+ until valid === true
130
+ puts "\nSorry: #{validated}, Try again.\n" unless valid === :start
131
+
132
+ value_input = self.send get_method, default
133
+
134
+ # no check method? just return the value
135
+ return value_input if validate_method.nil?
136
+
137
+ (valid, validated) = D3::Admin::Validate.validate(value_input, validate_method)
138
+
139
+ end #until valid === true
140
+ return validated
141
+ end # get value
142
+
143
+ ### Prompt for user input for an option and return the response.
144
+ ###
145
+ ### A Description of the option is displayed, followed by a prompt.
146
+ ### If a default value is provided, the prompt includes the text
147
+ ### (Hit return for '#{default_value}')
148
+ ###
149
+ ### If the option is defined in D3::Admin::OPTIONS, the data for
150
+ ### the option is used, if not provided in the args.
151
+ ###
152
+ ### If the option is defined as unsettable, a line
153
+ ### "Enter 'n' for none." is also displayed before the prompt and
154
+ ### a value of 'n' will cause the method to return nil.
155
+ ###
156
+ ### If no prompt is given in the args, the :label is used from
157
+ ### D3::Admin::OPTIONS
158
+ ###
159
+ ### If no default value is given in the args, the one from D3::Admin::OPTIONS
160
+ ### is used. If required is true, the input can't be an empty string.
161
+ ###
162
+ ### Note: watch out for nil vs false in default values
163
+ ###
164
+ ### @param desc[String] A multi-line description of the value to be entered.
165
+ ###
166
+ ### @param prompt[String] The beginning text of the line on which the user enters data
167
+ ###
168
+ ### @param opt[Symbol] The option that is being prompted for, one of the keys of D3::Admin::OPTIONS
169
+ ###
170
+ ### @param default[Object] The default value that will be used if the user just types a return
171
+ ### (i.e. an empty string is entered). For options that are pkg attributes, this should be in
172
+ ### the format stored by D3::Package objects e.g. an array of groups, a Boolean, nil.
173
+ ### The :display_conversion for that option from D3::Admin::OPTIONS will be used to generate the
174
+ ### diaplay version (e.g. a comma-separated string)
175
+ ### The symbol :no_default means don't offer a default value.
176
+ ###
177
+ ### @param required[Boolean] re-prompt until a non-empty string is entered.
178
+ ###
179
+ ### @return [String] The data entered by the user, possibly an empty string
180
+ ###
181
+ def prompt_for_data (desc: nil, prompt: nil, opt: nil, default: :no_default, required: true )
182
+
183
+ unset_line = nil
184
+ default_display = default
185
+
186
+ # look up some info about this option, if needed
187
+ if opt
188
+ opt_def = D3::Admin::OPTIONS[opt]
189
+ if opt_def
190
+ prompt ||= opt_def[:label]
191
+ unset_line = "Enter '#{UNSET}' for none." if opt_def[:unsetable]
192
+ default = opt_def[:default] if opt_def[:default] and default == :no_default
193
+ default_display = opt_def[:display_conversion].call(default) if opt_def[:display_conversion]
194
+ end
195
+ end # if args[:opt]
196
+
197
+ # some values are special for displaying
198
+ default_display = case default_display
199
+ when :no_default then ''
200
+ when D3::Admin::DFT_REQUIRED then '' # the '---Required---' should only be visible in the menu, not the prompt
201
+ when D3::Admin::DFT_NONE then UNSET
202
+ else default_display.to_s
203
+ end
204
+
205
+ data_entered = ''
206
+ puts "\n#{desc}" if desc
207
+ puts unset_line if unset_line
208
+ prompt ||= "Please enter a value"
209
+ hit_return = default_display.empty? ? "" : " (Hit return for '#{default_display}')"
210
+ prompt_line = "#{prompt}#{hit_return}: "
211
+
212
+ while true do
213
+ data_entered = Readline.readline(prompt_line, false)
214
+ data_entered = default_display if data_entered == ''
215
+ break unless required and data_entered.empty?
216
+ end
217
+ # if 'n' was typed for an unsettable option, return nil
218
+ return nil if opt_def and opt_def[:unsetable] and data_entered == UNSET
219
+ return data_entered.strip
220
+ end # prompt_for_data
221
+
222
+ ### Ask the user for an edition or basename
223
+ ### of an existing package.
224
+ ###
225
+ ### @param default[String, nil] the name to offer as default
226
+ ###
227
+ ### @return [String,nil] the edition or basename entered, or nil
228
+ ###
229
+ def get_existing_package(default = nil)
230
+ desc = <<-END_DESC
231
+ EXISTING PACKAGE
232
+ Enter a package edition or basename for an existing d3 package.
233
+ If a basename, the currently live package for that basename will be used.
234
+ Enter:
235
+ - 'v' to view a list of all packages with the basenames and editions in d3.
236
+ END_DESC
237
+
238
+ input = "v"
239
+ while input == "v" do
240
+ input = prompt_for_data(desc: desc, prompt: "Edition or Basename", default: default, required: true)
241
+ D3::Admin::Report.show_all_basenames_and_editions if input == "v"
242
+ end
243
+ return input
244
+ end # get existing pkg
245
+
246
+ ### Ask the user for an id or name
247
+ ### of an existing JSS package to import into d3
248
+ ###
249
+ ### @return [String] the name or id entered, or nil
250
+ ###
251
+ def get_jss_package_for_import (default = nil)
252
+ desc = <<-END_DESC
253
+ IMPORT JSS PACKAGE
254
+ Enter a package id or display-name for
255
+ an existing JSS package to import into d3.
256
+ Enter:
257
+ - 'v' to view a list of all JSS package names not in d3.
258
+ END_DESC
259
+
260
+ input = "v"
261
+ while input == "v" do
262
+ input = prompt_for_data(desc: desc, prompt: "JSS id or display name", default: default, required: true)
263
+ D3::Admin::Report.show_pkgs_available_for_import if input == "v"
264
+ end
265
+ return input
266
+ end # get existing pkg
267
+
268
+ ### get a basename from the user
269
+ def get_basename (default = nil)
270
+ desc = <<-END_DESC
271
+ BASENAME
272
+ Enter a basename.
273
+ Enter 'v' to view a list of all basenames in d3 and
274
+ the newest edition for each.
275
+ END_DESC
276
+
277
+ input = "v"
278
+ while input == "v" do
279
+ input = prompt_for_data(desc: desc, prompt: "Basename", required: true)
280
+ D3::Admin::Report.show_all_basenames_and_editions if input == "v"
281
+ end
282
+ return input
283
+ end # get basename
284
+
285
+ ### get a package name from user
286
+ def get_package_name (default = nil)
287
+ desc = <<-END_DESC
288
+ JSS PACKAGE NAME
289
+ Enter a unique name for this package in d3 and Casper.
290
+ Enter 'v' to view a list of package names currently in d3.
291
+ END_DESC
292
+ input = "v"
293
+ while input == "v" do
294
+ input = prompt_for_data(opt: :package_name, desc: desc, default: default, required: true)
295
+ D3::Admin::Report.show_existing_package_ids if input == "v"
296
+ end
297
+ return input
298
+ end # get pkg name
299
+
300
+ ### get a package name from user
301
+ def get_filename (default = nil)
302
+ desc = <<-END_DESC
303
+ INSTALLER FILENAME
304
+ Enter a unique name for this package's installer file
305
+ on the master distribution point. The file will be
306
+ renamed to this name on the distribution point.
307
+ Enter 'v' to see a list of existing pkg filenames in the JSS
308
+ END_DESC
309
+ input = "v"
310
+ while input == "v" do
311
+ input = prompt_for_data(opt: :filename, desc: desc, default: default, required: true)
312
+ D3::Admin::Report.show_existing_package_ids if input == "v"
313
+ end
314
+ return input
315
+ end # get pkg name
316
+
317
+ ### Get a version from the user
318
+ ###
319
+ ### @param default[String] the value to use when the user types a return.
320
+ ###
321
+ ### @return [String] the value to use as the version
322
+ def get_version (default = nil)
323
+ desc = <<-END_DESC
324
+ VERSION
325
+ Enter a version for this package.
326
+ All spaces will be converted to underscores.
327
+ END_DESC
328
+
329
+ prompt_for_data(opt: :version, desc: desc, default: default, required: true)
330
+ end
331
+
332
+ ### Get a revision from the user
333
+ ###
334
+ ### @param default[String] the rev to use when the user types a return.
335
+ ###
336
+ ### @return [String] the value to use as the rev
337
+ ###
338
+ def get_revision (default = nil)
339
+ desc = <<-END_DESC
340
+ REVISION
341
+ Enter a Package revision for this package.
342
+ This is an integer representing a new packaging of
343
+ an existing version of a given basename.
344
+ END_DESC
345
+
346
+ prompt_for_data(opt: :revision, desc: desc, default: default, required: true)
347
+ end
348
+
349
+ ### Get a multiline description from the user using the editor
350
+ ### of their choice: nano, vi, emacs, or ENV['EDITOR']
351
+ ###
352
+ ### @param desc[String] the description to start with
353
+ ###
354
+ ### @return [String] the desired description
355
+ ###
356
+ def get_description(current_desc = "")
357
+
358
+ # do we have a current desc to display and possibly keep?
359
+ current_desc_review = ""
360
+ unless current_desc.to_s.empty?
361
+ current_desc_review = "\n----- Current Description -----\n#{current_desc}\n-------------------------------\n\n"
362
+ end
363
+
364
+ if prefd_editor = D3::Admin::Prefs.prefs[:editor]
365
+ prefd_editor_choice = "\n - 'e' to edit using '#{prefd_editor}' "
366
+ else
367
+ prefd_editor_choice = ''
368
+ end
369
+
370
+ # the blurb to show the user
371
+ input_desc = <<-END_DESC
372
+ DESCRIPTION
373
+ Create a multi-line description of this package:
374
+ - what does the installed thing do?
375
+ - where did it come from, where to get updates?
376
+ - who maintains it in your environment?
377
+ - any other info useful to d3 and Casper admins.
378
+ (don't just say "installs foo" when "foo" is the basename)
379
+ #{current_desc_review}Enter:#{prefd_editor_choice}
380
+ - 'n' to edit using 'nano'
381
+ - 'v' to edit using 'vi' or 'vim'
382
+ - 'm' to edit using 'emacs'
383
+ - 'b' to have a blank description
384
+ Anything else will edit with the EDITOR for your environment
385
+ or '#{DFT_EDITOR}' if none is set.
386
+ END_DESC
387
+
388
+ # show it, get response
389
+ puts input_desc
390
+ choice = Readline.readline("Your choice (hit return to keep current desc.): ", false)
391
+
392
+ # keep or empty?
393
+ return current_desc if choice.empty?
394
+
395
+ return "" if choice.casecmp('b') == 0
396
+
397
+ # make a tem file, save current into it
398
+ desc_tmp_file = Pathname.new Tempfile.new("d3_description_")
399
+ desc_tmp_file.jss_save current_desc
400
+
401
+ # which editor?
402
+ if choice.casecmp('e') == 0
403
+ cmd = prefd_editor
404
+ elsif choice.casecmp('v') == 0
405
+ cmd = "/usr/bin/vim"
406
+ elsif choice.casecmp('m') == 0
407
+ cmd = "/usr/bin/emacs"
408
+ elsif choice.casecmp('n') == 0
409
+ cmd = "/usr/bin/nano -L"
410
+ else
411
+ cmd = ENV['EDITOR']
412
+ end
413
+ cmd ||= DFT_EDITOR
414
+
415
+ system "#{cmd} '#{desc_tmp_file}'"
416
+
417
+ result = desc_tmp_file.read.chomp
418
+ desc_tmp_file.delete
419
+ return result.chomp
420
+ end # get_description
421
+
422
+ ### Get the local path to the package being added to d3
423
+ ### Also sets @build_installer, and @build_installer_type
424
+ ### if the source is a root-folder rather than a .pkg or .dmg
425
+ ###
426
+ ### @return [Pathname] the local path to the pkg source
427
+ def get_source_path (default = false)
428
+ desc = <<-END_DESC
429
+ SOURCE
430
+ Enter the path to a .pkg or .dmg installer
431
+ or a 'root' folder from which to build one.
432
+ END_DESC
433
+
434
+ # dragging in items from the finder will esacpe spaces in the path with \'s
435
+ # in the shell this is good, but ruby is interpreting the \'s, so lets remove them.
436
+ prompt_for_data(opt: :source_path, desc: desc, default: default, required: true).strip.gsub(/\\ /," ")
437
+ end
438
+
439
+ ### If we're builting a pkg, should we build a .pkg, or a .dmg?
440
+ ###
441
+ ### @return [Symbol] :pkg or :dmg
442
+ ###
443
+ def get_package_build_type(default = D3::Admin::DFT_PKG_TYPE)
444
+ desc = <<-END_DESC
445
+ PACKAGE BUILD TYPE
446
+ Looks like we need to build the installer from a package-root.
447
+ Should we build a .pkg or .dmg? ( p = pkg, d = dmg )
448
+ END_DESC
449
+ prompt_for_data(opt: :package_build_type, desc: desc, default: default, required: true)
450
+ end
451
+
452
+ ### Get the pkg identifier for building .pkgs
453
+ ###
454
+ ### @param default[String] the default value when hitting return
455
+ ###
456
+ ### @return [String] the prefix to use
457
+ ###
458
+ def get_pkg_identifier (default = nil)
459
+ desc = <<-END_DESC
460
+ PKG IDENTIFIER
461
+ Enter the Apple .pkg indentifier for building a .pkg.
462
+ E.g. com.mycompany.myapp
463
+ END_DESC
464
+ prompt_for_data(opt: :pkg_identifier_prefix, desc: desc, default: default, required: true)
465
+ end
466
+
467
+ ### Get the pkg identifier prefex for building .pkgs
468
+ ### When building .pkgs, this string is prefixed to the
469
+ ### basename to create the Apple Pkg identifier.
470
+ ### For example if the value is com.pixar.d3, then
471
+ ### when building a pkg with the basename "foo"
472
+ ### the identifier will be com.pixar.d3.foo
473
+ ###
474
+ ### This value is saved in the admin prefs for future use.
475
+ ###
476
+ ### @param default[String] the default value when hitting return
477
+ ###
478
+ ### @return [String] the prefix to use
479
+ ###
480
+ def get_pkg_identifier_prefix (default = D3::Admin::DFT_PKG_ID_PREFIX)
481
+ desc = <<-END_DESC
482
+ PKG IDENTIFIER PREFIX
483
+ Enter the prefix to prepend to a basename to create an Apple .pkg indentifier.
484
+ E.g. If you enter 'com.mycompany', then when you build a .pkg with basename 'foo'
485
+ the default .pkg identifier will be 'com.mycompany.foo'
486
+ END_DESC
487
+ prompt_for_data(opt: :pkg_identifier_prefix, desc: desc, default: default, required: true)
488
+ end
489
+
490
+ ### Get the desired local workspace for building pkgs
491
+ ### Defaults to ENV['HOME']
492
+ ###
493
+ ### @param default[Pathname, String] the default choice when typing return
494
+ ###
495
+ ### @return [Pathname] the path to the workspace
496
+ ###
497
+ def get_workspace (default = ENV['HOME'])
498
+ desc = <<-END_DESC
499
+ PACKAGE BUILD WORKSPACE
500
+ Enter the path to a folder where we can build packages.
501
+ This will be stored between uses of d3admin.
502
+ END_DESC
503
+ Pathname.new prompt_for_data(opt: :workspace, desc: desc, default: default, required: true)
504
+ end
505
+
506
+ ### Ask if the pkg should preserve
507
+ ### source ownership, or apply OS defaults
508
+ ###
509
+ ### @param default[String] the default answer when user hits return
510
+ ###
511
+ ### @return [String] the users response
512
+ ###
513
+ def get_pkg_preserve_owners (default = 'n')
514
+ desc = <<-END_DESC
515
+ PRESERVE SOURCE OWNERSHIP
516
+ When building a .pkg, the OS generally sets the ownership and permissions
517
+ of the payload to match OS standards, e.g. Apps owned by 'root' with group
518
+ 'admin' or 'wheel'
519
+
520
+ If desired you can preserve the current ownership and permissions of the source
521
+ folder contents when the payload is installed. This is generally not recomended.
522
+
523
+ Should we override the OS and preserve the ownership on
524
+ the source folder when the item is installed on the client?
525
+ Enter 'y' or 'n'
526
+ END_DESC
527
+ prompt_for_data(desc: desc, prompt: "Preserve ownership (y/n)", default: default, required: true)
528
+ end
529
+
530
+ ### Get a pre-install script, either local file, JSS id, or JSS name
531
+ ###
532
+ ### @param default[String] the name of an existing JSS script to use
533
+ ###
534
+ ### @return [Pathname, Integer, nil] The local script file, or the JSS id of the
535
+ ### chosen script
536
+ ###
537
+ def get_pre_install_script (default = nil)
538
+ get_script "PRE-INSTALL SCRIPT", :pre_install , default
539
+ end
540
+
541
+ ### Get a post-install script, either local file, JSS id, or JSS name
542
+ ###
543
+ ### @param default[String] the name of an existing JSS script to use
544
+ ###
545
+ ### @return [Pathname, Integer, nil] The local script file, or the JSS id of the
546
+ ### chosen script
547
+ ###
548
+ def get_post_install_script (default = nil)
549
+ get_script "POST-INSTALL SCRIPT", :post_install , default
550
+ end
551
+
552
+ ### Get a pre-remove script, either local file, JSS id, or JSS name
553
+ ###
554
+ ### @param default[String] the name of an existing JSS script to use
555
+ ###
556
+ ### @return [Pathname, Integer, nil] The local script file, or the JSS id of the
557
+ ### chosen script
558
+ ###
559
+ def get_pre_remove_script (default = nil)
560
+ get_script "PRE-REMOVE SCRIPT", :pre_remove , default
561
+ end
562
+
563
+ ### Get a post-remove script, either local file, JSS id, or JSS name
564
+ ###
565
+ ### @param default[String] the name of an existing JSS script to use
566
+ ###
567
+ ### @return [Pathname, Integer, nil] The local script file, or the JSS id of the
568
+ ### chosen script
569
+ ###
570
+ def get_post_remove_script (default = nil)
571
+ get_script "POST-REMOVE SCRIPT", :post_remove , default
572
+ end
573
+
574
+ ### Get a script, either local file, JSS id, or JSS name
575
+ ###
576
+ ### @param default[String] the name of an existing JSS script to use
577
+ ###
578
+ ### @return [Pathname, Integer, nil] The local script file, or the JSS id of the
579
+ ### chosen script
580
+ ###
581
+ def get_script (heading, opt , default = nil)
582
+ desc = <<-END_DESC
583
+ #{heading}
584
+ Enter a path to a local file containing the script
585
+ or the name or id of an existing script in the JSS.
586
+ Enter 'v' to view a list of scripts in the JSS.
587
+ END_DESC
588
+
589
+ result = "v"
590
+ while result == "v" do
591
+ result = prompt_for_data(opt: opt, desc: desc, default: default, required: true)
592
+ D3.less_text JSS::Script.all_names.sort_by{|s| s.downcase}.join("\n") if result == "v"
593
+ end
594
+ return result
595
+ end
596
+
597
+ ### Prompt the admin for one or more auto-groups for this installer
598
+ ###
599
+ ### @param default[nil,String,Array<String>] The groups to use
600
+ ###
601
+ ### @return [String]
602
+ def get_auto_groups (default = nil)
603
+ desc = <<-END_DESC
604
+ AUTO-INSTALL GROUPS
605
+ Enter a comma-separated list of JSS Computer Group names whose members should
606
+ have this package installed automatically when it is made live.
607
+ Enter 'v' to view a list of computer groups.
608
+ Enter '#{D3::STANDARD_AUTO_GROUP}' to install on all machines.
609
+ END_DESC
610
+ get_groups desc, :auto_groups, default
611
+ end # get auto
612
+
613
+ ### Prompt the admin for one or more auto-groups for this installer
614
+ ###
615
+ ### @param default[nil,String,Array<String>] The groups to
616
+ def get_excluded_groups (default = nil)
617
+
618
+ desc = <<-END_PROMPT
619
+ EXCLUDED GROUPS
620
+ Enter a comma-separated list of JSS Computer Group names
621
+ whose members should not get this installed without force.
622
+ Enter 'v' to view list of computer groups.
623
+ END_PROMPT
624
+ get_groups desc, :excluded_groups, default
625
+ end # get auto
626
+
627
+ ### Prompt the admin for text to search for package searchs
628
+ ###
629
+ ### @return [String] whatever the admin typed
630
+ ###
631
+ def get_search_target (default = false)
632
+ desc = <<-END_PROMPT
633
+ SEARCH TEXT
634
+ Enter text to use in matching basenames or computer group names.
635
+ Matching a basename will list all packages with the basename.
636
+ Matching a group name will list all packages auto-installed or
637
+ excluded for the group. (RegExp's OK)
638
+ Enter 'all' to list all packages in d3.
639
+ END_PROMPT
640
+ prompt_for_data( desc: desc, prompt: "Text to match or 'all'").chomp
641
+ end # get auto
642
+
643
+
644
+ def get_status_for_filter (with_frozen = false)
645
+ if with_frozen
646
+ frozen_line = "\nUse 'frozen' to limit to frozen receipts"
647
+ frozen_title = " OR FROZEN"
648
+ else
649
+ frozen_line = ""
650
+ frozen_title = ""
651
+ end
652
+
653
+ desc = <<-END_PROMPT
654
+ LIMIT TO STATUS#{frozen_title}
655
+ Enter a comma-separate list of statuses for limiting the list.
656
+ Valid Statuses are: #{D3::Basename::STATUSES_FOR_FILTERS.join(", ")}#{frozen_line}
657
+ Enter 'all' to show all statuses
658
+ END_PROMPT
659
+ prompt_for_data( desc: desc, prompt: "Statuses", default: 'all').chomp
660
+ end
661
+
662
+ ### Prompt the admin for one or more groups
663
+ ###
664
+ ### @param default[String,Array<String>] The groups to use
665
+ ###
666
+ ### @return [String,nil]
667
+ ###
668
+ def get_groups (desc, opt, default = nil)
669
+
670
+ result = "v"
671
+ while result == "v" do
672
+ result = prompt_for_data(opt: opt, desc: desc, default: default, required: true)
673
+ D3.less_text JSS::ComputerGroup.all_names.sort_by{|s| s.downcase}.join("\n") if result == "v"
674
+ end
675
+
676
+ return result
677
+ end # get auto
678
+
679
+ ### Get a list of allowed OSes for this pkg
680
+ ###
681
+ ### @param default[String, Array] An array or comma-separated list of OSes
682
+ ### selected when the user hits return
683
+ ###
684
+ ### @return [String,nil] A comma-separated list of allowed OSes
685
+ ###
686
+ def get_oses (default = [])
687
+ desc = <<-END_DESC
688
+ LIMIT TO OS's
689
+ Enter a comma-separated list of OS's allowed to
690
+ install this package, e.g. '10.8.5, 10.9.5, 10.10.x'
691
+ Use '>=' to set a minimum OS, e.g. '>=10.8.5'
692
+ END_DESC
693
+ prompt_for_data(desc: desc, opt: :oses, default: default, required: true)
694
+ end
695
+
696
+ ### Get a the CPU-type limitation for this package
697
+ ###
698
+ ### @param default[String] the default limitation if the user hits return
699
+ ###
700
+ ### @return [Symbol,nil] :ppc, :intel, or nil
701
+ ###
702
+ def get_cpu_type (default = 'x86')
703
+ desc = <<-END_DESC
704
+ LIMIT TO CPU TYPE
705
+ Should this packge be limited to certain CPU types?
706
+ Enter 'ppc' or 'x86' or 'none' for neither.
707
+ END_DESC
708
+ prompt_for_data(desc: desc, opt: :cpu_type, default: default, required: true)
709
+ end
710
+
711
+ ### Get a JSS Category from the user
712
+ ###
713
+ ### @param default[String] the category used when the user hits return
714
+ ###
715
+ ### @return [String] the category entered by the user
716
+ ###
717
+ def get_category (default = "n")
718
+ desc = <<-END_DESC
719
+ CATEGORY
720
+ Enter the JSS category name for this package.
721
+ Enter:
722
+ - 'v' to view all JSS categories
723
+ - 'n' for no category
724
+ END_DESC
725
+
726
+ result = "v"
727
+ while result == "v" do
728
+ result = prompt_for_data(desc: desc, prompt: "Category", default: default, required: true)
729
+ D3.less_text JSS::Category.all_names.sort_by{|c| c.downcase}.join("\n") if result == "v"
730
+ end
731
+ return nil if result == 'n'
732
+ result
733
+ end
734
+
735
+ ### Get a pattern to match for the prohibiting process
736
+ ### If this matches a line of output from `/bin/ps -A -c -o comm`
737
+ ### at install time, then the install won't happen.
738
+ ### Strings must match a whole line, Regexps will work with
739
+ ### any match.
740
+ ###
741
+ ### @param default[String,Regexp] the default pattern when hitting return
742
+ ###
743
+ ### @return [Regexp,nil] the pattern to match
744
+ ###
745
+ def get_prohibiting_process (default = 'n')
746
+ desc = <<-END_DESC
747
+ PROHIBITING PROCESS
748
+ Enter the name of a process as it appears on one line
749
+ of the output of `/bin/ps -A -c -o comm`
750
+
751
+ If this process is running at install time,
752
+ the installation will be skipped.
753
+ Matching is case-insensitive
754
+
755
+ Enter 'n' for none.
756
+ END_DESC
757
+
758
+ result = prompt_for_data(desc: desc, prompt: "Prohibiting Process", default: default, required: true)
759
+ return nil if result == 'n'
760
+ result
761
+ end
762
+
763
+ ### Ask if this package is uninstallable
764
+ ###
765
+ ### @param default[String] the default answer when user hits return
766
+ ###
767
+ ### @return [String] the users response
768
+ ###
769
+ def get_removable (default = 'y')
770
+ desc = <<-END_DESC
771
+ REMOVABLE
772
+ Can this package be uninstalled?
773
+ Enter 'y' or 'n'
774
+ END_DESC
775
+ prompt_for_data(desc: desc, prompt: "Removable? (y/n)", default: default, required: true)
776
+ end
777
+
778
+ ### Ask if we should ininstall older versions of this basename
779
+ ### before installing this one
780
+ ###
781
+ ### @param default[String] the default answer when user hits return
782
+ ###
783
+ ### @return [String] the users response
784
+ ###
785
+ def get_remove_first (default = 'y')
786
+ desc = <<-END_DESC
787
+ UNINSTALL OLDER VERSIONS
788
+ Should older versions of this basename be uninstalled
789
+ (if they are removable) before attempting to install this package?
790
+ Enter 'y' or 'n'
791
+ END_DESC
792
+ prompt_for_data(desc: desc, prompt: "Remove older installs first? (y/n)", default: default, required: true)
793
+ end
794
+
795
+ ### Ask if this package needs a reboot
796
+ ###
797
+ ### @param default[String] the default answer when user hits return
798
+ ###
799
+ ### @return [String] the users response
800
+ ###
801
+ def get_reboot (default = 'n')
802
+ desc = <<-END_DESC
803
+ REBOOT REQUIRED (PUPPIES!)
804
+ Does this package require a reboot after installation?
805
+ If so, it will be added to the Puppy Queue when installed
806
+ with 'd3 install', and the user will be notified to log
807
+ out as soon as possible.
808
+ Enter 'y' or 'n'
809
+ END_DESC
810
+ prompt_for_data(desc: desc, prompt: "Requires reboot? (y/n)", default: default, required: true)
811
+
812
+ end
813
+
814
+ ### Get an expiration period (# of days) from the user
815
+ ###
816
+ ### @param default[Integer] the # to use when the user types a return.
817
+ ###
818
+ ### @return [Integer] the value to use as the expiration
819
+ ###
820
+ def get_expiration (default = 0)
821
+ desc = <<-END_DESC
822
+ EXPIRATION
823
+ On machines that allow package expiration,
824
+ should this package be removed after some
825
+ number of days without being used?
826
+ Enter the number of days, or 0 for no expiration.
827
+ END_DESC
828
+
829
+ prompt_for_data(desc: desc, prompt: "Expiration days", default: default, required: true)
830
+ end
831
+
832
+ ### Get the path to the application to monitor for expiration
833
+ ###
834
+ ### @param default[Pathname, String] the default choice when typing return
835
+ ###
836
+ ### @return [Pathname] the path to the application
837
+ ###
838
+ def get_expiration_path (default = 'n')
839
+ desc = <<-END_DESC
840
+ EXPIRATION PATH
841
+ Enter the path to a the application that must be used
842
+ to prevent expiration.
843
+ E.g. /Applications/Google Chrome.app
844
+ Enter 'n' for none
845
+ END_DESC
846
+ prompt_for_data(desc: desc, prompt: "Expiration Path", default: default, required: true)
847
+ end
848
+
849
+ ### when deleting a pkg, should its pre- and post- scripts be deleted
850
+ ###
851
+ ### @param default[String] the default answer when user hits return
852
+ ###
853
+ ### @return [String] the users response
854
+ ###
855
+ def get_delete_scripts (default = 'n')
856
+ desc = <<-END_DESC
857
+ DELETE ASSOCIATED SCRIPTS?
858
+ When deleting a package, should any associated scripts
859
+ (pre-install, post-install, pre-remove, post-remove) also be deleted?
860
+
861
+ NOTE: If any other d3 packages or policies are using the scripts
862
+ they won't be deleted, but the other users will be reported.
863
+ Enter 'y' or 'n'
864
+ END_DESC
865
+ prompt_for_data(desc: desc, prompt: "Delete Scripts? (y/n)", default: default, required: true)
866
+ end
867
+
868
+ ### when deleting a pkg, should it be kept in the JSS?
869
+ ###
870
+ ### @param default[String] the default answer when user hits return
871
+ ###
872
+ ### @return [String] the users response
873
+ ###
874
+ def get_keep_in_jss (default = 'n')
875
+ desc = <<-END_DESC
876
+ KEEP THE PACKAGE IN THE JSS?
877
+ When deleting a package, should it be kept as a JSS package
878
+ and only deleted from d3?
879
+ Enter 'y' or 'n'
880
+ END_DESC
881
+ prompt_for_data(desc: desc, prompt: "Keep in JSS? (y/n)", default: default, required: true)
882
+ end
883
+
884
+ ### what kind of package list are we showing?
885
+ ###
886
+ ### @param default[String] the default answer when user hits return
887
+ ###
888
+ ### @return [String] the chosen report type
889
+ ###
890
+ def get_show_type (default = D3::Admin::Report::DFT_SHOW_TYPE)
891
+ desc = <<-END_DESC
892
+ SERVER PACKAGE LIST
893
+ Enter the type of list you'd like to generate about packages in d3.
894
+
895
+ One of:
896
+ all - all packages in d3
897
+ pilot - packages newer than live
898
+ live - live packages
899
+ deprecated - old packages that used to be live
900
+ skipped - old packages that were never made live
901
+ missing - packages in d3, but not Casper
902
+ auto - packages auto-installed for a given computer group
903
+ excluded - packages not available to a given computer group
904
+ END_DESC
905
+ prompt_for_data(desc: desc, prompt: "Show packages", default: default, required: true)
906
+ end
907
+
908
+ ### What computer are we generating a receipt report for?
909
+ ###
910
+ ### @return [String] A computer name in the JSS
911
+ ###
912
+ def get_computer (default = nil)
913
+ desc = <<-END_DESC
914
+ COMPUTER NAME
915
+ Enter the name of a computer Casper.
916
+ Enter 'v' to view a list available computer names.
917
+ END_DESC
918
+ input = "v"
919
+ while input == "v" do
920
+ input = prompt_for_data(desc: desc, prompt: "Computer name", default: nil, required: true)
921
+ D3::Admin::Report.show_available_computers_for_reports if input == "v"
922
+ end
923
+ return input
924
+ end # get computer
925
+
926
+ ### Get the config target
927
+ ###
928
+ ### @param default[String] the default value when hitting return
929
+ ###
930
+ ### @return [String] the prefix to use
931
+ ###
932
+ def get_config_target (default = "all")
933
+ desc = <<-END_DESC
934
+ CONFIGURATION
935
+ Which setting would you like to configure?
936
+ jss - the JSS and credentials (stored in your keychain)
937
+ db - the MySQL server and credentials (stored in your keychain)
938
+ dist - the master distribution point RW password (stored in your keychain)
939
+ workspace - the folder in which to build .pkgs and .dmgs
940
+ editor - the shell command for editing package descriptions
941
+ pkg-id-prefix - the prefix for the .pkg identifier when building .pkgs
942
+ all - all of the above
943
+ display - show current configuration
944
+
945
+ END_DESC
946
+ prompt_for_data(opt: :pkg_identifier_prefix, desc: desc, default: default, required: true)
947
+ end
948
+
949
+ ### get the shell command for editing package descriptions
950
+ ###
951
+ ### @param default[String] the default value when hitting return
952
+ ###
953
+ ### @return [String] the command to use
954
+ ###
955
+ def get_editor (default = "/usr/bin/nano")
956
+ desc = <<-END_DESC
957
+ EDITOR
958
+ Enter the shell command to use during --walkthru
959
+ for editing package descriptions
960
+ e.g. /usr/bin/vim, /usr/bin/emacs
961
+
962
+ Note: if the command launches a GUI editor, make sure the
963
+ shell command stays running until the document is closed.
964
+ Most such editors have an option for that.
965
+ END_DESC
966
+ prompt_for_data( desc: desc, default: default,prompt: "Command", required: true)
967
+ end
968
+
969
+ end # module
970
+ end # module Admin
971
+ end # module D3
972
+