Module: D3::Admin::Interactive
Overview
This module contains methods for interacting with the user in the terminal prompting for data related to administering d3 packages.
These methods all return a string of user input, possibly an empty string.
Constant Summary collapse
- UNSET =
'n'.freeze
- DFT_EDITOR =
'/usr/bin/nano -L'.freeze
Class Method Summary collapse
-
.get_auto_groups(default = nil) ⇒ String
Prompt the admin for one or more auto-groups for this installer.
-
.get_basename(default = nil) ⇒ Object
get a basename from the user.
-
.get_category(default = 'n') ⇒ String
Get a JSS Category from the user.
-
.get_computer(default = nil) ⇒ String
What computer are we generating a receipt report for?.
-
.get_config_target(default = 'all') ⇒ String
Get the config target.
-
.get_cpu_type(default = 'x86') ⇒ Symbol?
Get a the CPU-type limitation for this package.
-
.get_description(current_desc = '') ⇒ String
Get a multiline description from the user using the editor of their choice: nano, vi, emacs, or ENV.
-
.get_editor(default = '/usr/bin/nano') ⇒ String
get the shell command for editing package descriptions.
-
.get_excluded_groups(default = nil) ⇒ Object
Prompt the admin for one or more auto-groups for this installer.
-
.get_existing_package(default = nil) ⇒ String?
Ask the user for an edition or basename of an existing package.
-
.get_expiration(default = 0) ⇒ Integer
Get an expiration period (# of days) from the user.
-
.get_expiration_paths(default = 'n') ⇒ Array<Pathname>
Get the path to the executable(s) to monitor for expiration.
-
.get_filename(default = nil) ⇒ Object
get a package name from user.
-
.get_groups(desc, opt, default = nil) ⇒ String?
Prompt the admin for one or more groups.
-
.get_jss_package_for_import(default = nil) ⇒ String
Ask the user for an id or name of an existing JSS package to import into d3.
-
.get_keep_in_jss(default = 'n') ⇒ String
when deleting a pkg, should it be kept in the JSS?.
-
.get_keep_scripts(default = 'n') ⇒ String
when deleting a pkg, should its pre- and post- scripts be kept?.
-
.get_menu_choice(header, items) ⇒ Integer, String
Display a menu of numbered choices, and return the user’s choice, or ‘x’ if the user is done choosing.
-
.get_oses(default = []) ⇒ String?
Get a list of allowed OSes for this pkg.
-
.get_package_build_type(default = D3::Admin::DFT_PKG_TYPE) ⇒ Symbol
If we’re builting a pkg, should we build a .pkg, or a .dmg?.
-
.get_package_name(default = nil) ⇒ Object
get a package name from user.
-
.get_pkg_identifier(default = nil) ⇒ String
Get the pkg identifier for building .pkgs.
-
.get_pkg_identifier_prefix(default = D3::Admin::DFT_PKG_ID_PREFIX) ⇒ String
Get the pkg identifier prefex for building .pkgs When building .pkgs, this string is prefixed to the basename to create the Apple Pkg identifier.
-
.get_pkg_preserve_owners(default = 'n') ⇒ String
Ask if the pkg should preserve source ownership, or apply OS defaults.
-
.get_post_install_script(default = nil) ⇒ Pathname, ...
Get a post-install script, either local file, JSS id, or JSS name.
-
.get_post_remove_script(default = nil) ⇒ Pathname, ...
Get a post-remove script, either local file, JSS id, or JSS name.
-
.get_pre_install_script(default = nil) ⇒ Pathname, ...
Get a pre-install script, either local file, JSS id, or JSS name.
-
.get_pre_remove_script(default = nil) ⇒ Pathname, ...
Get a pre-remove script, either local file, JSS id, or JSS name.
-
.get_prohibiting_processes(default = 'n') ⇒ Regexp?
Get a pattern to match for the prohibiting processes If this matches a line of output from ‘/bin/ps -A -c -o comm` at install time, then graceful quit will be attempted.
-
.get_reboot(default = 'n') ⇒ String
Ask if this package needs a reboot.
-
.get_removable(default = 'y') ⇒ String
Ask if this package is uninstallable.
-
.get_remove_first(default = 'y') ⇒ String
Ask if we should ininstall older versions of this basename before installing this one.
-
.get_revision(default = nil) ⇒ String
Get a revision from the user.
-
.get_script(heading, opt, default = nil) ⇒ Pathname, ...
Get a script, either local file, JSS id, or JSS name.
-
.get_search_target(default = false) ⇒ String
Prompt the admin for text to search for package searchs.
-
.get_show_type(default = D3::Admin::Report::DFT_SHOW_TYPE) ⇒ String
what kind of package list are we showing?.
-
.get_signing_identity(default = ) ⇒ String
Get the optional Apple Developer signing ID .pkgs can be codesigned with a certificate from Apple The Developer ID Installer certificate must be in the login.keychain of the user operating d3admin unless otherwise specified in signing_options.
-
.get_signing_options(default = ) ⇒ String
Get any arguments and options to pass to pkgbuild A signing identity must be defined for these options to be used.
-
.get_source_path(default = false) ⇒ Pathname
Get the local path to the package being added to d3 Also sets @build_installer, and @build_installer_type if the source is a root-folder rather than a .pkg or .dmg.
-
.get_status_for_filter(with_frozen = false) ⇒ Object
get auto.
-
.get_value(option_or_get_method, default = nil, validate_method = nil) ⇒ Object
Call one of the get_ methods and do the matching validity check, if desired, repeatedly until a valid value is supplied.
-
.get_version(default = nil) ⇒ String
Get a version from the user.
-
.get_workspace(default = ) ⇒ Pathname
Get the desired local workspace for building pkgs Defaults to ENV.
-
.prompt_for_data(desc: nil, prompt: nil, opt: nil, default: :no_default, required: true) ⇒ String
Prompt for user input for an option and return the response.
Instance Method Summary collapse
-
#get_auto_groups(default = nil) ⇒ String
Prompt the admin for one or more auto-groups for this installer.
-
#get_basename(default = nil) ⇒ Object
get a basename from the user.
-
#get_category(default = 'n') ⇒ String
Get a JSS Category from the user.
-
#get_computer(default = nil) ⇒ String
What computer are we generating a receipt report for?.
-
#get_config_target(default = 'all') ⇒ String
Get the config target.
-
#get_cpu_type(default = 'x86') ⇒ Symbol?
Get a the CPU-type limitation for this package.
-
#get_description(current_desc = '') ⇒ String
Get a multiline description from the user using the editor of their choice: nano, vi, emacs, or ENV.
-
#get_editor(default = '/usr/bin/nano') ⇒ String
get the shell command for editing package descriptions.
-
#get_excluded_groups(default = nil) ⇒ Object
Prompt the admin for one or more auto-groups for this installer.
-
#get_existing_package(default = nil) ⇒ String?
Ask the user for an edition or basename of an existing package.
-
#get_expiration(default = 0) ⇒ Integer
Get an expiration period (# of days) from the user.
-
#get_expiration_paths(default = 'n') ⇒ Array<Pathname>
Get the path to the executable(s) to monitor for expiration.
-
#get_filename(default = nil) ⇒ Object
get a package name from user.
-
#get_groups(desc, opt, default = nil) ⇒ String?
Prompt the admin for one or more groups.
-
#get_jss_package_for_import(default = nil) ⇒ String
Ask the user for an id or name of an existing JSS package to import into d3.
-
#get_keep_in_jss(default = 'n') ⇒ String
when deleting a pkg, should it be kept in the JSS?.
-
#get_keep_scripts(default = 'n') ⇒ String
when deleting a pkg, should its pre- and post- scripts be kept?.
-
#get_menu_choice(header, items) ⇒ Integer, String
Display a menu of numbered choices, and return the user’s choice, or ‘x’ if the user is done choosing.
-
#get_oses(default = []) ⇒ String?
Get a list of allowed OSes for this pkg.
-
#get_package_build_type(default = D3::Admin::DFT_PKG_TYPE) ⇒ Symbol
If we’re builting a pkg, should we build a .pkg, or a .dmg?.
-
#get_package_name(default = nil) ⇒ Object
get a package name from user.
-
#get_pkg_identifier(default = nil) ⇒ String
Get the pkg identifier for building .pkgs.
-
#get_pkg_identifier_prefix(default = D3::Admin::DFT_PKG_ID_PREFIX) ⇒ String
Get the pkg identifier prefex for building .pkgs When building .pkgs, this string is prefixed to the basename to create the Apple Pkg identifier.
-
#get_pkg_preserve_owners(default = 'n') ⇒ String
Ask if the pkg should preserve source ownership, or apply OS defaults.
-
#get_post_install_script(default = nil) ⇒ Pathname, ...
Get a post-install script, either local file, JSS id, or JSS name.
-
#get_post_remove_script(default = nil) ⇒ Pathname, ...
Get a post-remove script, either local file, JSS id, or JSS name.
-
#get_pre_install_script(default = nil) ⇒ Pathname, ...
Get a pre-install script, either local file, JSS id, or JSS name.
-
#get_pre_remove_script(default = nil) ⇒ Pathname, ...
Get a pre-remove script, either local file, JSS id, or JSS name.
-
#get_prohibiting_processes(default = 'n') ⇒ Regexp?
Get a pattern to match for the prohibiting processes If this matches a line of output from ‘/bin/ps -A -c -o comm` at install time, then graceful quit will be attempted.
-
#get_reboot(default = 'n') ⇒ String
Ask if this package needs a reboot.
-
#get_removable(default = 'y') ⇒ String
Ask if this package is uninstallable.
-
#get_remove_first(default = 'y') ⇒ String
Ask if we should ininstall older versions of this basename before installing this one.
-
#get_revision(default = nil) ⇒ String
Get a revision from the user.
-
#get_script(heading, opt, default = nil) ⇒ Pathname, ...
Get a script, either local file, JSS id, or JSS name.
-
#get_search_target(default = false) ⇒ String
Prompt the admin for text to search for package searchs.
-
#get_show_type(default = D3::Admin::Report::DFT_SHOW_TYPE) ⇒ String
what kind of package list are we showing?.
-
#get_signing_identity(default = ) ⇒ String
Get the optional Apple Developer signing ID .pkgs can be codesigned with a certificate from Apple The Developer ID Installer certificate must be in the login.keychain of the user operating d3admin unless otherwise specified in signing_options.
-
#get_signing_options(default = ) ⇒ String
Get any arguments and options to pass to pkgbuild A signing identity must be defined for these options to be used.
-
#get_source_path(default = false) ⇒ Pathname
Get the local path to the package being added to d3 Also sets @build_installer, and @build_installer_type if the source is a root-folder rather than a .pkg or .dmg.
-
#get_status_for_filter(with_frozen = false) ⇒ Object
get auto.
-
#get_value(option_or_get_method, default = nil, validate_method = nil) ⇒ Object
Call one of the get_ methods and do the matching validity check, if desired, repeatedly until a valid value is supplied.
-
#get_version(default = nil) ⇒ String
Get a version from the user.
-
#get_workspace(default = ) ⇒ Pathname
Get the desired local workspace for building pkgs Defaults to ENV.
-
#prompt_for_data(desc: nil, prompt: nil, opt: nil, default: :no_default, required: true) ⇒ String
Prompt for user input for an option and return the response.
Class Method Details
.get_auto_groups(default = nil) ⇒ String
Prompt the admin for one or more auto-groups for this installer
637 638 639 640 641 642 643 644 645 646 |
# File 'lib/d3/admin/interactive.rb', line 637 def get_auto_groups(default = nil) desc = <<-END_DESC AUTO-INSTALL GROUPS Enter a comma-separated list of JSS Computer Group names whose members should have this package installed automatically when it is made live. Enter 'v' to view a list of computer groups. Enter '#{D3::STANDARD_AUTO_GROUP}' to install on all machines. END_DESC get_groups desc, :auto_groups, default end |
.get_basename(default = nil) ⇒ Object
get a basename from the user
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/d3/admin/interactive.rb', line 265 def get_basename(default = nil) desc = <<-END_DESC BASENAME Enter a basename. Enter 'v' to view a list of all basenames in d3 and the newest edition for each. END_DESC input = 'v' while input == 'v' input = prompt_for_data(desc: desc, prompt: 'Basename', required: true) D3::Admin::Report.show_all_basenames_and_editions if input == 'v' end input end |
.get_category(default = 'n') ⇒ String
Get a JSS Category from the user
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
# File 'lib/d3/admin/interactive.rb', line 748 def get_category(default = 'n') desc = <<-END_DESC CATEGORY Enter the JSS category name for this package. Enter: - 'v' to view all JSS categories - 'n' for no category END_DESC result = 'v' while result == 'v' result = prompt_for_data(desc: desc, prompt: 'Category', default: default, required: true) D3.less_text JSS::Category.all_names.sort_by(&:downcase).join("\n") if result == 'v' end return nil if result == 'n' result end |
.get_computer(default = nil) ⇒ String
What computer are we generating a receipt report for?
945 946 947 948 949 950 951 952 953 954 955 956 957 |
# File 'lib/d3/admin/interactive.rb', line 945 def get_computer(default = nil) desc = <<-END_DESC COMPUTER NAME Enter the name of a computer Jamf Pro. Enter 'v' to view a list available computer names. END_DESC input = 'v' while input == 'v' input = prompt_for_data(desc: desc, prompt: 'Computer name', default: nil, required: true) D3::Admin::Report.show_available_computers_for_reports if input == 'v' end input end |
.get_config_target(default = 'all') ⇒ String
Get the config target
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 |
# File 'lib/d3/admin/interactive.rb', line 965 def get_config_target(default = 'all') desc = <<-END_DESC CONFIGURATION Which setting would you like to configure? jss - the JSS and credentials (stored in your keychain) db - the MySQL server and credentials (stored in your keychain) dist - the master distribution point RW password (stored in your keychain) workspace - the folder in which to build .pkgs and .dmgs editor - the shell command for editing package descriptions pkg-id-prefix - the prefix for the .pkg identifier when building .pkgs signing-identity - optional Developer ID Installer certificate issued by Apple signing-options - optional string of signing options to pass to pkgbuild. all - all of the above display - show current configuration END_DESC prompt_for_data(opt: :pkg_identifier_prefix, desc: desc, default: default, required: true) end |
.get_cpu_type(default = 'x86') ⇒ Symbol?
Get a the CPU-type limitation for this package
733 734 735 736 737 738 739 740 |
# File 'lib/d3/admin/interactive.rb', line 733 def get_cpu_type(default = 'x86') desc = <<-END_DESC LIMIT TO CPU TYPE Should this packge be limited to certain CPU types? Enter 'ppc' or 'x86' or 'none' for neither. END_DESC prompt_for_data(desc: desc, opt: :cpu_type, default: default, required: true) end |
.get_description(current_desc = '') ⇒ String
Get a multiline description from the user using the editor of their choice: nano, vi, emacs, or ENV
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
# File 'lib/d3/admin/interactive.rb', line 352 def get_description(current_desc = '') # do we have a current desc to display and possibly keep? current_desc_review = '' unless current_desc.to_s.empty? current_desc_review = "\n----- Current Description -----\n#{current_desc}\n-------------------------------\n\n" end if prefd_editor = D3::Admin::Prefs.prefs[:editor] prefd_editor_choice = "\n - 'e' to edit using '#{prefd_editor}' " else prefd_editor_choice = '' end # the blurb to show the user input_desc = <<-END_DESC DESCRIPTION Create a multi-line description of this package: - what does the installed thing do? - where did it come from, where to get updates? - who maintains it in your environment? - any other info useful to d3 and Jamf Pro admins. (don't just say "installs foo" when "foo" is the basename) #{current_desc_review}Enter:#{prefd_editor_choice} - 'n' to edit using 'nano' - 'v' to edit using 'vi' or 'vim' - 'm' to edit using 'emacs' - 'b' to have a blank description Anything else will edit with the EDITOR for your environment or '#{DFT_EDITOR}' if none is set. END_DESC # show it, get response puts input_desc choice = Readline.readline('Your choice (hit return to keep current desc.): ', false) # keep or empty? return current_desc if choice.empty? return '' if choice.casecmp('b').zero? # make a tem file, save current into it desc_tmp_file = Pathname.new Tempfile.new('d3_description_') desc_tmp_file.jss_save current_desc # which editor? if choice.casecmp('e').zero? cmd = prefd_editor elsif choice.casecmp('v').zero? cmd = '/usr/bin/vim' elsif choice.casecmp('m').zero? cmd = '/usr/bin/emacs' elsif choice.casecmp('n').zero? cmd = '/usr/bin/nano -L' else cmd = ENV['EDITOR'] end cmd ||= DFT_EDITOR system "#{cmd} '#{desc_tmp_file}'" result = desc_tmp_file.read.chomp desc_tmp_file.delete result.chomp end |
.get_editor(default = '/usr/bin/nano') ⇒ String
get the shell command for editing package descriptions
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 |
# File 'lib/d3/admin/interactive.rb', line 990 def get_editor(default = '/usr/bin/nano') desc = <<-END_DESC EDITOR Enter the shell command to use during --walkthru for editing package descriptions e.g. /usr/bin/vim, /usr/bin/emacs Note: if the command launches a GUI editor, make sure the shell command stays running until the document is closed. Most such editors have an option for that. END_DESC prompt_for_data(desc: desc, default: default, prompt: 'Command', required: true) end |
.get_excluded_groups(default = nil) ⇒ Object
Prompt the admin for one or more auto-groups for this installer
651 652 653 654 655 656 657 658 659 |
# File 'lib/d3/admin/interactive.rb', line 651 def get_excluded_groups(default = nil) desc = <<-END_PROMPT EXCLUDED GROUPS Enter a comma-separated list of JSS Computer Group names whose members should not get this installed without force. Enter 'v' to view list of computer groups. END_PROMPT get_groups desc, :excluded_groups, default end |
.get_existing_package(default = nil) ⇒ String?
Ask the user for an edition or basename of an existing package.
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/d3/admin/interactive.rb', line 225 def get_existing_package(default = nil) desc = <<-END_DESC EXISTING PACKAGE Enter a package edition or basename for an existing d3 package. If a basename, the currently live package for that basename will be used. Enter: - 'v' to view a list of all packages with the basenames and editions in d3. END_DESC input = 'v' while input == 'v' input = prompt_for_data(desc: desc, prompt: 'Edition or Basename', default: default, required: true) D3::Admin::Report.show_all_basenames_and_editions if input == 'v' end input end |
.get_expiration(default = 0) ⇒ Integer
Get an expiration period (# of days) from the user
852 853 854 855 856 857 858 859 860 861 862 |
# File 'lib/d3/admin/interactive.rb', line 852 def get_expiration(default = 0) desc = <<-END_DESC EXPIRATION On machines that allow package expiration, should this package be removed after some number of days without being used? Enter the number of days, or 0 for no expiration. END_DESC prompt_for_data(desc: desc, prompt: 'Expiration days', default: default, required: true) end |
.get_expiration_paths(default = 'n') ⇒ Array<Pathname>
Get the path to the executable(s) to monitor for expiration
870 871 872 873 874 875 876 877 878 879 880 |
# File 'lib/d3/admin/interactive.rb', line 870 def get_expiration_paths(default = 'n') desc = <<-END_DESC EXPIRATION PATH(S) Enter the path(s) to the executable(s) that must be used to prevent expiration. Multiple paths should be separated by commas, spaces should not be escaped. E.g. /Applications/Google Chrome.app/Contents/MacOS/Google Chrome, /Applications/Firefox.app/Contents/MacOS/firefox Enter 'n' for none END_DESC prompt_for_data(desc: desc, prompt: 'Expiration Path(s)', default: default, required: true) end |
.get_filename(default = nil) ⇒ Object
get a package name from user
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/d3/admin/interactive.rb', line 297 def get_filename(default = nil) desc = <<-END_DESC INSTALLER FILENAME Enter a unique name for this package's installer file on the master distribution point. The file will be renamed to this name on the distribution point. Enter 'v' to see a list of existing pkg filenames in the JSS END_DESC input = 'v' while input == 'v' input = prompt_for_data(opt: :filename, desc: desc, default: default, required: true) D3::Admin::Report.show_existing_package_ids if input == 'v' end input end |
.get_groups(desc, opt, default = nil) ⇒ String?
Prompt the admin for one or more groups
701 702 703 704 705 706 707 708 |
# File 'lib/d3/admin/interactive.rb', line 701 def get_groups(desc, opt, default = nil) result = 'v' while result == 'v' result = prompt_for_data(opt: opt, desc: desc, default: default, required: true) D3.less_text JSS::ComputerGroup.all_names.sort_by(&:downcase).join("\n") if result == 'v' end result end |
.get_jss_package_for_import(default = nil) ⇒ String
Ask the user for an id or name of an existing JSS package to import into d3
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/d3/admin/interactive.rb', line 247 def get_jss_package_for_import(default = nil) desc = <<-END_DESC IMPORT JSS PACKAGE Enter a package id or display-name for an existing JSS package to import into d3. Enter: - 'v' to view a list of all JSS package names not in d3. END_DESC input = 'v' while input == 'v' input = prompt_for_data(desc: desc, prompt: 'JSS id or display name', default: default, required: true) D3::Admin::Report.show_pkgs_available_for_import if input == 'v' end input end |
.get_keep_in_jss(default = 'n') ⇒ String
when deleting a pkg, should it be kept in the JSS?
907 908 909 910 911 912 913 914 915 |
# File 'lib/d3/admin/interactive.rb', line 907 def get_keep_in_jss(default = 'n') desc = <<-END_DESC KEEP THE PACKAGE IN JAMF PRO? When deleting a package, should it be kept as a Jamf Pro package and only deleted from d3? Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Keep in JSS? (y/n)', default: default, required: true) end |
.get_keep_scripts(default = 'n') ⇒ String
when deleting a pkg, should its pre- and post- scripts be kept?
888 889 890 891 892 893 894 895 896 897 898 899 |
# File 'lib/d3/admin/interactive.rb', line 888 def get_keep_scripts(default = 'n') desc = <<-END_DESC KEEP ASSOCIATED SCRIPTS IN JAMF PRO? When deleting a package, should any associated scripts (pre-install, post-install, pre-remove, post-remove) be kept in Jamf Pro? NOTE: If any other d3 packages or policies are using the scripts they won't be deleted. The other users of the scripts will be reported. Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Delete Scripts? (y/n)', default: default, required: true) end |
.get_menu_choice(header, items) ⇒ Integer, String
Display a menu of numbered choices, and return the user’s choice, or ‘x’ if the user is done choosing.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/d3/admin/interactive.rb', line 64 def (header, items) # add a 1-based number and ) to the start of each line, like 1), and 2)... items.each_index { |i| items[i] = "#{i + 1}) #{items[i]}" } = items.count = "(1-#{}, x=done, ^c=cancel)" = "#{header}\n#{items.join("\n")}" # clear the screen between displays of the menu, so its always at the top. system 'clear' or system 'cls' puts choice = '' while choice == '' choice = Readline.readline("Which to change? #{}: ", false) break if choice == 'x' # they chose a number.. if choice =~ /^\d+$/ # map it to one of the editing options choice = choice.to_i - 1 # but they might have chosen a higher number than allowws choice = '' unless (0..( - 1)).cover? choice else choice = '' end # tell them they made a bad choice if choice == '' puts "\n******* Sorry, invalid choice.\n" next end end # while choice == "" choice end |
.get_oses(default = []) ⇒ String?
Get a list of allowed OSes for this pkg
717 718 719 720 721 722 723 724 725 |
# File 'lib/d3/admin/interactive.rb', line 717 def get_oses(default = []) desc = <<-END_DESC LIMIT TO OS's Enter a comma-separated list of OS's allowed to install this package, e.g. '10.8.5, 10.9.5, 10.10.x' Use '>=' to set a minimum OS, e.g. '>=10.8.5' END_DESC prompt_for_data(desc: desc, opt: :oses, default: default, required: true) end |
.get_package_build_type(default = D3::Admin::DFT_PKG_TYPE) ⇒ Symbol
If we’re builting a pkg, should we build a .pkg, or a .dmg?
438 439 440 441 442 443 444 445 |
# File 'lib/d3/admin/interactive.rb', line 438 def get_package_build_type(default = D3::Admin::DFT_PKG_TYPE) desc = <<-END_DESC PACKAGE BUILD TYPE Looks like we need to build the installer from a package-root. Should we build a .pkg or .dmg? ( p = pkg, d = dmg ) END_DESC prompt_for_data(opt: :package_build_type, desc: desc, default: default, required: true) end |
.get_package_name(default = nil) ⇒ Object
get a package name from user
282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/d3/admin/interactive.rb', line 282 def get_package_name(default = nil) desc = <<-END_DESC JSS PACKAGE NAME Enter a unique name for this package in d3 and Jamf Pro. Enter 'v' to view a list of package names currently in d3. END_DESC input = 'v' while input == 'v' input = prompt_for_data(opt: :package_name, desc: desc, default: default, required: true) D3::Admin::Report.show_existing_package_ids if input == 'v' end input end |
.get_pkg_identifier(default = nil) ⇒ String
Get the pkg identifier for building .pkgs
453 454 455 456 457 458 459 460 |
# File 'lib/d3/admin/interactive.rb', line 453 def get_pkg_identifier(default = nil) desc = <<-END_DESC PKG IDENTIFIER Enter the Apple .pkg indentifier for building a .pkg. E.g. com.mycompany.myapp END_DESC prompt_for_data(opt: :pkg_identifier_prefix, desc: desc, default: default, required: true) end |
.get_pkg_identifier_prefix(default = D3::Admin::DFT_PKG_ID_PREFIX) ⇒ String
Get the pkg identifier prefex for building .pkgs When building .pkgs, this string is prefixed to the basename to create the Apple Pkg identifier. For example if the value is com.pixar.d3, then when building a pkg with the basename “foo” the identifier will be com.pixar.d3.foo
This value is saved in the admin prefs for future use.
475 476 477 478 479 480 481 482 483 |
# File 'lib/d3/admin/interactive.rb', line 475 def get_pkg_identifier_prefix(default = D3::Admin::DFT_PKG_ID_PREFIX) desc = <<-END_DESC PKG IDENTIFIER PREFIX Enter the prefix to prepend to a basename to create an Apple .pkg indentifier. E.g. If you enter 'com.mycompany', then when you build a .pkg with basename 'foo' the default .pkg identifier will be 'com.mycompany.foo' END_DESC prompt_for_data(opt: :pkg_identifier_prefix, desc: desc, default: default, required: true) end |
.get_pkg_preserve_owners(default = 'n') ⇒ String
Ask if the pkg should preserve source ownership, or apply OS defaults
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
# File 'lib/d3/admin/interactive.rb', line 548 def get_pkg_preserve_owners(default = 'n') desc = <<-END_DESC PRESERVE SOURCE OWNERSHIP When building a .pkg, the OS generally sets the ownership and permissions of the payload to match OS standards, e.g. Apps owned by 'root' with group 'admin' or 'wheel' If desired you can preserve the current ownership and permissions of the source folder contents when the payload is installed. This is generally not recomended. Should we override the OS and preserve the ownership on the source folder when the item is installed on the client? Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Preserve ownership (y/n)', default: default, required: true) end |
.get_post_install_script(default = nil) ⇒ Pathname, ...
Get a post-install script, either local file, JSS id, or JSS name
583 584 585 |
# File 'lib/d3/admin/interactive.rb', line 583 def get_post_install_script(default = nil) get_script 'POST-INSTALL SCRIPT', :post_install, default end |
.get_post_remove_script(default = nil) ⇒ Pathname, ...
Get a post-remove script, either local file, JSS id, or JSS name
605 606 607 |
# File 'lib/d3/admin/interactive.rb', line 605 def get_post_remove_script(default = nil) get_script 'POST-REMOVE SCRIPT', :post_remove, default end |
.get_pre_install_script(default = nil) ⇒ Pathname, ...
Get a pre-install script, either local file, JSS id, or JSS name
572 573 574 |
# File 'lib/d3/admin/interactive.rb', line 572 def get_pre_install_script(default = nil) get_script 'PRE-INSTALL SCRIPT', :pre_install, default end |
.get_pre_remove_script(default = nil) ⇒ Pathname, ...
Get a pre-remove script, either local file, JSS id, or JSS name
594 595 596 |
# File 'lib/d3/admin/interactive.rb', line 594 def get_pre_remove_script(default = nil) get_script 'PRE-REMOVE SCRIPT', :pre_remove, default end |
.get_prohibiting_processes(default = 'n') ⇒ Regexp?
Get a pattern to match for the prohibiting processes If this matches a line of output from ‘/bin/ps -A -c -o comm` at install time, then graceful quit will be attempted. Strings must match a whole line, Regexps will work with any match.
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 |
# File 'lib/d3/admin/interactive.rb', line 776 def get_prohibiting_processes(default = 'n') desc = <<-END_DESC PROHIBITING PROCESSES Enter a comma separated string of process name(s) as they appear in the of the output of `/bin/ps -A -c -o comm`. Example: Safari, Google Chrome, cfprefsd If a process is running at install time, the installer will quit any background processes automatically, and may prompt the user to quit GUI applications gracefully. Matching is case sensitive. Enter 'n' for none. END_DESC result = prompt_for_data(desc: desc, prompt: 'Prohibiting Processes', opt: :prohibiting_processes, default: default, required: true) return nil if result == 'n' result end |
.get_reboot(default = 'n') ⇒ String
Ask if this package needs a reboot
834 835 836 837 838 839 840 841 842 843 844 |
# File 'lib/d3/admin/interactive.rb', line 834 def get_reboot(default = 'n') desc = <<-END_DESC REBOOT REQUIRED (PUPPIES!) Does this package require a reboot after installation? If so, it will be added to the Puppy Queue when installed with 'd3 install', and the user will be notified to log out as soon as possible. Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Requires reboot? (y/n)', default: default, required: true) end |
.get_removable(default = 'y') ⇒ String
Ask if this package is uninstallable
802 803 804 805 806 807 808 809 |
# File 'lib/d3/admin/interactive.rb', line 802 def get_removable(default = 'y') desc = <<-END_DESC REMOVABLE Can this package be uninstalled? Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Removable? (y/n)', default: default, required: true) end |
.get_remove_first(default = 'y') ⇒ String
Ask if we should ininstall older versions of this basename before installing this one
818 819 820 821 822 823 824 825 826 |
# File 'lib/d3/admin/interactive.rb', line 818 def get_remove_first(default = 'y') desc = <<-END_DESC UNINSTALL OLDER VERSIONS Should older versions of this basename be uninstalled (if they are removable) before attempting to install this package? Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Remove older installs first? (y/n)', default: default, required: true) end |
.get_revision(default = nil) ⇒ String
Get a revision from the user
334 335 336 337 338 339 340 341 342 343 |
# File 'lib/d3/admin/interactive.rb', line 334 def get_revision(default = nil) desc = <<-END_DESC REVISION Enter a Package revision for this package. This is an integer representing a new packaging of an existing version of a given basename. END_DESC prompt_for_data(opt: :revision, desc: desc, default: default, required: true) end |
.get_script(heading, opt, default = nil) ⇒ Pathname, ...
Get a script, either local file, JSS id, or JSS name
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 |
# File 'lib/d3/admin/interactive.rb', line 616 def get_script(heading, opt, default = nil) desc = <<-END_DESC #{heading} Enter a path to a local file containing the script or the name or id of an existing script in the JSS. Enter 'v' to view a list of scripts in the JSS. END_DESC result = 'v' while result == 'v' result = prompt_for_data(opt: opt, desc: desc, default: default, required: true) D3.less_text JSS::Script.all_names.sort_by(&:downcase).join("\n") if result == 'v' end result end |
.get_search_target(default = false) ⇒ String
Prompt the admin for text to search for package searchs
665 666 667 668 669 670 671 672 673 674 675 |
# File 'lib/d3/admin/interactive.rb', line 665 def get_search_target(default = false) desc = <<-END_PROMPT SEARCH TEXT Enter text to use in matching basenames or computer group names. Matching a basename will list all packages with the basename. Matching a group name will list all packages auto-installed or excluded for the group. (RegExp's OK) Enter 'all' to list all packages in d3. END_PROMPT prompt_for_data(desc: desc, prompt: "Text to match or 'all'").chomp end |
.get_show_type(default = D3::Admin::Report::DFT_SHOW_TYPE) ⇒ String
what kind of package list are we showing?
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 |
# File 'lib/d3/admin/interactive.rb', line 923 def get_show_type(default = D3::Admin::Report::DFT_SHOW_TYPE) desc = <<-END_DESC SERVER PACKAGE LIST Enter the type of list you'd like to generate about packages in d3. One of: all - all packages in d3 pilot - packages newer than live live - live packages deprecated - old packages that used to be live skipped - old packages that were never made live missing - packages in d3, but not Jamf Pro auto - packages auto-installed for a given computer group excluded - packages not available to a given computer group END_DESC prompt_for_data(desc: desc, prompt: 'Show packages', default: default, required: true) end |
.get_signing_identity(default = ) ⇒ String
Get the optional Apple Developer signing ID .pkgs can be codesigned with a certificate from Apple The Developer ID Installer certificate must be in the login.keychain of the user operating d3admin unless otherwise specified in signing_options
This value is saved in the admin prefs for future use.
497 498 499 500 501 502 503 504 505 |
# File 'lib/d3/admin/interactive.rb', line 497 def get_signing_identity(default = D3::Admin::Prefs.prefs[:signing_identity]) desc = <<-END_DESC SIGNING IDENTITY Enter the common name of your Apple Developer signing ID to create signed Apple .pkgs. E.g. If you enter 'Developer ID Installer: My Company (A12BC34DE56)', then that string will be passed as the option for pkgbuild --sign. D3 will not attempt to sign unless this option is set.' END_DESC prompt_for_data(opt: :signing_identity, desc: desc, default: default, required: false) end |
.get_signing_options(default = ) ⇒ String
Get any arguments and options to pass to pkgbuild A signing identity must be defined for these options to be used.
This value is saved in the admin prefs for future use.
516 517 518 519 520 521 522 523 |
# File 'lib/d3/admin/interactive.rb', line 516 def (default = D3::Admin::Prefs.prefs[:signing_options]) desc = <<-END_DESC SIGNING OPTIONS Enter optional arguments and options to pass to pkgbuild. These options are ignored unless a signing identity is defined. E.g. --keychain '/Users/d3/Library/Keychain' --cert 'My Awesome Authority' --timestamp END_DESC prompt_for_data(opt: :signing_options, desc: desc, default: default, required: false) end |
.get_source_path(default = false) ⇒ Pathname
Get the local path to the package being added to d3 Also sets @build_installer, and @build_installer_type if the source is a root-folder rather than a .pkg or .dmg
422 423 424 425 426 427 428 429 430 431 432 |
# File 'lib/d3/admin/interactive.rb', line 422 def get_source_path(default = false) desc = <<-END_DESC SOURCE Enter the path to a .pkg or .dmg installer or a 'root' folder from which to build one. END_DESC # dragging in items from the finder will esacpe spaces in the path with \'s # in the shell this is good, but ruby is interpreting the \'s, so lets remove them. prompt_for_data(opt: :source_path, desc: desc, default: default, required: true).strip.gsub(/\\ /, ' ') end |
.get_status_for_filter(with_frozen = false) ⇒ Object
get auto
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
# File 'lib/d3/admin/interactive.rb', line 677 def get_status_for_filter(with_frozen = false) if with_frozen frozen_line = "\nUse 'frozen' to limit to frozen receipts" frozen_title = 'OR FROZEN' else frozen_line = '' frozen_title = '' end desc = <<-END_PROMPT LIMIT TO STATUS#{frozen_title} Enter a comma-separate list of statuses for limiting the list. Valid Statuses are: #{D3::Basename::STATUSES_FOR_FILTERS.join(', ')}#{frozen_line} Enter 'all' to show all statuses END_PROMPT prompt_for_data(desc: desc, prompt: 'Statuses', default: 'all').chomp end |
.get_value(option_or_get_method, default = nil, validate_method = nil) ⇒ Object
Call one of the get_ methods and do the matching validity check, if desired, repeatedly until a valid value is supplied.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/d3/admin/interactive.rb', line 115 def get_value(option_or_get_method, default = nil, validate_method = nil) # if the option_or_get_method is one of the keys in OPTIONS, then use OPTIONS[get_method][:get] if it exists if D3::Admin::OPTIONS.keys.include?(option_or_get_method) get_method = D3::Admin::OPTIONS[option_or_get_method][:get] # if we weren't giving a validate method, get it from the OPTIONS validate_method ||= D3::Admin::OPTIONS[option_or_get_method][:validate] end # otherwise we should have been given a symbolic method name. get_method ||= option_or_get_method valid = :start validated = nil until valid === true # Keep the ===, trust me. Don't listen to rubocop. puts "\nSorry: #{validated}, Try again.\n" unless valid === :start value_input = self.send get_method, default # no check method? just return the value return value_input if validate_method.nil? (valid, validated) = D3::Admin::Validate.validate(value_input, validate_method) end # until valid === true validated end |
.get_version(default = nil) ⇒ String
Get a version from the user
318 319 320 321 322 323 324 325 326 |
# File 'lib/d3/admin/interactive.rb', line 318 def get_version(default = nil) desc = <<-END_DESC VERSION Enter a version for this package. All spaces will be converted to underscores. END_DESC prompt_for_data(opt: :version, desc: desc, default: default, required: true) end |
.get_workspace(default = ) ⇒ Pathname
Get the desired local workspace for building pkgs Defaults to ENV
532 533 534 535 536 537 538 539 |
# File 'lib/d3/admin/interactive.rb', line 532 def get_workspace(default = ENV['HOME']) desc = <<-END_DESC PACKAGE BUILD WORKSPACE Enter the path to a folder where we can build packages. This will be stored between uses of d3admin. END_DESC Pathname.new prompt_for_data(opt: :workspace, desc: desc, default: default, required: true) end |
.prompt_for_data(desc: nil, prompt: nil, opt: nil, default: :no_default, required: true) ⇒ String
Prompt for user input for an option and return the response.
A Description of the option is displayed, followed by a prompt. If a default value is provided, the prompt includes the text
(Hit return for #{default_value})
If the option is defined in D3::Admin::OPTIONS, the data for the option is used, if not provided in the args.
If the option is defined as unsettable, a line “Enter ‘n’ for none.” is also displayed before the prompt and a value of ‘n’ will cause the method to return nil.
If no prompt is given in the args, the :label is used from D3::Admin::OPTIONS
If no default value is given in the args, the one from D3::Admin::OPTIONS is used. If required is true, the input can’t be an empty string.
Note: watch out for nil vs false in default values
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/d3/admin/interactive.rb', line 179 def prompt_for_data(desc: nil, prompt: nil, opt: nil, default: :no_default, required: true) unset_line = nil default_display = default # look up some info about this option, if needed if opt opt_def = D3::Admin::OPTIONS[opt] if opt_def prompt ||= opt_def[:label] unset_line = "Enter '#{UNSET}' for none." if opt_def[:unsetable] default = opt_def[:default] if opt_def[:default] and default == :no_default default_display = opt_def[:display_conversion].call(default) if opt_def[:display_conversion] end end # if args[:opt] # some values are special for displaying default_display = case default_display when :no_default then '' when D3::Admin::DFT_REQUIRED then '' # the '---Required---' should only be visible in the menu, not the prompt when D3::Admin::DFT_NONE then UNSET else default_display.to_s end data_entered = '' puts "\n#{desc}" if desc prompt ||= 'Please enter a value' hit_return = default_display.empty? ? '' : " (Hit return for '#{default_display}' )" prompt_line = "#{prompt}#{hit_return}: " while true do data_entered = Readline.readline(prompt_line, false) data_entered = default_display if data_entered == '' break unless required && data_entered.empty? end # if 'n' was typed for an unsettable option, return nil return nil if opt_def && opt_def[:unsetable] && data_entered == UNSET data_entered.strip end |
Instance Method Details
#get_auto_groups(default = nil) ⇒ String
Prompt the admin for one or more auto-groups for this installer
637 638 639 640 641 642 643 644 645 646 |
# File 'lib/d3/admin/interactive.rb', line 637 def get_auto_groups(default = nil) desc = <<-END_DESC AUTO-INSTALL GROUPS Enter a comma-separated list of JSS Computer Group names whose members should have this package installed automatically when it is made live. Enter 'v' to view a list of computer groups. Enter '#{D3::STANDARD_AUTO_GROUP}' to install on all machines. END_DESC get_groups desc, :auto_groups, default end |
#get_basename(default = nil) ⇒ Object
get a basename from the user
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/d3/admin/interactive.rb', line 265 def get_basename(default = nil) desc = <<-END_DESC BASENAME Enter a basename. Enter 'v' to view a list of all basenames in d3 and the newest edition for each. END_DESC input = 'v' while input == 'v' input = prompt_for_data(desc: desc, prompt: 'Basename', required: true) D3::Admin::Report.show_all_basenames_and_editions if input == 'v' end input end |
#get_category(default = 'n') ⇒ String
Get a JSS Category from the user
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
# File 'lib/d3/admin/interactive.rb', line 748 def get_category(default = 'n') desc = <<-END_DESC CATEGORY Enter the JSS category name for this package. Enter: - 'v' to view all JSS categories - 'n' for no category END_DESC result = 'v' while result == 'v' result = prompt_for_data(desc: desc, prompt: 'Category', default: default, required: true) D3.less_text JSS::Category.all_names.sort_by(&:downcase).join("\n") if result == 'v' end return nil if result == 'n' result end |
#get_computer(default = nil) ⇒ String
What computer are we generating a receipt report for?
945 946 947 948 949 950 951 952 953 954 955 956 957 |
# File 'lib/d3/admin/interactive.rb', line 945 def get_computer(default = nil) desc = <<-END_DESC COMPUTER NAME Enter the name of a computer Jamf Pro. Enter 'v' to view a list available computer names. END_DESC input = 'v' while input == 'v' input = prompt_for_data(desc: desc, prompt: 'Computer name', default: nil, required: true) D3::Admin::Report.show_available_computers_for_reports if input == 'v' end input end |
#get_config_target(default = 'all') ⇒ String
Get the config target
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 |
# File 'lib/d3/admin/interactive.rb', line 965 def get_config_target(default = 'all') desc = <<-END_DESC CONFIGURATION Which setting would you like to configure? jss - the JSS and credentials (stored in your keychain) db - the MySQL server and credentials (stored in your keychain) dist - the master distribution point RW password (stored in your keychain) workspace - the folder in which to build .pkgs and .dmgs editor - the shell command for editing package descriptions pkg-id-prefix - the prefix for the .pkg identifier when building .pkgs signing-identity - optional Developer ID Installer certificate issued by Apple signing-options - optional string of signing options to pass to pkgbuild. all - all of the above display - show current configuration END_DESC prompt_for_data(opt: :pkg_identifier_prefix, desc: desc, default: default, required: true) end |
#get_cpu_type(default = 'x86') ⇒ Symbol?
Get a the CPU-type limitation for this package
733 734 735 736 737 738 739 740 |
# File 'lib/d3/admin/interactive.rb', line 733 def get_cpu_type(default = 'x86') desc = <<-END_DESC LIMIT TO CPU TYPE Should this packge be limited to certain CPU types? Enter 'ppc' or 'x86' or 'none' for neither. END_DESC prompt_for_data(desc: desc, opt: :cpu_type, default: default, required: true) end |
#get_description(current_desc = '') ⇒ String
Get a multiline description from the user using the editor of their choice: nano, vi, emacs, or ENV
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
# File 'lib/d3/admin/interactive.rb', line 352 def get_description(current_desc = '') # do we have a current desc to display and possibly keep? current_desc_review = '' unless current_desc.to_s.empty? current_desc_review = "\n----- Current Description -----\n#{current_desc}\n-------------------------------\n\n" end if prefd_editor = D3::Admin::Prefs.prefs[:editor] prefd_editor_choice = "\n - 'e' to edit using '#{prefd_editor}' " else prefd_editor_choice = '' end # the blurb to show the user input_desc = <<-END_DESC DESCRIPTION Create a multi-line description of this package: - what does the installed thing do? - where did it come from, where to get updates? - who maintains it in your environment? - any other info useful to d3 and Jamf Pro admins. (don't just say "installs foo" when "foo" is the basename) #{current_desc_review}Enter:#{prefd_editor_choice} - 'n' to edit using 'nano' - 'v' to edit using 'vi' or 'vim' - 'm' to edit using 'emacs' - 'b' to have a blank description Anything else will edit with the EDITOR for your environment or '#{DFT_EDITOR}' if none is set. END_DESC # show it, get response puts input_desc choice = Readline.readline('Your choice (hit return to keep current desc.): ', false) # keep or empty? return current_desc if choice.empty? return '' if choice.casecmp('b').zero? # make a tem file, save current into it desc_tmp_file = Pathname.new Tempfile.new('d3_description_') desc_tmp_file.jss_save current_desc # which editor? if choice.casecmp('e').zero? cmd = prefd_editor elsif choice.casecmp('v').zero? cmd = '/usr/bin/vim' elsif choice.casecmp('m').zero? cmd = '/usr/bin/emacs' elsif choice.casecmp('n').zero? cmd = '/usr/bin/nano -L' else cmd = ENV['EDITOR'] end cmd ||= DFT_EDITOR system "#{cmd} '#{desc_tmp_file}'" result = desc_tmp_file.read.chomp desc_tmp_file.delete result.chomp end |
#get_editor(default = '/usr/bin/nano') ⇒ String
get the shell command for editing package descriptions
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 |
# File 'lib/d3/admin/interactive.rb', line 990 def get_editor(default = '/usr/bin/nano') desc = <<-END_DESC EDITOR Enter the shell command to use during --walkthru for editing package descriptions e.g. /usr/bin/vim, /usr/bin/emacs Note: if the command launches a GUI editor, make sure the shell command stays running until the document is closed. Most such editors have an option for that. END_DESC prompt_for_data(desc: desc, default: default, prompt: 'Command', required: true) end |
#get_excluded_groups(default = nil) ⇒ Object
Prompt the admin for one or more auto-groups for this installer
651 652 653 654 655 656 657 658 659 |
# File 'lib/d3/admin/interactive.rb', line 651 def get_excluded_groups(default = nil) desc = <<-END_PROMPT EXCLUDED GROUPS Enter a comma-separated list of JSS Computer Group names whose members should not get this installed without force. Enter 'v' to view list of computer groups. END_PROMPT get_groups desc, :excluded_groups, default end |
#get_existing_package(default = nil) ⇒ String?
Ask the user for an edition or basename of an existing package.
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/d3/admin/interactive.rb', line 225 def get_existing_package(default = nil) desc = <<-END_DESC EXISTING PACKAGE Enter a package edition or basename for an existing d3 package. If a basename, the currently live package for that basename will be used. Enter: - 'v' to view a list of all packages with the basenames and editions in d3. END_DESC input = 'v' while input == 'v' input = prompt_for_data(desc: desc, prompt: 'Edition or Basename', default: default, required: true) D3::Admin::Report.show_all_basenames_and_editions if input == 'v' end input end |
#get_expiration(default = 0) ⇒ Integer
Get an expiration period (# of days) from the user
852 853 854 855 856 857 858 859 860 861 862 |
# File 'lib/d3/admin/interactive.rb', line 852 def get_expiration(default = 0) desc = <<-END_DESC EXPIRATION On machines that allow package expiration, should this package be removed after some number of days without being used? Enter the number of days, or 0 for no expiration. END_DESC prompt_for_data(desc: desc, prompt: 'Expiration days', default: default, required: true) end |
#get_expiration_paths(default = 'n') ⇒ Array<Pathname>
Get the path to the executable(s) to monitor for expiration
870 871 872 873 874 875 876 877 878 879 880 |
# File 'lib/d3/admin/interactive.rb', line 870 def get_expiration_paths(default = 'n') desc = <<-END_DESC EXPIRATION PATH(S) Enter the path(s) to the executable(s) that must be used to prevent expiration. Multiple paths should be separated by commas, spaces should not be escaped. E.g. /Applications/Google Chrome.app/Contents/MacOS/Google Chrome, /Applications/Firefox.app/Contents/MacOS/firefox Enter 'n' for none END_DESC prompt_for_data(desc: desc, prompt: 'Expiration Path(s)', default: default, required: true) end |
#get_filename(default = nil) ⇒ Object
get a package name from user
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/d3/admin/interactive.rb', line 297 def get_filename(default = nil) desc = <<-END_DESC INSTALLER FILENAME Enter a unique name for this package's installer file on the master distribution point. The file will be renamed to this name on the distribution point. Enter 'v' to see a list of existing pkg filenames in the JSS END_DESC input = 'v' while input == 'v' input = prompt_for_data(opt: :filename, desc: desc, default: default, required: true) D3::Admin::Report.show_existing_package_ids if input == 'v' end input end |
#get_groups(desc, opt, default = nil) ⇒ String?
Prompt the admin for one or more groups
701 702 703 704 705 706 707 708 |
# File 'lib/d3/admin/interactive.rb', line 701 def get_groups(desc, opt, default = nil) result = 'v' while result == 'v' result = prompt_for_data(opt: opt, desc: desc, default: default, required: true) D3.less_text JSS::ComputerGroup.all_names.sort_by(&:downcase).join("\n") if result == 'v' end result end |
#get_jss_package_for_import(default = nil) ⇒ String
Ask the user for an id or name of an existing JSS package to import into d3
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/d3/admin/interactive.rb', line 247 def get_jss_package_for_import(default = nil) desc = <<-END_DESC IMPORT JSS PACKAGE Enter a package id or display-name for an existing JSS package to import into d3. Enter: - 'v' to view a list of all JSS package names not in d3. END_DESC input = 'v' while input == 'v' input = prompt_for_data(desc: desc, prompt: 'JSS id or display name', default: default, required: true) D3::Admin::Report.show_pkgs_available_for_import if input == 'v' end input end |
#get_keep_in_jss(default = 'n') ⇒ String
when deleting a pkg, should it be kept in the JSS?
907 908 909 910 911 912 913 914 915 |
# File 'lib/d3/admin/interactive.rb', line 907 def get_keep_in_jss(default = 'n') desc = <<-END_DESC KEEP THE PACKAGE IN JAMF PRO? When deleting a package, should it be kept as a Jamf Pro package and only deleted from d3? Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Keep in JSS? (y/n)', default: default, required: true) end |
#get_keep_scripts(default = 'n') ⇒ String
when deleting a pkg, should its pre- and post- scripts be kept?
888 889 890 891 892 893 894 895 896 897 898 899 |
# File 'lib/d3/admin/interactive.rb', line 888 def get_keep_scripts(default = 'n') desc = <<-END_DESC KEEP ASSOCIATED SCRIPTS IN JAMF PRO? When deleting a package, should any associated scripts (pre-install, post-install, pre-remove, post-remove) be kept in Jamf Pro? NOTE: If any other d3 packages or policies are using the scripts they won't be deleted. The other users of the scripts will be reported. Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Delete Scripts? (y/n)', default: default, required: true) end |
#get_menu_choice(header, items) ⇒ Integer, String
Display a menu of numbered choices, and return the user’s choice, or ‘x’ if the user is done choosing.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/d3/admin/interactive.rb', line 64 def (header, items) # add a 1-based number and ) to the start of each line, like 1), and 2)... items.each_index { |i| items[i] = "#{i + 1}) #{items[i]}" } = items.count = "(1-#{}, x=done, ^c=cancel)" = "#{header}\n#{items.join("\n")}" # clear the screen between displays of the menu, so its always at the top. system 'clear' or system 'cls' puts choice = '' while choice == '' choice = Readline.readline("Which to change? #{}: ", false) break if choice == 'x' # they chose a number.. if choice =~ /^\d+$/ # map it to one of the editing options choice = choice.to_i - 1 # but they might have chosen a higher number than allowws choice = '' unless (0..( - 1)).cover? choice else choice = '' end # tell them they made a bad choice if choice == '' puts "\n******* Sorry, invalid choice.\n" next end end # while choice == "" choice end |
#get_oses(default = []) ⇒ String?
Get a list of allowed OSes for this pkg
717 718 719 720 721 722 723 724 725 |
# File 'lib/d3/admin/interactive.rb', line 717 def get_oses(default = []) desc = <<-END_DESC LIMIT TO OS's Enter a comma-separated list of OS's allowed to install this package, e.g. '10.8.5, 10.9.5, 10.10.x' Use '>=' to set a minimum OS, e.g. '>=10.8.5' END_DESC prompt_for_data(desc: desc, opt: :oses, default: default, required: true) end |
#get_package_build_type(default = D3::Admin::DFT_PKG_TYPE) ⇒ Symbol
If we’re builting a pkg, should we build a .pkg, or a .dmg?
438 439 440 441 442 443 444 445 |
# File 'lib/d3/admin/interactive.rb', line 438 def get_package_build_type(default = D3::Admin::DFT_PKG_TYPE) desc = <<-END_DESC PACKAGE BUILD TYPE Looks like we need to build the installer from a package-root. Should we build a .pkg or .dmg? ( p = pkg, d = dmg ) END_DESC prompt_for_data(opt: :package_build_type, desc: desc, default: default, required: true) end |
#get_package_name(default = nil) ⇒ Object
get a package name from user
282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/d3/admin/interactive.rb', line 282 def get_package_name(default = nil) desc = <<-END_DESC JSS PACKAGE NAME Enter a unique name for this package in d3 and Jamf Pro. Enter 'v' to view a list of package names currently in d3. END_DESC input = 'v' while input == 'v' input = prompt_for_data(opt: :package_name, desc: desc, default: default, required: true) D3::Admin::Report.show_existing_package_ids if input == 'v' end input end |
#get_pkg_identifier(default = nil) ⇒ String
Get the pkg identifier for building .pkgs
453 454 455 456 457 458 459 460 |
# File 'lib/d3/admin/interactive.rb', line 453 def get_pkg_identifier(default = nil) desc = <<-END_DESC PKG IDENTIFIER Enter the Apple .pkg indentifier for building a .pkg. E.g. com.mycompany.myapp END_DESC prompt_for_data(opt: :pkg_identifier_prefix, desc: desc, default: default, required: true) end |
#get_pkg_identifier_prefix(default = D3::Admin::DFT_PKG_ID_PREFIX) ⇒ String
Get the pkg identifier prefex for building .pkgs When building .pkgs, this string is prefixed to the basename to create the Apple Pkg identifier. For example if the value is com.pixar.d3, then when building a pkg with the basename “foo” the identifier will be com.pixar.d3.foo
This value is saved in the admin prefs for future use.
475 476 477 478 479 480 481 482 483 |
# File 'lib/d3/admin/interactive.rb', line 475 def get_pkg_identifier_prefix(default = D3::Admin::DFT_PKG_ID_PREFIX) desc = <<-END_DESC PKG IDENTIFIER PREFIX Enter the prefix to prepend to a basename to create an Apple .pkg indentifier. E.g. If you enter 'com.mycompany', then when you build a .pkg with basename 'foo' the default .pkg identifier will be 'com.mycompany.foo' END_DESC prompt_for_data(opt: :pkg_identifier_prefix, desc: desc, default: default, required: true) end |
#get_pkg_preserve_owners(default = 'n') ⇒ String
Ask if the pkg should preserve source ownership, or apply OS defaults
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
# File 'lib/d3/admin/interactive.rb', line 548 def get_pkg_preserve_owners(default = 'n') desc = <<-END_DESC PRESERVE SOURCE OWNERSHIP When building a .pkg, the OS generally sets the ownership and permissions of the payload to match OS standards, e.g. Apps owned by 'root' with group 'admin' or 'wheel' If desired you can preserve the current ownership and permissions of the source folder contents when the payload is installed. This is generally not recomended. Should we override the OS and preserve the ownership on the source folder when the item is installed on the client? Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Preserve ownership (y/n)', default: default, required: true) end |
#get_post_install_script(default = nil) ⇒ Pathname, ...
Get a post-install script, either local file, JSS id, or JSS name
583 584 585 |
# File 'lib/d3/admin/interactive.rb', line 583 def get_post_install_script(default = nil) get_script 'POST-INSTALL SCRIPT', :post_install, default end |
#get_post_remove_script(default = nil) ⇒ Pathname, ...
Get a post-remove script, either local file, JSS id, or JSS name
605 606 607 |
# File 'lib/d3/admin/interactive.rb', line 605 def get_post_remove_script(default = nil) get_script 'POST-REMOVE SCRIPT', :post_remove, default end |
#get_pre_install_script(default = nil) ⇒ Pathname, ...
Get a pre-install script, either local file, JSS id, or JSS name
572 573 574 |
# File 'lib/d3/admin/interactive.rb', line 572 def get_pre_install_script(default = nil) get_script 'PRE-INSTALL SCRIPT', :pre_install, default end |
#get_pre_remove_script(default = nil) ⇒ Pathname, ...
Get a pre-remove script, either local file, JSS id, or JSS name
594 595 596 |
# File 'lib/d3/admin/interactive.rb', line 594 def get_pre_remove_script(default = nil) get_script 'PRE-REMOVE SCRIPT', :pre_remove, default end |
#get_prohibiting_processes(default = 'n') ⇒ Regexp?
Get a pattern to match for the prohibiting processes If this matches a line of output from ‘/bin/ps -A -c -o comm` at install time, then graceful quit will be attempted. Strings must match a whole line, Regexps will work with any match.
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 |
# File 'lib/d3/admin/interactive.rb', line 776 def get_prohibiting_processes(default = 'n') desc = <<-END_DESC PROHIBITING PROCESSES Enter a comma separated string of process name(s) as they appear in the of the output of `/bin/ps -A -c -o comm`. Example: Safari, Google Chrome, cfprefsd If a process is running at install time, the installer will quit any background processes automatically, and may prompt the user to quit GUI applications gracefully. Matching is case sensitive. Enter 'n' for none. END_DESC result = prompt_for_data(desc: desc, prompt: 'Prohibiting Processes', opt: :prohibiting_processes, default: default, required: true) return nil if result == 'n' result end |
#get_reboot(default = 'n') ⇒ String
Ask if this package needs a reboot
834 835 836 837 838 839 840 841 842 843 844 |
# File 'lib/d3/admin/interactive.rb', line 834 def get_reboot(default = 'n') desc = <<-END_DESC REBOOT REQUIRED (PUPPIES!) Does this package require a reboot after installation? If so, it will be added to the Puppy Queue when installed with 'd3 install', and the user will be notified to log out as soon as possible. Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Requires reboot? (y/n)', default: default, required: true) end |
#get_removable(default = 'y') ⇒ String
Ask if this package is uninstallable
802 803 804 805 806 807 808 809 |
# File 'lib/d3/admin/interactive.rb', line 802 def get_removable(default = 'y') desc = <<-END_DESC REMOVABLE Can this package be uninstalled? Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Removable? (y/n)', default: default, required: true) end |
#get_remove_first(default = 'y') ⇒ String
Ask if we should ininstall older versions of this basename before installing this one
818 819 820 821 822 823 824 825 826 |
# File 'lib/d3/admin/interactive.rb', line 818 def get_remove_first(default = 'y') desc = <<-END_DESC UNINSTALL OLDER VERSIONS Should older versions of this basename be uninstalled (if they are removable) before attempting to install this package? Enter 'y' or 'n' END_DESC prompt_for_data(desc: desc, prompt: 'Remove older installs first? (y/n)', default: default, required: true) end |
#get_revision(default = nil) ⇒ String
Get a revision from the user
334 335 336 337 338 339 340 341 342 343 |
# File 'lib/d3/admin/interactive.rb', line 334 def get_revision(default = nil) desc = <<-END_DESC REVISION Enter a Package revision for this package. This is an integer representing a new packaging of an existing version of a given basename. END_DESC prompt_for_data(opt: :revision, desc: desc, default: default, required: true) end |
#get_script(heading, opt, default = nil) ⇒ Pathname, ...
Get a script, either local file, JSS id, or JSS name
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 |
# File 'lib/d3/admin/interactive.rb', line 616 def get_script(heading, opt, default = nil) desc = <<-END_DESC #{heading} Enter a path to a local file containing the script or the name or id of an existing script in the JSS. Enter 'v' to view a list of scripts in the JSS. END_DESC result = 'v' while result == 'v' result = prompt_for_data(opt: opt, desc: desc, default: default, required: true) D3.less_text JSS::Script.all_names.sort_by(&:downcase).join("\n") if result == 'v' end result end |
#get_search_target(default = false) ⇒ String
Prompt the admin for text to search for package searchs
665 666 667 668 669 670 671 672 673 674 675 |
# File 'lib/d3/admin/interactive.rb', line 665 def get_search_target(default = false) desc = <<-END_PROMPT SEARCH TEXT Enter text to use in matching basenames or computer group names. Matching a basename will list all packages with the basename. Matching a group name will list all packages auto-installed or excluded for the group. (RegExp's OK) Enter 'all' to list all packages in d3. END_PROMPT prompt_for_data(desc: desc, prompt: "Text to match or 'all'").chomp end |
#get_show_type(default = D3::Admin::Report::DFT_SHOW_TYPE) ⇒ String
what kind of package list are we showing?
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 |
# File 'lib/d3/admin/interactive.rb', line 923 def get_show_type(default = D3::Admin::Report::DFT_SHOW_TYPE) desc = <<-END_DESC SERVER PACKAGE LIST Enter the type of list you'd like to generate about packages in d3. One of: all - all packages in d3 pilot - packages newer than live live - live packages deprecated - old packages that used to be live skipped - old packages that were never made live missing - packages in d3, but not Jamf Pro auto - packages auto-installed for a given computer group excluded - packages not available to a given computer group END_DESC prompt_for_data(desc: desc, prompt: 'Show packages', default: default, required: true) end |
#get_signing_identity(default = ) ⇒ String
Get the optional Apple Developer signing ID .pkgs can be codesigned with a certificate from Apple The Developer ID Installer certificate must be in the login.keychain of the user operating d3admin unless otherwise specified in signing_options
This value is saved in the admin prefs for future use.
497 498 499 500 501 502 503 504 505 |
# File 'lib/d3/admin/interactive.rb', line 497 def get_signing_identity(default = D3::Admin::Prefs.prefs[:signing_identity]) desc = <<-END_DESC SIGNING IDENTITY Enter the common name of your Apple Developer signing ID to create signed Apple .pkgs. E.g. If you enter 'Developer ID Installer: My Company (A12BC34DE56)', then that string will be passed as the option for pkgbuild --sign. D3 will not attempt to sign unless this option is set.' END_DESC prompt_for_data(opt: :signing_identity, desc: desc, default: default, required: false) end |
#get_signing_options(default = ) ⇒ String
Get any arguments and options to pass to pkgbuild A signing identity must be defined for these options to be used.
This value is saved in the admin prefs for future use.
516 517 518 519 520 521 522 523 |
# File 'lib/d3/admin/interactive.rb', line 516 def (default = D3::Admin::Prefs.prefs[:signing_options]) desc = <<-END_DESC SIGNING OPTIONS Enter optional arguments and options to pass to pkgbuild. These options are ignored unless a signing identity is defined. E.g. --keychain '/Users/d3/Library/Keychain' --cert 'My Awesome Authority' --timestamp END_DESC prompt_for_data(opt: :signing_options, desc: desc, default: default, required: false) end |
#get_source_path(default = false) ⇒ Pathname
Get the local path to the package being added to d3 Also sets @build_installer, and @build_installer_type if the source is a root-folder rather than a .pkg or .dmg
422 423 424 425 426 427 428 429 430 431 432 |
# File 'lib/d3/admin/interactive.rb', line 422 def get_source_path(default = false) desc = <<-END_DESC SOURCE Enter the path to a .pkg or .dmg installer or a 'root' folder from which to build one. END_DESC # dragging in items from the finder will esacpe spaces in the path with \'s # in the shell this is good, but ruby is interpreting the \'s, so lets remove them. prompt_for_data(opt: :source_path, desc: desc, default: default, required: true).strip.gsub(/\\ /, ' ') end |
#get_status_for_filter(with_frozen = false) ⇒ Object
get auto
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
# File 'lib/d3/admin/interactive.rb', line 677 def get_status_for_filter(with_frozen = false) if with_frozen frozen_line = "\nUse 'frozen' to limit to frozen receipts" frozen_title = 'OR FROZEN' else frozen_line = '' frozen_title = '' end desc = <<-END_PROMPT LIMIT TO STATUS#{frozen_title} Enter a comma-separate list of statuses for limiting the list. Valid Statuses are: #{D3::Basename::STATUSES_FOR_FILTERS.join(', ')}#{frozen_line} Enter 'all' to show all statuses END_PROMPT prompt_for_data(desc: desc, prompt: 'Statuses', default: 'all').chomp end |
#get_value(option_or_get_method, default = nil, validate_method = nil) ⇒ Object
Call one of the get_ methods and do the matching validity check, if desired, repeatedly until a valid value is supplied.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/d3/admin/interactive.rb', line 115 def get_value(option_or_get_method, default = nil, validate_method = nil) # if the option_or_get_method is one of the keys in OPTIONS, then use OPTIONS[get_method][:get] if it exists if D3::Admin::OPTIONS.keys.include?(option_or_get_method) get_method = D3::Admin::OPTIONS[option_or_get_method][:get] # if we weren't giving a validate method, get it from the OPTIONS validate_method ||= D3::Admin::OPTIONS[option_or_get_method][:validate] end # otherwise we should have been given a symbolic method name. get_method ||= option_or_get_method valid = :start validated = nil until valid === true # Keep the ===, trust me. Don't listen to rubocop. puts "\nSorry: #{validated}, Try again.\n" unless valid === :start value_input = self.send get_method, default # no check method? just return the value return value_input if validate_method.nil? (valid, validated) = D3::Admin::Validate.validate(value_input, validate_method) end # until valid === true validated end |
#get_version(default = nil) ⇒ String
Get a version from the user
318 319 320 321 322 323 324 325 326 |
# File 'lib/d3/admin/interactive.rb', line 318 def get_version(default = nil) desc = <<-END_DESC VERSION Enter a version for this package. All spaces will be converted to underscores. END_DESC prompt_for_data(opt: :version, desc: desc, default: default, required: true) end |
#get_workspace(default = ) ⇒ Pathname
Get the desired local workspace for building pkgs Defaults to ENV
532 533 534 535 536 537 538 539 |
# File 'lib/d3/admin/interactive.rb', line 532 def get_workspace(default = ENV['HOME']) desc = <<-END_DESC PACKAGE BUILD WORKSPACE Enter the path to a folder where we can build packages. This will be stored between uses of d3admin. END_DESC Pathname.new prompt_for_data(opt: :workspace, desc: desc, default: default, required: true) end |
#prompt_for_data(desc: nil, prompt: nil, opt: nil, default: :no_default, required: true) ⇒ String
Prompt for user input for an option and return the response.
A Description of the option is displayed, followed by a prompt. If a default value is provided, the prompt includes the text
(Hit return for #{default_value})
If the option is defined in D3::Admin::OPTIONS, the data for the option is used, if not provided in the args.
If the option is defined as unsettable, a line “Enter ‘n’ for none.” is also displayed before the prompt and a value of ‘n’ will cause the method to return nil.
If no prompt is given in the args, the :label is used from D3::Admin::OPTIONS
If no default value is given in the args, the one from D3::Admin::OPTIONS is used. If required is true, the input can’t be an empty string.
Note: watch out for nil vs false in default values
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/d3/admin/interactive.rb', line 179 def prompt_for_data(desc: nil, prompt: nil, opt: nil, default: :no_default, required: true) unset_line = nil default_display = default # look up some info about this option, if needed if opt opt_def = D3::Admin::OPTIONS[opt] if opt_def prompt ||= opt_def[:label] unset_line = "Enter '#{UNSET}' for none." if opt_def[:unsetable] default = opt_def[:default] if opt_def[:default] and default == :no_default default_display = opt_def[:display_conversion].call(default) if opt_def[:display_conversion] end end # if args[:opt] # some values are special for displaying default_display = case default_display when :no_default then '' when D3::Admin::DFT_REQUIRED then '' # the '---Required---' should only be visible in the menu, not the prompt when D3::Admin::DFT_NONE then UNSET else default_display.to_s end data_entered = '' puts "\n#{desc}" if desc prompt ||= 'Please enter a value' hit_return = default_display.empty? ? '' : " (Hit return for '#{default_display}' )" prompt_line = "#{prompt}#{hit_return}: " while true do data_entered = Readline.readline(prompt_line, false) data_entered = default_display if data_entered == '' break unless required && data_entered.empty? end # if 'n' was typed for an unsettable option, return nil return nil if opt_def && opt_def[:unsetable] && data_entered == UNSET data_entered.strip end |