diff --git a/bin/sc-jstd b/bin/sc-jstd new file mode 100755 index 00000000..f18676ce --- /dev/null +++ b/bin/sc-jstd @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +# =========================================================================== +# Project: Abbot - SproutCore Build Tools +# Copyright: ©2010 Apple Inc. +# portions copyright @2006-2011 Strobe Inc. +# and contributors +# =========================================================================== + +if caller.empty? + puts "FATAL: You need to invoke sc-jstd from an installed gem or through bundler. For more information, please visit http://github.com/sproutcore/abbot/wiki/Using-Abbot-1.4-From-Source" + exit +end + +require "sproutcore" + +begin + gem 'nokogiri' +rescue LoadError + puts "FATAL: Missing nokogiri. Please install nokogiri (~1.5.0) to use sc-jstd." + exit +end + +SC::Tools.invoke 'jstd' + +# EOF diff --git a/lib/sproutcore.rb b/lib/sproutcore.rb index 8577b8d4..ae990f40 100644 --- a/lib/sproutcore.rb +++ b/lib/sproutcore.rb @@ -98,6 +98,12 @@ def self.builtin_project @builtin_project ||= SC::Project.new(PATH) end + # This is used by sc-jstd. When using sc-jstd you will have two servers running, sc-server and + # the jstd server. Because the browser will be connecting to the jstd server directly these + # url paths need to be absolute. Not the most ideal approach, but this avoids alot of refactoring. + def self.module_url_prefix; return @module_url_prefix if @module_url_prefix; return "" end + def self.module_url_prefix=(module_url_prefix); @module_url_prefix = module_url_prefix; end + # Returns the current project, if defined. This is normally only set # when you start sc-server in interactive mode. def self.project; @project; end diff --git a/lib/sproutcore/builders/module.rb b/lib/sproutcore/builders/module.rb index 09aeda21..2ba9ca49 100644 --- a/lib/sproutcore/builders/module.rb +++ b/lib/sproutcore/builders/module.rb @@ -40,6 +40,7 @@ def build(dst_path) EOT output = "" + module_url_prefix = SC.module_url_prefix entry.targets.each do |t| next unless t[:target_type] == :module @@ -48,19 +49,19 @@ def build(dst_path) script_entry = manifest.find_entry('javascript.js') next if not script_entry - script_url = script_entry.cacheable_url + script_url = module_url_prefix + script_entry.cacheable_url string_entry = manifest.find_entry('javascript-strings.js') next if not string_entry - string_url = string_entry.cacheable_url + string_url = module_url_prefix + string_entry.cacheable_url module_info = t.module_info({ :variation => entry[:variation] }) output << eruby.evaluate({ :target_name => t[:target_name].to_s.sub(/^\//,''), :dependencies => module_info[:requires].map{ |t| "'#{t[:target_name].to_s.sub(/^\//,'')}'" }, - :styles => module_info[:css_urls].map{ |url| "'#{url}'" }, - :styles2x => module_info[:css_2x_urls].map {|url| "'#{url}'"}, + :styles => module_info[:css_urls].map{ |url| "'#{module_url_prefix}#{url}'" }, + :styles2x => module_info[:css_2x_urls].map {|url| "'#{module_url_prefix}#{url}'"}, :script => script_url, :string => string_url, :prefetched => t[:prefetched_module] diff --git a/lib/sproutcore/models/project.rb b/lib/sproutcore/models/project.rb index 3df9d85c..7fe086cc 100644 --- a/lib/sproutcore/models/project.rb +++ b/lib/sproutcore/models/project.rb @@ -41,6 +41,12 @@ class Project # Parent project this project shoud inherit build rules and targets from attr_reader :parent_project + + # Proc that will be called when changes are detected to a monitored project + attr_accessor :monitor_proc + + # regex so that certain files don't trigger monitor update + attr_accessor :nomonitor_pattern def inspect "SC::Project(#{File.basename(project_root || '')})" diff --git a/lib/sproutcore/rack/builder.rb b/lib/sproutcore/rack/builder.rb index fa4df149..4475150e 100644 --- a/lib/sproutcore/rack/builder.rb +++ b/lib/sproutcore/rack/builder.rb @@ -217,6 +217,9 @@ def monitor_project! @project_mtime = files.map { |x| File.mtime(x).to_i }.max Thread.new do + # TODO instead of polling every second, should investigate using a FS event + # monitor like fssm (https://github.com/ttilley/fssm). Would be both quicker + # and less resource intensive than polling while @should_monitor # only need to start scanning again 2 seconds after the last @@ -227,8 +230,7 @@ def monitor_project! # follow 1-level of symlinks files += Dir.glob(@project_root / '**' / '*' / '**' / '*') tmp_path = /^#{Regexp.escape(@project_root / 'tmp')}/ - files.reject! { |f| f =~ tmp_path } - files.reject! { |f| File.directory?(f) } + files.reject! { |f| (f =~ tmp_path || File.directory?(f) || f =~ @project.nomonitor_pattern) } cur_file_count = files.size cur_mtime = files.map { |x| File.mtime(x).to_i }.max @@ -238,6 +240,9 @@ def monitor_project! @project_did_change = true @project_file_count = cur_file_count @project_mtime = cur_mtime + # place for some extra project maintainen + extra_action = @project.monitor_proc + extra_action.call if (extra_action && extra_action.respond_to?(:call)) end end diff --git a/lib/sproutcore/tools.rb b/lib/sproutcore/tools.rb index a0428ce5..408e08b4 100644 --- a/lib/sproutcore/tools.rb +++ b/lib/sproutcore/tools.rb @@ -414,6 +414,7 @@ def self.start(args = ARGV) require "sproutcore/tools/docs" require "sproutcore/tools/gen" require "sproutcore/tools/init" +require "sproutcore/tools/jstd" require "sproutcore/tools/manifest" require "sproutcore/tools/server" diff --git a/lib/sproutcore/tools/jstd.rb b/lib/sproutcore/tools/jstd.rb new file mode 100644 index 00000000..8e2ad347 --- /dev/null +++ b/lib/sproutcore/tools/jstd.rb @@ -0,0 +1,93 @@ +# =========================================================================== +# Copyright: ©2011 Paul Lambert & Sproutcore Contributors +# For Abbot, and licensed under same terms as Sproutcore itself +# =========================================================================== + +require 'open-uri' +require 'thread' +require 'yaml' +require 'digest/md5' + +module SC + class Tools + + desc "jstd TARGET [OPTIONS]", "Generates configuration file for JsTestDriver (http://code.google.com/p/js-test-driver/wiki/ConfigurationFile)" + method_options :daemonize => false, + :pid => :string, + :port => :string, + :jstdport => :string, + :jstdhost => :string, + :jstdconfpath => :string, + :app => :string, + :host => :string, + :irb => false, + :filesystem => true + + def jstd(*targets) + require 'nokogiri' + + # set defaults + port = options[:port] = options[:port] || "4225" + jstdport = options[:jstdport] || "4224" + jstdhost = options[:jstdhost] || "http://localhost" + jstdconfpath = options[:jstdconfpath] || "jsTestDriver.conf" + host = options[:host] || "http://localhost" + SC.module_url_prefix = "#{host}:#{port}" + + # find app target + target = requires_target!(*targets) + fatal! "Target must be an app" unless target[:target_type] == :app + target_name = target[:target_name].to_s + + project = requires_project! + # apparently necessary as getting target results in connections being refused + # unless project is subsequently reloaded + project.reload! + + # wrap logic to rebuild configuration file in a Proc/closure + # allowing for it to be rebuilt 'on the fly', which makes for + # a much nicer testing loop. See rack/builder.rb for monitoring and + # invokation of this callback + project.monitor_proc = Proc.new do + url = "#{host}:#{port}#{target_name}/en/current/tests.html" + doc = Nokogiri::HTML(open(url)) + dir = "tmp/jstd" + Dir.mkdir(dir) if not Dir.exists?(dir) + + loadPaths = [] + doc.css('script').each do |link| + js = link['src'] + if js + loadPaths << "#{host}:#{port}#{js}" + elsif (link.content and link.content.length > 0) + js = link.content + + filename = "#{dir}/#{Digest::MD5.hexdigest(js)}.js" + File.open(filename, "w") do |f| + f.write(js) + end + + loadPaths << filename + end + end + project.nomonitor_pattern = Regexp.new(Regexp.escape(jstdconfpath)) + + # write out to yaml conf + conf = {"server"=>"#{jstdhost}:#{jstdport}", "load"=>loadPaths} + File.open(jstdconfpath, "w") do |f| + f.write(YAML::dump(conf)) + end + + SC.logger.info "Wrote to #{jstdconfpath}" + end + + Thread.new do + sleep(4) # give server a chance to start up + project.monitor_proc.call # call once to make sure everything's fresh and valid + end + + server() + end + + end +end diff --git a/sproutcore.gemspec b/sproutcore.gemspec index 94849d8a..206628c9 100644 --- a/sproutcore.gemspec +++ b/sproutcore.gemspec @@ -22,7 +22,6 @@ Gem::Specification.new do |s| s.add_dependency 'erubis', "~> 2.6" s.add_dependency 'thor', '~> 0.14.3' s.add_dependency 'haml', '~> 3.1.1' - s.add_dependency 'compass', '~> 0.11.1' s.add_dependency 'em-http-request', '~> 1.0.0.beta'