### Copyright 2016 Pixar ### ### Licensed under the Apache License, Version 2.0 (the "Apache License") ### with the following modification; you may not use this file except in ### compliance with the Apache License and the following modification to it: ### Section 6. Trademarks. is deleted and replaced with: ### ### 6. Trademarks. This License does not grant permission to use the trade ### names, trademarks, service marks, or product names of the Licensor ### and its affiliates, except as required to comply with Section 4(c) of ### the License and to reproduce the content of the NOTICE file. ### ### You may obtain a copy of the Apache License at ### ### http://www.apache.org/licenses/LICENSE-2.0 ### ### Unless required by applicable law or agreed to in writing, software ### distributed under the Apache License with the above modification is ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ### KIND, either express or implied. See the Apache License for the specific ### language governing permissions and limitations under the Apache License. ### ### ### module D3 module Admin module Edit extend self ### These are all the options that can be edited for an existing d3 package. # This also defines the order they're presented when editing via walkthru. # # This is defined as an array, separate from the keys of PKG_ATTRIBUTE_CONFIG # EDITING_OPTIONS = %w{ version revision package_name filename category oses cpu_type reboot removable remove_first prohibiting_process auto_groups excluded_groups pre_install post_install pre_remove post_remove expiration expiration_paths description }.map{|i| i.to_sym} ### This is how nils and empty strings are displayed to the user NONE = "none" ### Continuously loop through displaying the editing menu, and getting ### new values, until the user types 'x'. ### ### @param pkg[D3::Package] the package being edited ### ### @return [Hash] A hash of changes to make to the pkg. Keys are the option ### symbols from EDITING_OPTIONS, values are new values ### def loop_thru_editing_walkthru (pkg) editing_walkthru_state = initial_editing_walkthru_state(pkg) walkthru_menu_header = <<-ENDMENU ------------------------------------ Editing #{pkg.status} d3 package '#{pkg.edition}' JSS Package id: #{pkg.id} JSS Package name: #{pkg.package_name} Installer filename: #{pkg.filename} ------------------------------------ Current Settings => New Settings ENDMENU choice = nil # loop until the user types an x while choice != "x" choice = D3::Admin::Interactive.get_menu_choice( walkthru_menu_header, walkthru_menu_lines(editing_walkthru_state) ) break if choice == 'x' # the number they chose becomes an option key like :reboot chosen_opt = EDITING_OPTIONS[choice] # Here's the definition of the option from the OPTIONS hash opt_def = D3::Admin::OPTIONS[chosen_opt] # Here the value we're actually editing orig_opt_value = editing_walkthru_state[chosen_opt][:original_value] orig_opt_value ||= opt_def[:default] # prompt for a new value and put it in place editing_walkthru_state[chosen_opt][:new_value] = D3::Admin::Interactive.get_value( chosen_opt, orig_opt_value ) end # while choice != x # extract just the changes to make changes_to_make = {} editing_walkthru_state.each do |opt, data| comparer = D3::Admin::OPTIONS[opt][:compare] if comparer next if (comparer.call data[:original_value], data[:new_value]) else next if (data[:original_value].to_s == data[:new_value].to_s) end changes_to_make[opt] = data[:new_value] end # editing_walkthru_state.each do |opt, data| return changes_to_make end ### A hash of hashes holding the state of the various options ### of a pkg that can be edited during a walkthru. ### ### For each editable option it holds: ### - the original value of the option from the pkg ### - the textual-display version of that value, as created by the matching ### :display_conversion proc in D3::Admin::EDITING_OPTION_INFO ### - The the new value when the user makes a change. ### ### @param pkg[D3::Package] the pkg being edited ### ### @return [Hash] the walkthru-editing values for the pkg ### def initial_editing_walkthru_state (pkg) editing_walkthru_state = {} EDITING_OPTIONS.each do |o| original_value = pkg.send(o) converter = D3::Admin::OPTIONS[o][:display_conversion] editing_walkthru_state[o] = { :original_value => original_value, :original_value_display => converter ? converter.call(original_value) : original_value, :new_value => original_value } # end hash # set orig value displays that are empty to 'none' editing_walkthru_state[o][:original_value_display] = NONE if editing_walkthru_state[o][:original_value_display].to_s.empty? end # EDITING_OPTIONS.each do |o| return editing_walkthru_state end ### Regenerate the walkthru menu lines ### ### @param editing_walkthru_state[Hash] the current state of the values being edited ### ### @return [Array] the lines of the walkthru menu ### def walkthru_menu_lines (editing_walkthru_state) display_lines = [] EDITING_OPTIONS.each do |opt| # opt is the option symbol, like :reboot opt_def = D3::Admin::OPTIONS[opt] label = opt_def[:label] converter = opt_def[:display_conversion] # did the thing change? # compare the old and new either with .to_s and == # or with the :compare proc defined in EDITING_OPTION_INFO if opt_def[:compare] option_didnt_change = (opt_def[:compare].call editing_walkthru_state[opt][:original_value], editing_walkthru_state[opt][:new_value]) else option_didnt_change = (editing_walkthru_state[opt][:original_value].to_s == editing_walkthru_state[opt][:new_value].to_s) end # no change, so just display the orig value if option_didnt_change val_to_display = editing_walkthru_state[opt][:original_value_display] # But if the new val is different, convert it if needed, then show it as "orig => new" else new_value_display = converter ? converter.call(editing_walkthru_state[opt][:new_value]) : editing_walkthru_state[opt][:new_value] new_value_display = NONE if new_value_display.to_s.empty? val_to_display = "#{editing_walkthru_state[opt][:original_value_display]} => #{new_value_display}" end # make the line and add it to the array of lines display_lines << "#{label}: #{val_to_display}" end return display_lines end # def update_editing_display_lines(editing_options) ### Validate the desired edits from the CLI options ### ### @param cli_options[OpenStruct] the options from the CLI ### ### @return [Hash] A hash of changes to make to the pkg. Keys are the option ### symbols from EDITING_OPTIONS, values are new values ### def validate_cli_edits (cli_options) changes_to_make = {} EDITING_OPTIONS.each do |opt| if cli_options[opt] opt_check = D3::Admin::OPTIONS[opt][:validate] if opt_check changes_to_make[opt] = D3::Admin::Validate.send(opt_check, cli_options[opt]) else changes_to_make[opt] = cli_options[opt] end end # if @options[opt] end #.each do |opt| changes_to_make end ### Before making edits, check the possibly new edition in two ways: ### 1) that it doesn't conflict with another edition in d3 ### 2) if the original package name contained the original edition ### and the edition has changed, change the package name to match. ### ### Raises an exception if there are edition conflicts ### ### @param pkg[D3::Package] the package we're editing ### ### @param changes_to_make[Hash] the changes we want to make ### ### @return [Hash] changes_to_make with a possibly new :name ### def check_new_edition (pkg, changes_to_make) new_vers = changes_to_make[:version] new_rev = changes_to_make[:revision] if new_vers or new_rev potential_edition = "#{pkg.basename}-#{new_vers ? new_vers : pkg.version}-#{new_rev ? new_rev : pkg.revision}" unless pkg.edition == potential_edition # edition conflict? if D3::Package.all_editions.include? potential_edition raise JSS::AlreadyExistsError, "Can't change version or revision as requested: edition conflict with #{potential_edition}" end # name syncing? if pkg.name.include? pkg.edition changes_to_make[:package_name] = pkg.name.sub(pkg.edition, potential_edition ) unless changes_to_make[:package_name] end end # unless end # if new_vers or new_rev return changes_to_make end ### Before making edits, confirm that the possibly new auto ### or excluded groups don't overlap with each other. ### ### Raises an exception if there are overlaps ### ### @param pkg[D3::Package] the package we're editing ### ### @param changes_to_make[Hash] the changes we want to make ### ### @return [void] ### def check_for_new_group_overlaps (pkg, changes_to_make) new_auto_gs = changes_to_make[:auto_groups] new_excl_gs = changes_to_make[:excluded_groups] bad_groups = [] if new_excl_gs and new_auto_gs bad_groups = new_excl_gs & new_auto_gs elsif new_excl_gs bad_groups = new_excl_gs & pkg.auto_groups elsif new_auto_gs bad_groups = new_auto_gs & pkg.excluded_groups end raise "Auto and Excluded groups can't overlap!" unless bad_groups.empty? true end ### Make the changes that have been requested with an edit ### ### @param pkg[D3::Package] the package we're editing ### ### @param changes_to_make[Hash] the changes we want to make ### ### @return [void] ### def process_edits (pkg, changes_to_make) changes_to_make.each do |opt, new_val| setter = (opt.to_s + "=").to_sym pkg.send setter, new_val end pkg.save pkg.update_master_filename D3::Admin::Auth.rw_credentials(:dist)[:password] if changes_to_make[:filename] end end # module edit end # module Admin end # module D3