$:.push(File.dirname(__FILE__)) require 'rubygems' require 'rake/clean' require 'rake/tasklib' require 'yaml' require 'log' require 'erb' require 'uri' require 'fileutils' require 'zip/zipfilesystem' require 'archive/tar/minitar' module PatternPark class SproutError < StandardError; end class UsageError < SproutError; end class Sprout attr_accessor :name, :type, :render, :platform, :base_url, :dependencies, :targets, :config_cache, :config @@base_urls = ['http://projectsprouts.googlecode.com/svn/trunk/sprouts/', 'http://www.projectsprouts.org/sprout/'] @@default_rakefiles = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze @@universal = 'universal' @@update = false @@project_name = '' @@config_cache = nil @@home = nil @@cache = nil @@project_path = nil ## # Given a simple string @name, request that sprout # definition from each location in the location list # until it's found # def Sprout.load(name) local = File.join(Sprout.config_cache, name) if(!Sprout.update && File.exists?(local)) return Sprout.load_local(local) else @@base_urls.each do |url| begin loader = RemoteFileLoader.new loader.get_remote_file(url + name, local) sprout = Sprout.load_local(local) if(sprout.post_install) eval(sprout.post_install) end return sprout rescue OpenURI::HTTPError => e Log.puts("[WARNING] Sprout not found at: #{url + name}, trying next location") next end raise SproutError.new("\n[ERROR] Sprout could not find '#{name}' definition at any known locations, please check the sprout name and try again.") end end end ## # Retrieve and resolve a locally downloaded Sprout def Sprout.load_local(path) data = nil File.open(path, 'r') do |f| data = f.read end data = ERB.new(data, nil, '>').result(binding) begin sprout = YAML.load(data) rescue StandardError => e Log.puts("[ERROR] An invalid sprout definition was encountered at: [#{path}] with:\n\n#{data}\n\nPlease try again...") if(File.exists?(path)) File.delete(path) end raise UsageError.new('Invalid Sprout definiton') end sprout.resolve return sprout end def Sprout.update=(update) @@update = update end def Sprout.update return @@update end ## # Begin loading and resolving this Sprout instance # and recursively call on dependencies def resolve load_target load_dependencies end def execute dependencies.each do |dep| dep.execute end end def post_install if(target.nil?) return nil end return target.post_install end ## # Load the remote file target associated with this sprout instance def load_target target = get_platform_target if(target) # Forward type name so that RemoteFileTargets can place # downloaded files into the appropriate user home folder target.type = type target.resolve end end ## # Take the array of string dependency names # load each dependency YAML file, and replace # the array with resolved Sprout instances # Tell each dependency to load it's own # dependencies def load_dependencies(loaded_deps=nil) loaded_deps = (loaded_deps.nil?) ? [name] : loaded_deps # Don't reload deps have already been loaded deps = [] if(dependencies) dependencies.each do |dep| dep.values.each do |name| if(!loaded_deps.index(name)) dep = Sprout.load(name) loaded_deps << name deps << dep end end end end @dependencies = deps end ## # Insert search locations (Array) 'base paths' for Sprout.load operations def Sprout.insert_locations(locations) @@base_urls = Sprout.clean_locations(locations) + @@base_urls end # TODO: Be smart about added a trailing '/' # Try to ensure that only valid URLs get # added to the list of locations - throw # something informative if needed. def Sprout.clean_locations(locations) return locations end ## # The system-specific home folder for Sprout application data # e.g., On OS X, /Users/you/Library/Sprouts # e.g., On Win, C:\Documents And Settings\you\Local Settings\Application Data\Sprouts def Sprout.home if(@@home.nil?) @@home = User.new().application_home(:sprouts) end return @@home end ## # The nearest valid project path or current working directory # if no rakefile was found in parent paths def Sprout.project_path(path=nil) if(@@project_path.nil?) path = (path.nil?) ? Dir.pwd : path; path = Sprout.get_project_path(path) if(path.nil?) path = Dir.pwd end @@project_path = path end return @@project_path end def Sprout.project_path=(path) @@project_path = path end def Sprout.get_project_path(path) if(path.nil? || path == '/') return nil end @@default_rakefiles.each do |file| if(File.exists?(File.join(path, file))) return path end end return Sprout.get_project_path(File.dirname(path)) end ## # Offline storage location for network entities like # Sprout definitions, tasks and archives def Sprout.cache if(@@cache.nil?) @@cache = File.join(Sprout.home, 'cache') end return @@cache end def Sprout.config_cache if(@@config_cache.nil?) @@config_cache = File.join(Sprout.cache, 'sprouts') end return @@config_cache end ## # List of potential rakefile names for project_path searching def Sprout.default_rakefiles return @@default_rakefiles end def Sprout.rakefile @@default_rakefiles.each do |name| file = File.join(Sprout.project_path, name) if(File.exists?(file)) return file end end return nil end ## # Reset static values for test purposes def Sprout.init_values User.init_values @@project_path = nil @@config_cache = nil @@cache = nil @@home = nil end ## # List of files to ignore when copying project templates # These files will not be copied @@COPY_IGNORE_FILES = ['.', '..', '.svn', '.DS_Store', 'CVS', '.cvs' 'Thumbs.db', '__MACOSX', '.Trashes', 'Desktop DB', 'Desktop DF'] # Do not copy files found in the ignore_files list def Sprout.ignore_file? file @@COPY_IGNORE_FILES.each do |name| if(name == file) return true end end return false end ## # The project name as entered in the sprout shell command def Sprout.project_name=(name) @@project_name = name end def Sprout.project_name return @@project_name end def get_platform_target usr = User.new @target = nil if(targets) universal_target = nil platform = usr.platform.to_s targets.each do |t| if(t.platform == platform) @target = t elsif(t.platform == @@universal) universal_target = t end end if(target.nil? && universal_target) @target = universal_target end end return @target end ## # The first FileTarget that is applicable for this # client operating system def target return @target end def archive_path return File.join(install_path, target.archive_path) end def install_path target.install_path end def downloaded_path target.downloaded_path end def config_path(name) return Sprout.config_cache + name end end require 'singleton' require 'progress_bar' require 'template_resolver' require 'platform' require 'user' require 'project' require 'library' require 'template' require 'task' require 'command' require 'tool' require 'remote_file_loader' require 'file_target' require 'remote_file_target' require 'project_model' require 'generate' end cache = File.join(PatternPark::Sprout.cache) $:.push(cache)