### 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 Variables ##################################### ##################################### ### Module Methods ##################################### ##################################### ### Classes ##################################### ### A class for working with settings & preferences for the D3 module ### ### This is a singleton class, only one instance can exist at a time. ### ### When the D3 module loads, the Configuration instance is created and stored ### in the constant {D3::CONFIG}. ### ### Known attributes are listed and defined in the d3.conf.default file ### in the rubygem folder's data folder ### (e.g. /Library/Ruby/Gems/2.0.0/gems/depot3-3.0.0/data/d3.conf.default) ### ### The current settings may be saved using {Configuration#save}. ### With no parameter, {#save} writes to the {Configuration::CONF_FILE} ### otherwise provide a String or Pathname file path. ### NOTE: This overwrites any existing file. ### ### To re-load the settings use {Configuration#reload}. This clears the ### current settings, and re-reads both the {CONF_FILE}. ### If a pathname is provided, e.g. ### D3::CONFIG.reload '/path/to/other/file' ### the current settings are cleared and reloaded from that other file. ### ### To view the current settings, use {Configuration#print}. ### ### class Configuration include Singleton ################# Class Constants ################# ### The filename for storing the prefs, globally CONF_FILE = Pathname.new "/etc/d3.conf" ### The attribute keys we maintain, and the String#method to convert them ### to the correct ruby class ### See the d3.conf.default file in the rubygem's data folder ### for detailed descriptions of these keys. ### (e.g. /Library/Ruby/Gems/2.0.0/gems/depot3-3.0.0/data/d3.conf.default) ### CONF_KEYS = { :jss_default_pkg_category => :to_s, :jss_default_script_category => :to_s, :log_file => :to_s, :log_level => :to_sym, :log_timestamp_format => :to_s, :client_expiration_allowed => :jss_to_bool, :client_expiration_policy => :to_s, :client_jss_ro_user => :to_s, :client_jss_ropw_path => :to_s, :client_db_ro_user => :to_s, :client_db_ropw_path => :to_s, :client_distpoint_ropw_path => :to_s, :client_http_ropw_path => :to_s, :client_try_cloud_distpoint => :jss_to_bool, :client_prohibited_admin_names => [:split,/\s*,\s*/], :puppy_notification_policy => :to_s, :puppy_notification_frequency => :to_i, :puppy_last_notification => :jss_to_time, :puppy_reboot_policy => :to_s, :puppy_notify_image_path => :to_s, :puppy_optout_seconds => :to_i, :puppy_optout_text => :to_s, :puppy_optout_image_path => :to_s, :puppy_slideshow_folder_path => :to_s, :puppy_display_captions => :jss_to_bool, :puppy_no_captions_text => :to_s, :puppy_image_size => :to_i, :puppy_title => :to_s, :puppy_display_secs => :to_i, :notification_image_path => :jss_to_pathname, :admin_make_live_script => :to_s, :admin_auto_clean => :jss_to_bool, :admin_auto_clean_keep_deprecated => :to_i, :admin_auto_clean_keep_latest_pilots => :jss_to_bool, :report_receipts_ext_attr_name => :to_s, :report_puppyq_ext_attr_name => :to_s, :report_db_server => :to_s } ################# Attributes ################# # automatically create accessors for all the CONF_KEYS CONF_KEYS.keys.each {|k| attr_accessor k} ################# Constructor ################# ### ### Initialize! ### def initialize read_conf end ################# Public Instance Methods ################# ### Since config must be loaded before logging can start ### use this to send debug messages to stderr before ### the logger is set up, if the client app has set debugging ### ### def log (msg, level) if D3.respond_to? :loaded? and D3.loaded? D3.log msg, level else STDERR.puts "#{level}: #{msg}" if ENV['D3_DEBUG'] end end ### Clear all values ### ### @return [void] ### def clear_all log "Clearing all config values", :debug unless @initializing CONF_KEYS.keys.each {|k| self.send "#{k}=".to_sym, nil} end ### (Re)read the global prefs, if it exists. ### ### @return [void] ### def read_conf read CONF_FILE if CONF_FILE.file? and CONF_FILE.readable? end ### Clear the settings and reload the prefs files, or another file if provided ### ### @param file[String,Pathname] a non-standard prefs file to load ### ### @return [void] ### def reload(file = nil) clear_all if file read file return true end read_conf return true end ### Save the prefs into a file. ### ### @param file[String,Pathname] an arbitrary file into which the config is saved. ### defaults to CONF_FILE ### ### @return [void] ### def save(file = CONF_FILE) file = Pathname.new file # file already exists? read it in and update the values. if file.readable? data = file.read # go thru the known attributes/keys CONF_KEYS.keys.sort.each do |k| savable_value = to_string k # if the key exists, update it. if data =~ /^#{k}:/ log "Updating config file value #{k}: #{savable_value}", :debug data.sub!(/^#{k}:.*$/, "#{k}: #{savable_value}") # if not, add it to the end unless it's nil else log "Adding config file value #{k}: #{savable_value}", :debug data += "\n#{k}: #{savable_value}" unless self.send(k).nil? end # if data =~ /^#{k}:/ end #each do |k| else # not readable, make a new file data = "" log "Config file #{file} not found, creating.", :debug CONF_KEYS.keys.sort.each do |k| data << "#{k}: #{savable_value}\n" unless self.send(k).nil? end end # if path readable # make sure we end with a newline, the save it. data << "\n" unless data.end_with?("\n") file.jss_save data log "Config file #{file} saved.", :debug end # read file ### ### Print out the current settings to stdout ### ### @return [void] ### def print CONF_KEYS.keys.sort.each{|k| puts "#{k}: #{to_string k}"} end ################# Private Instance Methods ################# private ### Convert an attribute value to a savable string. ### All values are converted to Strings using a matching '_to_s' ### private method, if defined, or with standard #to_s. ### ### @param key[symbol] one of the attribute keys from CONF_KEYS ### ### @return [String] a string version of teh attribute value ### def to_string (key) # custom convertion to savable string? convert = (key.to_s + '_to_s').to_sym if self.class.private_method_defined? convert str = self.send convert else str = self.send(key).to_s end str end ### Custom string conversion for the :client_prohibited_admin_names ### value, which is an array. ### ### @return [String,nil] the Array values joined with commas, or nil ### def client_prohibited_admin_names_to_s return nil unless @client_prohibited_admin_names @client_prohibited_admin_names.join "," end ### ### Read in any prefs file ### ### @param file[String,Pathname] the file to read ### ### @return [void] ### def read(file) log "Reading config file #{file}", :debug Pathname.new(file).read.each_line do |line| # skip blank lines and those starting with # next if line =~ /^\s*(#|$)/ line.strip =~ /^(\w+?):\s*(\S.*)$/ next unless $1 attr = $1.to_sym setter = "#{attr}=".to_sym value = $2.strip if CONF_KEYS.keys.include? attr if value # convert the value to the correct class # using the method from CONF_KEYS value = value.send *CONF_KEYS[attr] end self.send(setter, value) log "Set key '#{attr}' to '#{value}'", :debug end # if end # do line end # read file end # class Configuration # The single instance of Configuration # must be created before the LOG, since # the log looks here for file names CONFIG = D3::Configuration.instance end # module D3