# encoding: utf-8 # Copyright (c) 2012, HipByte SPRL and contributors # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'motion/project/app' module Motion; module Project class Config include Rake::DSL if defined?(Rake) && Rake.const_defined?(:DSL) VARS = [] def self.variable(*syms) syms.each do |sym| attr_accessor sym VARS << sym.to_s end end class Deps < Hash def []=(key, val) key = relpath(key) val = [val] unless val.is_a?(Array) val = val.map { |x| relpath(x) } super end def relpath(path) /^\./.match(path) ? path : File.join('.', path) end end variable :name, :files, :build_dir, :specs_dir, :resources_dirs, :motiondir # Internal only. attr_accessor :build_mode, :spec_mode, :distribution_mode, :dependencies, :template, :detect_dependencies, :exclude_from_detect_dependencies ConfigTemplates = {} def self.register(template) ConfigTemplates[template] = self end def self.make(template, project_dir, build_mode) klass = ConfigTemplates[template] unless klass $stderr.puts "Config template `#{template}' not registered" exit 1 end config = klass.new(project_dir, build_mode) config.template = template config end def initialize(project_dir, build_mode) @project_dir = project_dir @files = Dir.glob(File.join(project_dir, 'app/**/*.rb')) @build_mode = build_mode @name = 'Untitled' @resources_dirs = [File.join(project_dir, 'resources')] @build_dir = File.join(project_dir, 'build') @specs_dir = File.join(project_dir, 'spec') @detect_dependencies = true @exclude_from_detect_dependencies = [] end OSX_VERSION = `/usr/bin/sw_vers -productVersion`.strip.sub(/\.\d+$/, '').to_f def variables map = {} VARS.each do |sym| map[sym] = begin send(sym) rescue Exception 'Error' end end map end def setup_blocks @setup_blocks ||= [] end def setup if @setup_blocks @setup_blocks.each { |b| b.call(self) } @setup_blocks = nil validate end self end def unescape_path(path) path.gsub('\\', '') end def escape_path(path) path.gsub(' ', '\\ ') end def locate_binary(name) [File.join(xcode_dir, 'usr/bin'), '/usr/bin'].each do |dir| path = File.join(dir, name) return escape_path(path) if File.exist?(path) end App.fail "Can't locate binary `#{name}' on the system." end def validate # Do nothing, for now. end def supported_versions @supported_versions ||= Dir.glob(File.join(motiondir, 'data', template.to_s, '*')).select{|path| File.directory?(path)}.map do |path| File.basename path end end def resources_dir warn("`app.resources_dir' is deprecated; use `app.resources_dirs'"); @resources_dirs.first end def resources_dir=(dir) warn("`app.resources_dir' is deprecated; use `app.resources_dirs'"); @resources_dirs = [dir] end def build_dir unless File.directory?(@build_dir) tried = false begin FileUtils.mkdir_p(@build_dir) rescue Errno::EACCES raise if tried require 'digest/sha1' hash = Digest::SHA1.hexdigest(File.expand_path(project_dir)) tmp = File.join(ENV['TMPDIR'], hash) App.warn "Cannot create build_dir `#{@build_dir}'. Check the permissions. Using a temporary build directory instead: `#{tmp}'" @build_dir = tmp tried = true retry end end @build_dir end def build_mode_name @build_mode.to_s.capitalize end def development? @build_mode == :development end def release? @build_mode == :release end def development yield if development? end def release yield if release? end def opt_level @opt_level ||= case @build_mode when :development; 0 when :release; 3 else; 0 end end attr_reader :project_dir def project_file File.join(@project_dir, 'Rakefile') end def files_dependencies(deps_hash) res_path = lambda do |x| path = /^\.{0,2}\//.match(x) ? x : File.join('.', x) unless @files.flatten.include?(path) App.fail "Can't resolve dependency `#{path}'" end path end deps_hash.each do |path, deps| deps = [deps] unless deps.is_a?(Array) @dependencies[res_path.call(path)] = deps.map(&res_path) end end def file_dependencies(file) # memorize the calculated file dependencies in order to reduce the time # detecting file dependencies. # http://hipbyte.myjetbrains.com/youtrack/issue/RM-466 @known_dependencies ||= {} @known_dependencies[file] ||= begin deps = @dependencies[file] || [] deps = deps.map { |x| file_dependencies(x) }.flatten.uniq deps << file deps end end def ordered_build_files @ordered_build_files ||= begin @files.flatten.map { |file| file_dependencies(file) }.flatten.uniq end end def spec_core_files @spec_core_files ||= begin # Core library + core helpers. Dir.chdir(File.join(File.dirname(__FILE__), '..')) do (['spec.rb'] + Dir.glob(File.join('spec', 'helpers', '*.rb')) + Dir.glob(File.join('project', 'template', App.template.to_s, 'spec-helpers', '*.rb'))). map { |x| File.expand_path(x) } end end end def spec_files @spec_files ||= begin # Project helpers. helpers = Dir.glob(File.join(specs_dir, 'helpers', '*.rb')) # Project specs. specs = Dir.glob(File.join(specs_dir, '**', '*.rb')) - helpers if files_filter = ENV['files'] # Filter specs we want to run. A filter can be either the basename of a spec file or its path. files_filter = files_filter.split(',') files_filter.map! { |x| File.exist?(x) ? File.expand_path(x) : x } specs.delete_if { |x| [File.expand_path(x), File.basename(x, '.rb'), File.basename(x, '_spec.rb')].none? { |p| files_filter.include?(p) } } end spec_core_files + helpers + specs end end def motiondir @motiondir ||= File.expand_path(File.join(File.dirname(__FILE__), '../../..')) end def bindir File.join(motiondir, 'bin') end def datadir(target=deployment_target) File.join(motiondir, 'data', template.to_s, target) end def strip_args '' end def print_crash_message $stderr.puts '' $stderr.puts '=' * 80 $stderr.puts <