bake 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,111 @@
1
+ require 'bake/target'
2
+
3
+ module Bake
4
+ class ProjectLoader
5
+ attr_reader :invok_project
6
+
7
+ def initialize(context, invok_dir, props)
8
+ @context = context
9
+ load_root_project(invok_dir, props)
10
+ load_invok_project
11
+ end
12
+
13
+ def load_project(name, from_proj)
14
+ proj = from_proj.child(name, Project)
15
+ if !proj
16
+ dir = File.join(from_proj[:cwdir], name)
17
+ raise "no such directory #{dir}" if !File.exists?(dir)
18
+ proj = Project.new(from_proj)
19
+ proj.loader = self
20
+ proj.name = name
21
+ proj.opt(:projname => name)
22
+ proj.opt(:cwdir => dir)
23
+ process(proj)
24
+ end
25
+ return proj
26
+ end
27
+
28
+ private
29
+ def load_root_project(invok_dir, props)
30
+ project = nil
31
+ dir = invok_dir
32
+ @invok_path = []
33
+ while true
34
+ bakefile = File.join(dir, 'root.bake')
35
+ if File.exists?(bakefile)
36
+ project = Project.new(nil)
37
+ project.loader = self
38
+ project.req(:rootdir => dir)
39
+ project.opt(:projname => 'root')
40
+ project.opt(:cwdir => dir)
41
+ project.opt(:outdir => '${cwdir}')
42
+ props.each_pair { |key, val| project.opt(key => val) }
43
+ break
44
+ end
45
+
46
+ parent_dir = File.dirname(dir)
47
+ raise 'root.bake not found' if parent_dir == dir
48
+ @invok_path << File.basename(dir)
49
+ dir = parent_dir
50
+ end
51
+
52
+ @root_project = project
53
+ process(@root_project)
54
+ end
55
+
56
+ def load_invok_project
57
+ project = @root_project
58
+ @invok_path.reverse_each do |name|
59
+ project = load_project(name, project)
60
+ end
61
+ @invok_project = project
62
+ return project
63
+ end
64
+
65
+ def process(proj)
66
+ if proj.parent
67
+ dir = proj[:cwdir]
68
+ bakefile = File.join(dir, 'sub.bake')
69
+ if File.exists?(bakefile)
70
+ Dir.chdir(dir) { eval_bakefile(proj, bakefile) }
71
+ end
72
+ else
73
+ raise 'internal error' if !@root_project.equal?(proj)
74
+ Dir.chdir(@root_project[:cwdir]) do
75
+ if config_bakefile
76
+ eval_bakefile(@root_project, config_bakefile)
77
+ end
78
+ eval_bakefile(@root_project, root_bakefile)
79
+ end
80
+ end
81
+ end
82
+
83
+ def eval_bakefile(project, bakefile)
84
+ @context.context_eval(project, File.read(bakefile), bakefile)
85
+ end
86
+
87
+ def root_bakefile
88
+ return @root_bakefile if @root_bakefile
89
+ @root_bakefile = File.join(@root_project[:cwdir], 'root.bake')
90
+ return @root_bakefile
91
+ end
92
+
93
+ def config_bakefile
94
+ return @config_bakefile if @config_bakefile
95
+ bakefile = File.join(@root_project[:cwdir], 'config.bake')
96
+ if !File.exists?(bakefile)
97
+ home = ENV['HOME']
98
+ if home
99
+ bakefile = File.join(home, 'config.bake')
100
+ if !File.exists?(bakefile)
101
+ bakefile = nil
102
+ end
103
+ else
104
+ bakefile = nil
105
+ end
106
+ end
107
+ return @config_bakefile = bakefile
108
+ end
109
+ end
110
+ end
111
+
@@ -0,0 +1,62 @@
1
+ require 'bake/toolset'
2
+ require 'bake/target'
3
+ require 'bake/cpp_scheme.rb'
4
+ require 'fileutils'
5
+
6
+ module Qt
7
+ class Moc < Bake::Toolset
8
+ def build(target)
9
+ raise "unknown target '#{target}'" if !target.is_a?(MocFile)
10
+ return if !stale?(target)
11
+ src = target.src
12
+ sh("moc -o #{target.output} #{target.src}")
13
+ end
14
+
15
+ def clean(target)
16
+ FileUtils.rm_f(target.output)
17
+ end
18
+
19
+ def stale?(target)
20
+ return true if !File.exists?(target.output)
21
+ return File.mtime(target.src) > File.mtime(target.output)
22
+ end
23
+
24
+ def sh(*args)
25
+ cmd = args.join(' ')
26
+ puts cmd
27
+ system(*args)
28
+ raise "error: #{cmd}" if !$? || !$?.success?
29
+ end
30
+ end
31
+
32
+ class MocFile < Bake::Target
33
+ attr_reader :output
34
+ attr_accessor :src
35
+
36
+ def initialize(parent, src)
37
+ super(parent)
38
+ ext = File.extname(src)
39
+ @output = File.basename(src, ext) + '.moc' + ext
40
+ @src = src
41
+ end
42
+ end
43
+ end
44
+
45
+ module Cpp
46
+ class Library
47
+ def moc(*args)
48
+ return args.flatten.collect do |file|
49
+ Qt::MocFile.new(Cpp::Object.new(self), file)
50
+ end
51
+ end
52
+ end
53
+
54
+ class Executable
55
+ def moc(*args)
56
+ return args.flatten.collect do |file|
57
+ Qt::MocFile.new(Cpp::Object.new(self), file)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,104 @@
1
+ require 'bake/target'
2
+ require 'bake/toolset'
3
+
4
+ module Bake
5
+ class Scheme
6
+ attr_reader :name, :targets, :toolsets, :toolset
7
+
8
+ def initialize(mod)
9
+ @name = underscore(mod.name)
10
+ @module = mod
11
+ @targets = []
12
+ @toolsets = []
13
+ populate_targets_and_toolsets
14
+ raise "no toolsets in scheme '#{@name}'" if @toolsets.size == 0
15
+ raise "no targets in scheme '#{@name}'" if @targets.size == 0
16
+ @accessors = {}
17
+ populate_accessors
18
+ end
19
+
20
+ def toolset=(toolset)
21
+ if !toolset.is_a?(Toolset)
22
+ ts = toolset_class(toolset.to_s)
23
+ raise "could not find toolset '#{toolset}'" if !ts
24
+ @toolset = ts.new
25
+ return
26
+ end
27
+ if !@toolsets.include?(toolset.class)
28
+ raise "toolset #{toolset.class.name} is not in scheme #{name}"
29
+ end
30
+ @toolset = toolset
31
+ end
32
+
33
+ def has_constructor?(accessor)
34
+ return accessors.has_key?(accessor)
35
+ end
36
+
37
+ def construct(type, *args)
38
+ if type.instance_of?(Class)
39
+ target_class = type
40
+ raise "#{type} not in #{name}" if !targets.include?(type)
41
+ else
42
+ target_class = accessors[type]
43
+ raise "no such constructor #{type}" if !target_class
44
+ end
45
+ target = target_class.new(*args)
46
+ return target
47
+ end
48
+
49
+ private
50
+ attr_reader :accessors
51
+
52
+ def underscore(str)
53
+ str = str.gsub(/[A-Z][a-z0-9]*/) { |val| val.downcase + '_' }.chop
54
+ return str.gsub('_::', '/')
55
+ end
56
+
57
+ def capitalize(str)
58
+ str = str.gsub(/[a-z0-9]+/) { |val| val.capitalize }
59
+ return str.gsub('_', '')
60
+ end
61
+
62
+ def toolset_class(name)
63
+ name = @module.name + '::' + capitalize(name)
64
+ return @toolsets.find { |t| t.name == name }
65
+ end
66
+
67
+ def populate_targets_and_toolsets
68
+ @module.constants.each do |const|
69
+ klazz = @module.const_get(const.to_sym)
70
+ if klazz.instance_of?(Class)
71
+ sup = klazz.superclass
72
+ while sup
73
+ if sup.equal?(Toolset)
74
+ @toolsets << klazz
75
+ break
76
+ elsif sup.equal?(Target)
77
+ @targets << klazz
78
+ break
79
+ end
80
+ sup = sup.superclass
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ def populate_accessors
87
+ @targets.each do |target|
88
+ if target.const_defined?(:ACCESSORS)
89
+ accessors = target.const_get(:ACCESSORS)
90
+ if accessors.respond_to?(:to_ary)
91
+ accessors = accessors.to_ary
92
+ else
93
+ accessors = [ accessors ]
94
+ end
95
+ accessors.each { |accessor| @accessors[accessor] = target }
96
+ end
97
+ if !target.const_defined?(:SCHEME)
98
+ target.const_set(:SCHEME, self)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
@@ -0,0 +1,28 @@
1
+ require 'bake/scheme'
2
+
3
+ module Bake
4
+ class SchemeLoader
5
+ attr_reader :schemes
6
+
7
+ def initialize
8
+ @schemes = {}
9
+ end
10
+
11
+ def scheme(name)
12
+ scheme = @schemes[name]
13
+ return scheme if scheme
14
+ return load_scheme(name)
15
+ end
16
+
17
+ def load_scheme(name)
18
+ file = File.join(File.dirname(__FILE__), "#{name}_scheme.rb")
19
+ raise "unknown scheme '#{name}'" if !File.exists?(file)
20
+ require "bake/#{name}_scheme"
21
+ mod = Bake.const_get(name.capitalize.to_sym)
22
+ scheme = Scheme.new(mod)
23
+ @schemes[scheme.name] = scheme
24
+ return scheme
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,19 @@
1
+ class String
2
+ def basename(options = {})
3
+ if options[:ext]
4
+ return File.basename(self, extname) + options[:ext]
5
+ elsif options[:noext]
6
+ return File.basename(self, extname)
7
+ end
8
+ return File.basename(self)
9
+ end
10
+
11
+ def dirname
12
+ return File.dirname(self)
13
+ end
14
+
15
+ def extname
16
+ return File.extname(self)
17
+ end
18
+ end
19
+
@@ -0,0 +1,115 @@
1
+ require 'bake/configuration'
2
+
3
+ module Bake
4
+ class Target
5
+ include Configuration
6
+
7
+ attr_reader :parent, :children, :deps
8
+ attr_accessor :name
9
+
10
+ def initialize(parent)
11
+ @parent = parent
12
+ @children = []
13
+ @deps = []
14
+ parent.children << self if parent
15
+ opt(:built? => false)
16
+ end
17
+
18
+ def child(name, klazz = nil)
19
+ if klazz
20
+ return children.find do |child|
21
+ child.name == name && child.is_a?(klazz)
22
+ end
23
+ end
24
+ return children.find { |child| child.name == name }
25
+ end
26
+
27
+ def find(name)
28
+ target = children.find do |child|
29
+ !child.is_a?(Project) && child.name == name
30
+ end
31
+ target ||= parent.find(name) if parent
32
+ return target
33
+ end
34
+
35
+ def dep(*targets)
36
+ ret = []
37
+ targets.each do |target|
38
+ if !target.is_a?(Target)
39
+ real_target = parent.find(target) if parent
40
+ raise "uknown target '#{target}'" if !real_target
41
+ target = real_target
42
+ end
43
+ deps << target
44
+ ret << target
45
+ end
46
+ return ret
47
+ end
48
+
49
+ def to_s(level = 0)
50
+ str = (' ' * level) + (@name || '<empty>') +
51
+ ' (' + self.class.name + ')'
52
+ if !deps.empty?
53
+ str += ' => '
54
+ deps.each do |target|
55
+ str += target.name + ' (' + target.class.name + ') '
56
+ end
57
+ end
58
+ str += "\n"
59
+ if !children.empty?
60
+ children.each { |target| str += target.to_s(level + 1) }
61
+ end
62
+ return str
63
+ end
64
+ end
65
+
66
+ class Project < Target
67
+ SCHEME = nil
68
+
69
+ attr_accessor :loader
70
+
71
+ def initialize(parent)
72
+ super(parent)
73
+ @mappings = {}
74
+ end
75
+
76
+ def map(mappings)
77
+ mappings.each do |name, loc|
78
+ raise "target '#{name}' already mapped" if @mappings[name]
79
+ @mappings[name] = loc
80
+ end
81
+ end
82
+
83
+ def mapping(name)
84
+ target = nil
85
+ mapping = @mappings[name]
86
+ if mapping
87
+ if mapping.instance_of?(String)
88
+ path = @mappings[name].split('/')
89
+ proj = self
90
+ path.each do |dir|
91
+ proj = loader.load_project(dir, proj)
92
+ end
93
+ target = proj.child(name)
94
+ @mappings[name] = target
95
+ raise "invalid mapping #{@mappings[name]}" if !target
96
+ elsif mapping.is_a?(Target)
97
+ target = mapping
98
+ else
99
+ raise "mapping has invalid class '#{mapping.class.name}'"
100
+ end
101
+ end
102
+ return target
103
+ end
104
+
105
+ def find(name)
106
+ target = mapping(name)
107
+ target ||= children.find do |child|
108
+ !child.is_a?(Project) && child.name == name
109
+ end
110
+ target ||= parent.find(name) if parent
111
+ return target
112
+ end
113
+ end
114
+ end
115
+
@@ -0,0 +1,11 @@
1
+ module Bake
2
+ class Toolset
3
+ def sh(*args)
4
+ cmd = args.join(' ')
5
+ puts cmd
6
+ system(*args)
7
+ raise "error: #{cmd}" if !$? || !$?.success?
8
+ end
9
+ end
10
+ end
11
+