class SC::Buildfile
A Buildfile
is a special type of file that contains the configurations and build tasks used for a particular project or project target. Buildfiles are based on Rake but largely use their own syntax and helper methods.
Whenever you create a project, you will often also add a Buildfile
, sc-config, or sc-config.rb file. All of these files are laoded into the build system using this class. The other model objects will then reference their buildfile to extract configuration information and to find key tasks required for the build process.
Loading a Buildfile
¶ ↑
To load a buildfile, just use the load() method:
buildfile = Buildfile.load('/path/to/buildfile')
You can also load multiple buildfiles by calling the load!() method on an exising Buildfile
object or by passing a directory with several buildfiles in it:
buildfile = Buildfile.new buildfile.load!('buildfile1').load!('buildfile2')
Defining a Buildfile
¶ ↑
Finally, you can also define new settings on a buildfile directly. Simply use the define() method:
buildfile = Buildfile.define do task :demo_task end
You can also define additional tasks on an existing buildfile object like so:
buildfile = Buildfile.new buildfile.define! do task :demo_task end
When you call define!() on a buildfile, the block is executed in the context of the buildfile object, just like a Buildfile
loaded from disk. You will not usually use define!() on a buildfile in normal code, but it is very useful for unit testing.
Executing Tasks¶ ↑
Once a buildfile is loaded, you can execute tasks on the buildfile using the invoke() method. You should pass the name of the task you want to execute along with any constants you want set for the task to access:
buildfile.invoke :demo_task, :context => my_context
With the above example, the demo_task could access the “context” as a global constant like do:
task :demo_task do CONTEXT.name = "demo!" end
Accessing Configs¶ ↑
Configs are stored in a “normalized” state in the “configs” property. You can access configs directly this way, but the more useful way to access configs is through the config_for
() method. Pass the name of the target that is the current “focus” of the config:
config = buildfile.config_for('/sproutcore') # target always starts w /
Configs can be specified in different “contexts” by the buildfile. When you call this method, the configs will be merged together, layering any configs that are targeted specifically at the /sproutcore target over the top of globally defined configs. The current build mode is also reflected in this call.
Constants
- BUILDFILE_NAMES
Default buildfile names. Override with SC.env.buildfile_names
Attributes
The hash of configs as loaded from the files. The configs are stored by mode and then by config name. To get a merged config, use config_for
().
TASK METHODS
Application options from the command line
The location of the buildfile represented by this object.
This is set if you use the project helper method in your buildfile.
The hash of all proxies paths and their options
The namespace for this buildfile. This should be name equal to the namespace of the target that owns the buildfile, if there is one
Public Class Methods
Determines if this directory has a buildfile or not…
# File lib/sproutcore/buildfile.rb, line 103 def self.has_buildfile?(dir_path, buildfile_names=nil) buildfile_names ||= (SC.env[:buildfile_names] || BUILDFILE_NAMES) buildfile_names.each do |path| path = File.join(dir_path, path) return true if File.exist?(path) && !File.directory?(path) end return false end
INTERNAL SUPPORT
SC::TaskManager::new
# File lib/sproutcore/buildfile.rb, line 406 def initialize super @configs = HashStruct.new @proxies = HashStruct.new @pending_imports = [] @imported = [] @options = HashStruct.new end
Public Instance Methods
Merge the passed hash of options into the config hash. This method is usually used by the config global helper
Params¶ ↑
config_name:: the name of the config to set config_mode:: the mode to store the config. If omitted use current opts: the config options to merge in
Returns¶ ↑
receiver
# File lib/sproutcore/buildfile.rb, line 303 def add_config(config_name, config_mode, opts=nil) # Normalize Params if opts.nil? opts = config_mode; config_mode = nil end config_mode = current_mode if config_mode.nil? # Normalize the config name -- :all or 'all' is OK, absolute OK. config_name = config_name.to_s if config_name != 'all' && (config_name[0..0] != '/') if target_name && (config_name == File.basename(target_name)) config_name = target_name else config_name = [target_name, config_name].join('/') end end # Perform Merge mode_configs = (self.configs[config_mode.to_sym] ||= HashStruct.new) config = (mode_configs[config_name.to_sym] ||= ::SC::Buildfile::Config.new) config.merge!(opts) end
Add a file to the list of files to be imported.
# File lib/sproutcore/buildfile.rb, line 232 def add_import(fn) @pending_imports << fn end
Adds a proxy to the list of proxy paths. These are used only in server mode to proxy certain URLs. If you call this method with the same proxy path more than once, the options will be merged.
Params¶ ↑
:proxy_path the URL to proxy :opts any proxy options
Returns¶ ↑
receiver
# File lib/sproutcore/buildfile.rb, line 397 def add_proxy(proxy_path, opts={}) @proxies[proxy_path.to_sym] = HashStruct.new(opts) return self end
Params¶ ↑
config_name:: The config name mode_name:: optional mode name
Returns¶ ↑
merged config -- a HashStruct
# File lib/sproutcore/buildfile.rb, line 341 def config_for(config_name, mode_name=nil) mode_name = :all if mode_name.nil? || mode_name.to_s.size == 0 config_name = :all if config_name.nil? || config_name.to_s.size == 0 # collect the hashes all_configs = configs[:all] cur_configs = configs[mode_name] ret = ::SC::Buildfile::Config.new # now merge em! -- note that this assumes the merge method will handle # self.merge(self) & self.merge(nil) gracefully ret.merge!(all_configs[:all]) if all_configs ret.merge!(cur_configs[:all]) if cur_configs ret.merge!(all_configs[config_name.to_sym]) if all_configs ret.merge!(cur_configs[config_name.to_sym]) if cur_configs # Done -- return result return ret end
CONFIG METHODS
# File lib/sproutcore/buildfile.rb, line 262 def current_mode @define_context[:current_mode] end
# File lib/sproutcore/buildfile.rb, line 266 def current_mode=(new_mode) @define_context[:current_mode] = new_mode end
Extend the buildfile dynamically by executing the named task. This will yield the block if given after making the buildfile the current build file.
Params¶ ↑
string:: optional string to eval &block:: optional block to execute
Returns¶ ↑
self
# File lib/sproutcore/buildfile.rb, line 153 def define!(string=nil, filename="(unknown Buildfile)", &block) context = reset_define_context :current_mode => :all instance_eval(string, filename) if string instance_eval(&block) if block_given? load_imports reset_define_context context return self end
When dup'ing, rewrite the @tasks hash to use clones of the tasks the point to the new application object.
# File lib/sproutcore/buildfile.rb, line 417 def dup ret = super # Make sure the tasks themselves are cloned ret_tasks = ret.instance_variable_set("@tasks", {}) @tasks.each do | key, task | ret_tasks[key] = task.dup(ret) end # Deep clone the config and proxy hashes as well... ret.configs = Marshal.load(Marshal.dump(configs)) ret.proxies = Marshal.load(Marshal.dump(proxies)) ret.options = Marshal.load(Marshal.dump(options)) ret.is_project = false if ret.project? return ret end
Support redefining a task…
SC::TaskManager#intern
# File lib/sproutcore/buildfile.rb, line 249 def intern(task_class, task_name) ret = super(task_class, task_name) ret.clear if @is_redefining return ret end
Executes the name task. Unlike invoke_task, this method will execute the task even if it has already been executed before. You can also pass a hash of additional constants that will be set on the global namespace before the task is invoked.
Params¶ ↑
task_name:: the full name of the task, including namespaces consts:: Optional hash of constant values to set on the env
# File lib/sproutcore/buildfile.rb, line 212 def invoke(task_name, consts = {}) original, SproutCore::RakeConstants.constant_list = SproutCore::RakeConstants.constant_list, consts self[task_name].invoke(consts) ensure SproutCore::RakeConstants.constant_list = original end
Loads the contents of the passed file into the buildfile object. The contents will be executed in the context of the buildfile object. If the filename passed is nil or the file does not exist, this will simply do nothing.
Params¶ ↑
filename:: the buildfile to load or a directory buildfile_names:: optional array of names to search in directory
Returns¶ ↑
self
# File lib/sproutcore/buildfile.rb, line 178 def load!(filename=nil, buildfile_names=nil) # If a directory is passed, look for any buildfile and load them... if File.directory?(filename) # search directory for buildfiles and load them. buildfile_names ||= (SC.env[:buildfile_names] || BUILDFILE_NAMES) buildfile_names.each do |path| path = File.join(filename, path) next unless File.exist?(path) && !File.directory?(path) load!(path) end elsif File.exist?(filename) old_path = @current_path @current_path = filename loaded_paths << filename # save loaded paths SC.logger.debug "Loading buildfile at #{filename}" define!(File.read(filename), filename) if filename && File.exist?(filename) @current_path = old_path end return self end
Load the pending list of imported files.
# File lib/sproutcore/buildfile.rb, line 237 def load_imports while fn = @pending_imports.shift next if @imported.member?(fn) if fn_task = lookup(fn) fn_task.invoke end load!(fn) @imported << fn end end
# File lib/sproutcore/buildfile.rb, line 202 def loaded_paths; @loaded_paths ||= []; end
# File lib/sproutcore/buildfile.rb, line 377 def project!; @is_project = true; end
Returns YES if this buildfile appears to represent a project. If you use the project() helper method, it will set this
# File lib/sproutcore/buildfile.rb, line 376 def project?; @is_project || false; end
# File lib/sproutcore/buildfile.rb, line 368 def project_type; @project_type || :default; end
# File lib/sproutcore/buildfile.rb, line 162 def task_defined?(task_name) !!lookup(task_name) end
Protected Instance Methods
Save off the old define context and replace it with the passed context This is used during a call to define()
# File lib/sproutcore/buildfile.rb, line 440 def reset_define_context(context=nil) ret = @define_context @define_context = HashStruct.new(context || {}) return ret end