# # File:: branch.rb # Description:: Project Branch configuration. # # Author:: David Muir # Author:: Greg Smith # Date:: 26 August 2008 # #----------------------------------------------------------------------------- # Uses #----------------------------------------------------------------------------- require 'pipeline/config/targets' require 'pipeline/config/script' require 'pipeline/util/string' #----------------------------------------------------------------------------- # Implementation #----------------------------------------------------------------------------- module Pipeline # # == Description # Unity build class. # class UnityBuildConfig attr_accessor :enabled def initialize() @enabled = true end end # # == Description # Code configuration class. # class CodeConfig attr_accessor :compiler # default compiler version (vs2005, vs2008, vs2010) attr_accessor :unity_build # unity build def initialize() @compiler = :'vs2005' @unity_build = UnityBuildConfig.new() end end # # == Description # Project branch configuration class. # class Branch attr_accessor :name # Branch name attr_reader :project # Project reference attr_accessor :default # true/false if default project branch # PATHS attr_accessor :audio # Branch audio data root path attr_accessor :build # Branch build data root path attr_accessor :export # Branch export data path (unprocessed, raw) attr_accessor :processed # Branch processed data path attr_accessor :metadata # Branch metadata data path attr_accessor :independent # Branch independent data path (OBSOLETE) attr_accessor :common # Branch common data path attr_accessor :shaders # Branch shaders path attr_accessor :code # Branch code path attr_accessor :ragecode # Branch RAGE code path attr_accessor :script # Branch script source path attr_accessor :art # Branch art path (typically shared between branches) attr_accessor :assets # Branch assets path (typically shared between branches) attr_accessor :preview # Branch preview directory # CODE CONFIG attr_accessor :codeconfigs # CodeConfig objects # SCRIPT CONFIG attr_accessor :scriptconfig # ScriptConfig object # TARGETS attr_reader :ind_target # Platform-independent target object attr_reader :targets # Hash of ProjectTarget objects # BUILDER CONFIG attr_accessor :builders # Hash, keys: :assetbuild, :codebuild, :scriptbuild, :assettest def initialize( project, name, build = '', export = '', processed = '', metadata = '', independent = '', common = '', shaders = '', code = nil, script = '', art = '', builders = {}, preview = '', audio = '', assets = '' ) @project = project @name = name @audio = audio @build = build @export = export @processed = processed @metadata = metadata @independent = independent # +OBSOLETE+ @common = common @shaders = shaders @code = code @script = script @art = art @assets = assets @preview = preview @codeconfigs = [] @ind_target = IndependentTarget.new( @project, self ) @targets = {} @builders = {} end def fill_env( env ) # Ensure we get the project's environment but not the default branches # environment. @project.fill_env( env, false ) unless ( @project.nil? ) env.add( 'branch', env.subst( @name ) ) env.add( 'build', env.subst( @build ) ) env.add( 'art', env.subst( @art ) ) \ unless ( not defined? @art ) or @art.nil? env.add( 'assets', env.subst( @assets ) ) \ unless ( not defined? @assets ) or @assets.nil? env.add( 'audio', env.subst( @audio ) ) \ unless ( not defined? @audio ) or @audio.nil? env.add( 'export', env.subst( @export ) ) env.add( 'processed', env.subst( @processed ) ) env.add( 'metadata', env.subst( @metadata ) ) env.add( 'independent', env.subst( @independent ) ) env.add( 'common', env.subst( @common ) ) env.add( 'shaders', env.subst( @shaders ) ) env.add( 'code', env.subst( @code ) ) \ unless ( not defined? @code ) or @code.nil? env.add( 'ragecode', env.subst( @ragecode ) ) \ unless ( not defined? @ragecode ) or @ragecode.nil? env.add( 'script', env.subst( @script ) ) \ unless ( not defined? @script ) or @script.nil? env.add( 'preview', env.subst( @preview ) ) \ unless ( not defined? @preview ) or @preview.nil? end def in_env( &block ) env = Environment.new() fill_env( env ) yield( env ) if ( block_given? ) end # # Return true iff the passed in filename is within this project's # export directory structure. # def is_export_file?( filename ) ( filename.starts_with( @export ) ) end # # Return true iff the passed in filename is within this project's # processed directory structure. # def is_processed_file?( filename ) ( filename.starts_with( @processed ) ) end # # Return true iff the passed in filename is within this project's # independent directory structure. # # +OBSOLETE+ # def is_independent_file?( filename ) ( filename.starts_with( @export ) ) end # # Return true iff the passed in filename is within a project target's # directory structure. # def is_platform_file?( filename ) @targets.each do |name, target| target_prefix = '$(target)' target.in_env do |e| target_prefix = e.subst( target_prefix ) end return true if ( filename.starts_with( target_prefix ) ) end false end # # Return true iff the passed in filename is within this project's # audio directory structure. # # DHM TODO: generalise these methods from all the PATH member data. # (incl. is_independent_file? etc) # def is_audio_file?( filename ) return true if ( filename.starts_with( @audio ) ) false end # # Return REXML::Element for local XML configuration. # def to_local_xml( ) branch_elem = Element.new( 'branch' ) branch_elem.attributes['name'] = @name targets_elem = branch_elem.add_element( 'targets' ) @targets.each_pair do |platform, target| targets_elem.add_element( target.to_local_xml() ) end branch_elem end #--------------------------------------------------------------------- # Class Methods #--------------------------------------------------------------------- # # Parse branch data from an XML node, either creating a new Branch # object or overwriting data in the specified branch object. # # The new (or updated) Branch object is returned. # # This allows us to have local.xml overwrite anything in config.xml. # def Branch::from_xml( xml_node, env, project, branch = nil ) throw ArgumentError.new( "Invalid Project object specified (#{project.class})." ) \ unless ( project.is_a?( Pipeline::Project ) ) throw ArgumentError.new( "Invalid Branch object specified (#{branch.class})." ) \ unless ( branch.nil? or branch.is_a?( Pipeline::Branch ) ) env.push( ) name = xml_node.attributes['name'] branch = Branch.new( project, name ) if ( branch.nil? ) # Initial environment setup. project.fill_env( env ) # Loop through our attributes; the attributes collection is a Hash # so we immediately lose order. Lets post-process the environment # afterwards. xml_node.attributes.each_attribute do |attr| # Please keep this case statement in alphabetical order. case ( attr.name.downcase.strip ) when 'art' branch.art = env.subst( attr.value ) env.add( 'art', branch.art ) unless ( branch.art.empty? ) when 'assets' branch.assets = env.subst( attr.value ) env.add( 'assets', branch.assets ) unless ( branch.assets.empty? ) when 'audio' branch.audio = env.subst( attr.value ) env.add( 'audio', branch.audio ) unless ( branch.audio.empty? ) when 'build' branch.build = env.subst( attr.value ) env.add( 'build', branch.build ) unless ( branch.build.empty? ) when 'code' branch.code = env.subst( attr.value ) env.add( 'code', branch.code ) unless ( branch.code.empty? ) when 'common' branch.common = env.subst( attr.value ) env.add( 'common', branch.common ) unless ( branch.common.empty? ) when 'export' branch.export = env.subst( attr.value ) env.add( 'export', branch.export ) unless ( branch.export.empty? ) when 'independent' # !!THIS IS OBSOLETE!! branch.independent = env.subst( attr.value ) env.add( 'independent', branch.independent ) unless ( branch.independent.empty? ) when 'metadata' branch.metadata = env.subst( attr.value ) env.add( 'metadata', branch.metadata ) unless ( branch.metadata.empty? ) when 'name' branch.name = env.subst( attr.value ) env.add( 'branch', branch.name ) unless ( branch.name.empty? ) when 'preview' branch.preview = env.subst( attr.value ) env.add( 'preview', branch.preview ) unless ( branch.preview.empty? ) when 'processed' branch.processed = env.subst( attr.value ) env.add( 'processed', branch.processed ) unless ( branch.processed.empty? ) when 'ragecode' branch.ragecode = env.subst( attr.value ) env.add( 'ragecode', branch.ragecode ) unless ( branch.ragecode.empty? ) when 'script' branch.script = env.subst( attr.value ) env.add( 'script', branch.script ) unless ( branch.script.empty? ) when 'shaders' branch.shaders = env.subst( attr.value ) env.add( 'shaders', branch.shaders ) unless ( branch.shaders.empty? ) end # switch attr.name end # ENVIRONMENT RESOLVE; because we can't read the attributes in the # order in which they were supplied in the XML file. branch.art = env.subst( branch.art ) branch.assets = env.subst( branch.assets ) branch.audio = env.subst( branch.audio ) branch.build = env.subst( branch.build ) branch.code = env.subst( branch.code ) branch.common = env.subst( branch.common ) branch.export = env.subst( branch.export ) # !!THIS IS OBSOLETE!! branch.independent = env.subst( branch.independent ) branch.metadata = env.subst( branch.metadata ) branch.preview = env.subst( branch.preview ) branch.processed = env.subst( branch.processed ) branch.ragecode = env.subst( branch.ragecode ) branch.script = env.subst( branch.script ) branch.shaders = env.subst( branch.shaders ) # SCRIPT CONFIG branch.scriptconfig = ScriptConfig::from_xml( xml_node.elements['script'], env, branch, branch.scriptconfig ) \ unless ( xml_node.elements['script'].nil? ) # CODE CONFIGS : high level build configuration : compiler, unity build. xml_node.elements.each( 'code_configs' ) do |code_configs| code_configs.elements.each( 'code_config' ) do |code_config| new_codeconfig = CodeConfig.new() new_codeconfig.compiler = code_config.attributes["compiler"].to_sym code_config.elements.each('unity_build') do |unity_build| new_codeconfig.unity_build.enabled = ( 'true' == unity_build.attributes['enabled'] ) unless unity_build.attributes['enabled'].nil? end branch.codeconfigs << new_codeconfig end end # TARGETS xml_node.elements.each( 'targets/target' ) do |target| platform = target.attributes['platform'] platform.downcase! target_platform = target.attributes['platform'] throw XMLParseError.new( 'Target does not specify platform. Fix target configuration.' ) \ if ( target_platform.nil? ) project_target = nil project_target = branch.targets[target_platform] if ( branch.targets.has_key?( target_platform ) ) project_target = Target::from_xml( target, project, branch, env, project_target ) # 2011/03/03 DHM; The unless statement here ensures that targets # defined in the local XML that do not have a definition are ignored. branch.targets[target_platform] = project_target unless ( project_target.target.nil? ) end # BUILDERS (only for builder server and client users) c = Config::instance() if ( c.user.is_builder_client or c.user.is_builder_server ) then branch.builders = {} xml_node.elements.each( 'builders/builder' ) do |builder_node| builder_name = builder_node.attributes['name'].to_sym unless ( builder_node.attributes['name'].nil? ) queue_port = builder_node.attributes['queue_port'].to_i unless ( builder_node.attributes['queue_port'].nil? ) branch.builders[builder_name] = {} branch.builders[builder_name][:queue_port] = queue_port end end env.pop( ) # RAGE # We do not parse the RAGE XML here, it is parsed in the # Pipeline::RageConvertTool class, in pipeline/util/rage.rb. branch end end end # Pipeline module # branch.rb