require 'ostruct' require 'yaml' # A Rack middleware application that creates a single configuration for Helix Web # Services. # # Most web services are modular Sinatra applications, which does come with it's # own settings mechanism. We should try to avoid those settings in most cases. # Perhaps only if those settings are only relevant to the logic directly # within the Sinatra app. # # Many other settings, like the port setting of the associated Helix Versioning # Engine, should be exposed and overridable by the client application. These # settings should be defined here. # # This class provides middleware that will inject an `hws_settings` object into # each request. This `hws_settings` object is seeded by values declared on this # class. When the system starts, our system config file is read in, and default # system values are overridden. On any request, these settings can be # overridden by the user. # # Additionally, there are "system" settings that are only overridable from the # system config file. Client classes should reference this class directly: # HWSSettings.system. # # ## Naming Conventions # # Use uppercase letters, numbers, or underscores only. # # ## HTTP Header Override Syntax # # We allow per-request overrides of settings via HTTP headers. # # The key format of the custom setting is: # # `X-PERFORCE-HELIX_WEB_SERVICES-{key}` # # For example: # # X-PERFORCE-HELIX_WEB_SERVICES-P4HOST: perforce.mycompany.com # X-PERFORCE-HELIX_WEB_SERVICES-P4CHARSET: auto # # Please note that headers will be converted by Rack to all uppercase, hence # our naming conventions. # # ## System Config File # # The system configuration is stored in the # `/etc/perforce/helix_web_services.conf` file. This is a YAML # file, and we override any locally defined variables with values found in # this file. ()If you specify a value in this file we do not locally define, # we ignore it.) # # Example values in /etc/perforce/helix_web_services.conf: # # P4HOST: 'perforce.mycompany.com' # P4PORT: '9991' # # class HWSSettings SYSTEM_CONFIG_PATH = '/etc/perforce/helix_web_services.conf' @settings = OpenStruct.new( # The .git-fusion depot name :GIT_FUSION_DEPOT => '.git-fusion', # If set, the HVEProjects class will use this path to locate projects # in the system. :HVE_PROJECTS_PATH => nil, # The current API level used to interact with the Perforce server :P4APILEVEL => '78', # The hostname of the p4d (Helix Versioning Engine) instance :P4HOST => nil, # The port of the p4d (Helix Versioning Engine) instance :P4PORT => '1666', # The charset setting to use when connecting to the p4d instance :P4CHARSET => 'auto' ) @system = OpenStruct.new( # Allow the indicated commands to be used in the # /helix_verdsioning_engine/v1/commands methods # Each entry is either a string (the command name) or an Array of command # and required arguments. :COMMAND_WHITELIST => ['info', ['files', '-m']], # Set this to true to use helix cloud as the authentication source. :ENABLE_HELIX_CLOUD_AUTH => false, # Enable Helix Cloud project helpers. :ENABLE_HELIX_CLOUD_PROJECTS => false, # The local file location that defines where services are located :SERVICE_CONFIGURATION => '/etc/perforce/services.json', # Use this working directory for temporary workspaces (typically for making submits) :WORKSPACE_DIR => '/var/lib/perforce/helix_web_services/workspaces' ) class << self # Returns baseline settings with system overrides applied. # # This is a copy of state. If you want to alter the default settings in # code instead of via config files, use the `settings_handle` def settings s = OpenStruct.new(@settings) s.each_pair do |key, _| if overrides.respond_to?(key) s[key] = overrides[key] end end s end # You can tweak the default settings directly here in code. def settings_handle @settings end # Returns our system settings overridden by local configuration in overrides. # # This is a *copy* of the class system settings, suitable for editing and # passing on. # # See the official guide for declared options. def system s = OpenStruct.new(@system) s.each_pair do |key, _| if overrides.respond_to?(key) s[key] = overrides[key] end end s end # In case your code wants to edit the system classes directly. Typically # used for test initialization. def system_handle @system end # Return the system overrides in our system configuration file. def overrides return @overrides ||= init_overrides end private def init_overrides if File.exists?(SYSTEM_CONFIG_PATH) OpenStruct.new(YAML.load_file(SYSTEM_CONFIG_PATH)) end end end def initialize(app) @app = app end def call(env) hws_settings = self.class.settings env.each do |key, value| match = /^HTTP_X_PERFORCE_HELIX_WEB_SERVICES_(.*)$/.match(key) if match hws_settings[match[1]] = value end end env['hws_settings'] = hws_settings @app.call(env) end end