diff --git a/lib/motion/project/builder.rb b/lib/motion/project/builder.rb index 9aa8f124..c05ef13a 100644 --- a/lib/motion/project/builder.rb +++ b/lib/motion/project/builder.rb @@ -24,6 +24,8 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'thread' +require 'motion/project/paralel_builder' +require 'motion/project/dependency' module Motion; module Project; class Builder @@ -562,214 +564,4 @@ EOS end end end - - class ParallelBuilder - attr_accessor :files - - def initialize(objs_build_dir, builder) - @builders_count = begin - if jobs = ENV['jobs'] - jobs.to_i - else - `/usr/sbin/sysctl -n machdep.cpu.thread_count`.strip.to_i - end - end - @builders_count = 1 if @builders_count < 1 - - @builders = [] - @builders_count.times do - queue = [] - th = Thread.new do - sleep - objs = [] - while path = queue.shift - objs << builder.call(objs_build_dir, path) - end - queue.concat(objs) - end - @builders << [queue, th] - end - end - - def run - builder_i = 0 - @files.each do |path| - @builders[builder_i][0] << path - builder_i += 1 - builder_i = 0 if builder_i == @builders_count - end - - # Start build. - @builders.each do |queue, th| - sleep 0.01 while th.status != 'sleep' - th.wakeup - end - @builders.each { |queue, th| th.join } - @builders - end - - def objects - objs = [] - builder_i = 0 - @files.each do |path| - objs << @builders[builder_i][0].shift - builder_i += 1 - builder_i = 0 if builder_i == @builders_count - end - objs - end - end - - class Dependency - begin - require 'ripper' - rescue LoadError - $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '../../ripper18'))) - require 'ripper' - end - - @file_paths = [] - - def initialize(paths, dependencies) - @file_paths = paths.flatten.sort - @dependencies = dependencies - end - - def cyclic?(dependencies, def_path, ref_path) - deps = dependencies[def_path] - if deps - if deps.include?(ref_path) - return true - end - deps.each do |file| - return true if cyclic?(dependencies, file, ref_path) - end - end - - return false - end - - def run - consts_defined = {} - consts_referred = {} - @file_paths.each do |path| - parser = Constant.new(File.read(path)) - parser.parse - parser.defined.each do |const| - consts_defined[const] = path - end - parser.referred.each do |const| - consts_referred[const] ||= [] - consts_referred[const] << path - end - end - - dependency = @dependencies.dup - consts_defined.each do |const, def_path| - if consts_referred[const] - consts_referred[const].each do |ref_path| - if def_path != ref_path - if cyclic?(dependency, def_path, ref_path) - # remove cyclic dependencies - next - end - - dependency[ref_path] ||= [] - dependency[ref_path] << def_path - dependency[ref_path].uniq! - end - end - end - end - - return dependency - end - - class Constant < Ripper::SexpBuilder - attr_accessor :defined - attr_accessor :referred - - def initialize(source) - @defined = [] - @referred = [] - super - end - - def on_const_ref(args) - args - end - - def on_var_field(args) - args - end - - def on_var_ref(args) - type, name, position = args - if type == :@const - @referred << name - return [:referred, name] - end - end - - def on_const_path_ref(parent, args) - type, name, position = args - if type == :@const - @referred << name - if parent && parent[0] == :referred - register_referred_constants(parent[1], name) - end - end - args - end - - def on_assign(const, *args) - type, name, position = const - if type == :@const - @defined << name - return [:defined, name] - end - end - - def on_module(const, *args) - handle_module_class_event(const, args) - end - - def on_class(const, *args) - handle_module_class_event(const, args) - end - - def handle_module_class_event(const, *args) - type, name, position = const - if type == :@const - @defined << name - @referred.delete(name) - children = args.flatten - children.each_with_index do |key, i| - if key == :defined - register_defined_constants(name, children[i+1]) - end - end - return [:defined, name] - end - end - - def register_defined_constants(parent, child) - construct_nest_constants!(@defined, parent, child) - end - - def register_referred_constants(parent, child) - construct_nest_constants!(@referred, parent, child) - end - - def construct_nest_constants!(consts, parent, child) - nested = [] - consts.each do |const| - if md = const.match(/^([^:]+)/) - nested << "#{parent}::#{const}" if md[0] == child - end - end - consts.concat(nested) - end - end - end end; end diff --git a/lib/motion/project/dependency.rb b/lib/motion/project/dependency.rb new file mode 100644 index 00000000..6216d07a --- /dev/null +++ b/lib/motion/project/dependency.rb @@ -0,0 +1,179 @@ +# 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. + +module Motion; module Project; + class Dependency + begin + require 'ripper' + rescue LoadError + $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '../../ripper18'))) + require 'ripper' + end + + @file_paths = [] + + def initialize(paths, dependencies) + @file_paths = paths.flatten.sort + @dependencies = dependencies + end + + def cyclic?(dependencies, def_path, ref_path) + deps = dependencies[def_path] + if deps + if deps.include?(ref_path) + return true + end + deps.each do |file| + return true if cyclic?(dependencies, file, ref_path) + end + end + + return false + end + + def run + consts_defined = {} + consts_referred = {} + @file_paths.each do |path| + parser = Constant.new(File.read(path)) + parser.parse + parser.defined.each do |const| + consts_defined[const] = path + end + parser.referred.each do |const| + consts_referred[const] ||= [] + consts_referred[const] << path + end + end + + dependency = @dependencies.dup + consts_defined.each do |const, def_path| + if consts_referred[const] + consts_referred[const].each do |ref_path| + if def_path != ref_path + if cyclic?(dependency, def_path, ref_path) + # remove cyclic dependencies + next + end + + dependency[ref_path] ||= [] + dependency[ref_path] << def_path + dependency[ref_path].uniq! + end + end + end + end + + return dependency + end + + class Constant < Ripper::SexpBuilder + attr_accessor :defined + attr_accessor :referred + + def initialize(source) + @defined = [] + @referred = [] + super + end + + def on_const_ref(args) + args + end + + def on_var_field(args) + args + end + + def on_var_ref(args) + type, name, position = args + if type == :@const + @referred << name + return [:referred, name] + end + end + + def on_const_path_ref(parent, args) + type, name, position = args + if type == :@const + @referred << name + if parent && parent[0] == :referred + register_referred_constants(parent[1], name) + end + end + args + end + + def on_assign(const, *args) + type, name, position = const + if type == :@const + @defined << name + return [:defined, name] + end + end + + def on_module(const, *args) + handle_module_class_event(const, args) + end + + def on_class(const, *args) + handle_module_class_event(const, args) + end + + def handle_module_class_event(const, *args) + type, name, position = const + if type == :@const + @defined << name + @referred.delete(name) + children = args.flatten + children.each_with_index do |key, i| + if key == :defined + register_defined_constants(name, children[i+1]) + end + end + return [:defined, name] + end + end + + def register_defined_constants(parent, child) + construct_nest_constants!(@defined, parent, child) + end + + def register_referred_constants(parent, child) + construct_nest_constants!(@referred, parent, child) + end + + def construct_nest_constants!(consts, parent, child) + nested = [] + consts.each do |const| + if md = const.match(/^([^:]+)/) + nested << "#{parent}::#{const}" if md[0] == child + end + end + consts.concat(nested) + end + end + end +end;end diff --git a/lib/motion/project/paralel_builder.rb b/lib/motion/project/paralel_builder.rb new file mode 100644 index 00000000..7089def9 --- /dev/null +++ b/lib/motion/project/paralel_builder.rb @@ -0,0 +1,83 @@ +# 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. + +module Motion; module Project; + class ParallelBuilder + attr_accessor :files + + def initialize(objs_build_dir, builder) + @builders_count = begin + if jobs = ENV['jobs'] + jobs.to_i + else + `/usr/sbin/sysctl -n machdep.cpu.thread_count`.strip.to_i + end + end + @builders_count = 1 if @builders_count < 1 + + @builders = [] + @builders_count.times do + queue = [] + th = Thread.new do + sleep + objs = [] + while path = queue.shift + objs << builder.call(objs_build_dir, path) + end + queue.concat(objs) + end + @builders << [queue, th] + end + end + + def run + builder_i = 0 + @files.each do |path| + @builders[builder_i][0] << path + builder_i += 1 + builder_i = 0 if builder_i == @builders_count + end + + # Start build. + @builders.each do |queue, th| + sleep 0.01 while th.status != 'sleep' + th.wakeup + end + @builders.each { |queue, th| th.join } + @builders + end + + def objects + objs = [] + builder_i = 0 + @files.each do |path| + objs << @builders[builder_i][0].shift + builder_i += 1 + builder_i = 0 if builder_i == @builders_count + end + objs + end + end +end;end \ No newline at end of file