Skip to content

Commit

Permalink
tests are green; down below 1100ms for a cold boot
Browse files Browse the repository at this point in the history
  • Loading branch information
wycats committed Aug 20, 2010
1 parent 580af47 commit 2285c77
Show file tree
Hide file tree
Showing 23 changed files with 217 additions and 190 deletions.
73 changes: 41 additions & 32 deletions lib/buildtasks/entry.rake
Expand Up @@ -3,60 +3,69 @@
# copyright 2008, Sprout Systems, Inc. and Apple Inc. all rights reserved
# ===========================================================================

# Tasks invoked while building ManifestEntry objects. You can override these
# Tasks invoked while building ManifestEntry objects. You can override these
# tasks in your buildfiles.
namespace :entry do

# Invoked whenever a new entry is added. Gives you a chance to fill in any
# standard properties. The default implementation ensures that the entry
# has at least a source_path, build_path, staging_path, url and build_task
#
# With this task in place, you can build an entry by simply providing a
# With this task in place, you can build an entry by simply providing a
# filename and, optionally a source_path or source_entries.
task_options :log => :none # no logging -- too much detail
task :prepare do
filename = ENTRY[:filename]
raise "All entries must have a filename!" if filename.nil?

entry, manifest = ENTRY, MANIFEST

filename = entry[:filename]
raise "All entries must have a filename!" unless filename

filename_parts = filename.split('/')
# If this is a composite entry, then the source_paths array should

# If this is a composite entry, then the source_paths array should
# contain the staging_path from the source_entries. The source_path
# is simply the first source_paths.
if ENTRY.composite?
ENTRY[:source_entries] ||= [ENTRY[:source_entry]].compact
ENTRY[:source_paths] ||= ENTRY[:source_entries].map { |e| e[:staging_path] }
ENTRY[:source_path] ||= ENTRY[:source_paths].first
ENTRY[:source_entry] ||= ENTRY[:source_entries].first

if entry.composite?
if source_entries = entry[:source_entries]
entry[:source_entry] ||= source_entries.first
else
source_entries = entry[:source_entries] = Array(entry[:source_entry])
end

unless source_paths = entry[:source_paths]
source_paths = entry[:source_paths] = source_entries.map { |e| e[:staging_path] }
end

entry[:source_path] ||= source_paths.first

# Otherwise, the source_path is where we will pull from and source_paths
# is simply the source_path in an array.
else
ENTRY[:source_path] ||= File.join(MANIFEST[:source_root], filename_parts)
ENTRY[:source_paths] ||= [ENTRY[:source_path]]
entry[:source_path] ||= File.join(manifest[:source_root], filename_parts)
entry[:source_paths] ||= [entry[:source_path]]
end

# Construct some easier paths if needed
ENTRY[:build_path] ||= File.join(MANIFEST[:build_root], filename_parts)
ENTRY[:url] ||= [MANIFEST[:url_root], filename_parts].join('/')
entry[:build_path] ||= File.join(manifest[:build_root], filename_parts)
entry[:url] ||= [manifest[:url_root], filename_parts].join('/')

# Fill in a default build task
ENTRY[:build_task] ||= 'build:copy'
ENTRY.ext = File.extname(filename)[1..-1]
# If the build_task is build:copy, make the staging path equal the
# source_root. This is an optimization that will avoid unnecessary
entry[:build_task] ||= 'build:copy'

entry[:ext] = File.extname(filename)[1..-1]

# If the build_task is build:copy, make the staging path equal the
# source_root. This is an optimization that will avoid unnecessary
# copying. All other build_tasks we build a staging path from the root.
if ENTRY[:build_task].to_s == 'build:copy'
ENTRY[:staging_path] ||= ENTRY[:source_path]
if entry[:build_task] == 'build:copy'
entry[:staging_path] ||= entry[:source_path]
else
ENTRY[:staging_path] ||= MANIFEST.unique_staging_path(File.join(MANIFEST[:staging_root], filename_parts))
entry[:staging_path] ||= manifest.unique_staging_path(File.join(manifest[:staging_root], filename_parts))
end
ENTRY[:cache_path] = MANIFEST.unique_cache_path(File.join(MANIFEST[:cache_root], filename_parts))

entry[:cache_path] = manifest.unique_cache_path(File.join(manifest[:cache_root], filename_parts))

end

end

10 changes: 5 additions & 5 deletions lib/sproutcore/builders/bundle.rb
Expand Up @@ -47,12 +47,12 @@ def build(dst_path)

output = ""
entry.targets.each do |t|
bundle_info = t.bundle_info({ :debug => entry.debug, :test => entry.test, :theme => entry.theme, :variation => entry.variation })
bundle_info = t.bundle_info({ :debug => entry[:debug], :test => entry[:test], :theme => entry[:theme], :variation => entry[:variation] })
output << eruby.evaluate({
:target_name => t.target_name.to_s.sub(/^\//,''),
:requires => bundle_info.requires.map{ |t| "'#{t.target_name.to_s.sub(/^\//,'')}'" },
:styles => bundle_info.css_urls.map{ |url| "'#{url}'" },
:scripts => bundle_info.js_urls.map{ |url| "'#{url}'" }
:target_name => t[:target_name].to_s.sub(/^\//,''),
:requires => bundle_info[:requires].map{ |t| "'#{t[:target_name].to_s.sub(/^\//,'')}'" },
:styles => bundle_info[:css_urls].map{ |url| "'#{url}'" },
:scripts => bundle_info[:js_urls].map{ |url| "'#{url}'" }
})
end
writelines dst_path, [output]
Expand Down
34 changes: 21 additions & 13 deletions lib/sproutcore/buildfile.rb
Expand Up @@ -212,9 +212,10 @@ def loaded_paths; @loaded_paths ||= []; end
# task_name:: the full name of the task, including namespaces
# consts:: Optional hash of constant values to set on the env
def invoke(task_name, consts = nil)
consts = set_kernel_consts consts # save to restore
self[task_name.to_s].invoke
set_kernel_consts consts # clear constants
original = set_kernel_consts consts
self[task_name].invoke
ensure
set_kernel_consts original
end

# Returns true if the buildfile has the named task defined
Expand Down Expand Up @@ -320,7 +321,7 @@ def add_config(config_name, config_mode, opts=nil)

# Perform Merge
mode_configs = (self.configs[config_mode.to_sym] ||= HashStruct.new)
config = (mode_configs[config_name.to_sym] ||= HashStruct.new)
config = (mode_configs[config_name.to_sym] ||= ::SC::Buildfile::Config.new)
config.merge!(opts)
end

Expand All @@ -346,7 +347,7 @@ def config_for(config_name, mode_name=nil)
# collect the hashes
all_configs = configs[:all]
cur_configs = configs[mode_name]
ret = HashStruct.new
ret = ::SC::Buildfile::Config.new

# now merge em! -- note that this assumes the merge method will handle
# self.merge(self) & self.merge(nil) gracefully
Expand Down Expand Up @@ -444,25 +445,25 @@ def reset_define_context(context=nil)

# For each key in the passed hash, this will register a global
def set_kernel_consts(env = nil)
return env if env.nil?
return env unless env

# for each item in the passed environment, convert to uppercase constant
# and set in global namespace. Save the old value so that it can be
# restored later.
ret = {}
env.each do |key, value|
const_key = key.to_s.upcase.to_sym
const_key = key.to_s.upcase

# Save the old const value
ret[key] = Kernel.const_get(const_key) rescue nil
ret[key] = Object.const_get(const_key) if Object.const_defined?(const_key)

# Reset
Kernel.const_reset(const_key, value)
Object.const_reset(const_key, value)
end

# Also, save env. Used mostly for logging
ret['TASK_ENV'] = Kernel.const_get('TASK_ENV') rescue nil
Kernel.const_reset('TASK_ENV', env)
ret['TASK_ENV'] = Object.const_get('TASK_ENV') if Object.const_defined?("TASK_ENV")
Object.const_reset('TASK_ENV', env)

return ret
end
Expand All @@ -473,13 +474,20 @@ def set_kernel_consts(env = nil)

# Add public method to kernel to remove defined constant using private
# method.
module Kernel
def const_reset(key, value)
class Object
def self.const_reset(key, value)
remove_const(key) if const_defined?(key)
const_set key, value
end
end

# back-compat
module Kernel
def self.const_reset(key, value)
Object.const_reset(key, value)
end
end

require "sproutcore/buildfile/build_task"
require "sproutcore/buildfile/buildfile_dsl"
require "sproutcore/buildfile/early_time"
Expand Down
9 changes: 8 additions & 1 deletion lib/sproutcore/buildfile/buildfile_dsl.rb
Expand Up @@ -9,6 +9,13 @@ module SC

class Buildfile

# This class allows us to memoize common computations
class Config < HashStruct
def target_names
@target_names ||= self[:target_types].keys
end
end

# Describe the domain-specific-language helpers supported by buildfiles.
# This is included as a mixin for the buildfile.
module Commands
Expand Down Expand Up @@ -132,7 +139,7 @@ def mode(build_mode, &block)
# end
#
def config(config_name, opts = {}, &block)
opts = ::SC::HashStruct.new(opts)
opts = ::SC::Buildfile::Config.new(opts)
yield(opts) if block_given?
add_config config_name, opts
return self
Expand Down
51 changes: 24 additions & 27 deletions lib/sproutcore/buildfile/task.rb
Expand Up @@ -64,7 +64,7 @@ def source
@sources.first if defined?(@sources)
end

IGNORE = %w(@lock @application)
IGNORE = %w(@application)
def dup(app=nil)
app = application if app.nil?
sibling = self.class.new(name, app)
Expand All @@ -84,7 +84,6 @@ def initialize(task_name, app)
@actions = []
@full_comment = nil
@comment = nil
@lock = Monitor.new
@application = app
@scope = app.current_scope
@arg_names = nil
Expand Down Expand Up @@ -165,40 +164,38 @@ def self.outdent_logs
def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
unless invocation_chain.already_invoked?(self)
invocation_chain = InvocationChain.append(self, invocation_chain)
@lock.synchronize do

indent = self.class.indent_logs
indent = self.class.indent_logs

# Use logging options to decide what to output
# one of :env, :name, :none
log_opt = task_options[:log] || :none
if [:name, :env].include?(log_opt)
SC.logger.debug "#{indent}invoke ~ #{name} #{format_trace_flags}"
end
# Use logging options to decide what to output
# one of :env, :name, :none
log_opt = task_options[:log] || :none
if [:name, :env].include?(log_opt)
SC.logger.debug "#{indent}invoke ~ #{name} #{format_trace_flags}"
end

if log_opt == :env
TASK_ENV.each do |key, value|
next if %w(config task_env).include?(key.to_s.downcase)
SC.logger.debug "#{indent} #{key} = #{value.inspect}"
end
if log_opt == :env
TASK_ENV.each do |key, value|
next if %w(config task_env).include?(key.to_s.downcase)
SC.logger.debug "#{indent} #{key} = #{value.inspect}"
end
end

t_start = Time.now.to_f * 1000

invocation_chain = invoke_prerequisites(task_args, invocation_chain)
@invoke_count += 1
execute(task_args) if needed?
t_start = Time.now.to_f * 1000

t_end = Time.now.to_f * 1000
t_diff = t_end - t_start
invocation_chain = invoke_prerequisites(task_args, invocation_chain)
@invoke_count += 1
execute(task_args) if needed?

# ignore short tasks
if t_diff > 10
SC.logger.debug "#{indent}long task ~ #{name}: #{t_diff.to_i} msec"
end
self.class.outdent_logs
t_end = Time.now.to_f * 1000
t_diff = t_end - t_start

# ignore short tasks
if t_diff > 10
SC.logger.debug "#{indent}long task ~ #{name}: #{t_diff.to_i} msec"
end
self.class.outdent_logs

end
return invocation_chain
end
Expand Down
28 changes: 15 additions & 13 deletions lib/sproutcore/buildfile/task_manager.rb
Expand Up @@ -17,6 +17,7 @@ module TaskManager

def initialize
super
@task_cache = Hash.new {|h,k| h[k] = {} }
@tasks = Hash.new
@rules = Array.new
@scope = Array.new
Expand Down Expand Up @@ -51,8 +52,7 @@ def intern(task_class, task_name)

# Find a matching task for +task_name+.
def [](task_name, scopes=nil)
task_name = task_name.to_s
self.lookup(task_name, scopes) or
lookup(task_name, scopes) or
raise "Don't know how to build task '#{task_name}'"
end

Expand Down Expand Up @@ -135,18 +135,20 @@ def clear
# are recognized. If no scope argument is supplied, use the
# current scope. Return nil if the task cannot be found.
def lookup(task_name, initial_scope=nil)
initial_scope ||= @scope
task_name = task_name.to_s
if task_name =~ /^rake:/
scopes = []
task_name = task_name.sub(/^rake:/, '')
elsif task_name =~ /^(\^+)/
scopes = initial_scope[0, initial_scope.size - $1.size]
task_name = task_name.sub(/^(\^+)/, '')
else
scopes = initial_scope
@task_cache[initial_scope][task_name] ||= begin
initial_scope ||= @scope
task_name = task_name.to_s
if task_name =~ /^rake:/
scopes = []
task_name = task_name.sub(/^rake:/, '')
elsif task_name =~ /^(\^+)/
scopes = initial_scope[0, initial_scope.size - $1.size]
task_name = task_name.sub(/^(\^+)/, '')
else
scopes = initial_scope
end
lookup_in_scope(task_name, scopes)
end
lookup_in_scope(task_name, scopes)
end

# Lookup the task name
Expand Down

0 comments on commit 2285c77

Please sign in to comment.