autobuild 1.7.10 → 1.7.11.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +3 -0
- data/lib/autobuild.rb +37 -7
- data/lib/autobuild/config.rb +85 -13
- data/lib/autobuild/configurable.rb +0 -7
- data/lib/autobuild/environment.rb +2 -3
- data/lib/autobuild/import/archive.rb +34 -4
- data/lib/autobuild/import/cvs.rb +5 -5
- data/lib/autobuild/import/darcs.rb +5 -1
- data/lib/autobuild/import/git.rb +211 -65
- data/lib/autobuild/import/hg.rb +5 -1
- data/lib/autobuild/import/svn.rb +5 -1
- data/lib/autobuild/importer.rb +5 -5
- data/lib/autobuild/package.rb +70 -131
- data/lib/autobuild/packages/autotools.rb +32 -13
- data/lib/autobuild/packages/cmake.rb +30 -16
- data/lib/autobuild/packages/dummy.rb +1 -1
- data/lib/autobuild/packages/genom.rb +1 -1
- data/lib/autobuild/packages/orogen.rb +1 -1
- data/lib/autobuild/packages/ruby.rb +109 -0
- data/lib/autobuild/parallel.rb +56 -17
- data/lib/autobuild/rake_task_extension.rb +19 -0
- data/lib/autobuild/reporting.rb +5 -20
- data/lib/autobuild/subcommand.rb +6 -6
- data/lib/autobuild/timestamps.rb +2 -7
- data/lib/autobuild/utility.rb +164 -0
- data/lib/autobuild/version.rb +1 -1
- data/test/test_config.rb +83 -0
- metadata +16 -11
@@ -0,0 +1,109 @@
|
|
1
|
+
module Autobuild
|
2
|
+
class Ruby < ImporterPackage
|
3
|
+
# The Rake task that is used to set up the package. Defaults to "default".
|
4
|
+
# Set to nil to disable setup altogether
|
5
|
+
attr_accessor :rake_setup_task
|
6
|
+
# The Rake task that is used to generate documentation. Defaults to "doc".
|
7
|
+
# Set to nil to disable documentation generation
|
8
|
+
attr_accessor :rake_doc_task
|
9
|
+
# The Rake task that is used to run tests. Defaults to "test".
|
10
|
+
# Set to nil to disable tests for this package
|
11
|
+
attr_accessor :rake_test_task
|
12
|
+
# The Rake task that is used to run cleanup. Defaults to "clean".
|
13
|
+
# Set to nil to disable tests for this package
|
14
|
+
attr_accessor :rake_clean_task
|
15
|
+
|
16
|
+
def initialize(*args)
|
17
|
+
self.rake_setup_task = "default"
|
18
|
+
self.rake_doc_task = "redocs"
|
19
|
+
self.rake_clean_task = "clean"
|
20
|
+
self.rake_test_task = "test"
|
21
|
+
|
22
|
+
super
|
23
|
+
exclude << /\.so$/
|
24
|
+
exclude << /Makefile$/
|
25
|
+
exclude << /mkmf.log$/
|
26
|
+
exclude << /\.o$/
|
27
|
+
exclude << /doc$/
|
28
|
+
end
|
29
|
+
|
30
|
+
def with_doc
|
31
|
+
doc_task do
|
32
|
+
progress_start "generating documentation for %s", :done_message => 'generated documentation for %s' do
|
33
|
+
Autobuild::Subprocess.run self, 'doc',
|
34
|
+
Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('rake'), rake_doc_task,
|
35
|
+
:working_directory => srcdir
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def with_tests
|
41
|
+
test_utility.task do
|
42
|
+
progress_start "running tests for %s", :done_message => 'tests passed for %s' do
|
43
|
+
Autobuild::Subprocess.run self, 'test',
|
44
|
+
Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('rake'), rake_test_task,
|
45
|
+
:working_directory => srcdir
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def install
|
51
|
+
progress_start "setting up Ruby package %s", :done_message => 'set up Ruby package %s' do
|
52
|
+
Autobuild.update_environment srcdir
|
53
|
+
# Add lib/ unconditionally, as we know that it is a ruby package.
|
54
|
+
# update_environment will add it only if there is a .rb file in the directory
|
55
|
+
libdir = File.join(srcdir, 'lib')
|
56
|
+
if File.directory?(libdir)
|
57
|
+
Autobuild.env_add_path 'RUBYLIB', libdir
|
58
|
+
end
|
59
|
+
|
60
|
+
if rake_setup_task && File.file?(File.join(srcdir, 'Rakefile'))
|
61
|
+
Autobuild::Subprocess.run self, 'post-install',
|
62
|
+
Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('rake'), rake_setup_task,
|
63
|
+
:working_directory => srcdir
|
64
|
+
end
|
65
|
+
end
|
66
|
+
super
|
67
|
+
end
|
68
|
+
|
69
|
+
def prepare_for_forced_build # :nodoc:
|
70
|
+
super
|
71
|
+
%w{ext tmp}.each do |extdir|
|
72
|
+
if File.directory?(extdir)
|
73
|
+
Find.find(extdir) do |file|
|
74
|
+
next if file !~ /\<Makefile\>|\<CMakeCache.txt\>$/
|
75
|
+
FileUtils.rm_rf file
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def prepare_for_rebuild # :nodoc:
|
82
|
+
super
|
83
|
+
if rake_clean_task && File.file?(File.join(srcdir, 'Rakefile'))
|
84
|
+
begin
|
85
|
+
Autobuild::Subprocess.run self, 'clean',
|
86
|
+
Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('rake'), rake_clean_task,
|
87
|
+
:working_directory => srcdir
|
88
|
+
rescue Autobuild::SubcommandFailed => e
|
89
|
+
warn "%s: cleaning failed. If this package does not need a clean target,"
|
90
|
+
warn "%s: set pkg.rake_clean_task = nil in the package definition."
|
91
|
+
warn "%s: see #{e.logfile} for more details"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def update_environment
|
97
|
+
Autobuild.update_environment srcdir
|
98
|
+
libdir = File.join(srcdir, 'lib')
|
99
|
+
if File.directory?(libdir)
|
100
|
+
Autobuild.env_add_path 'RUBYLIB', libdir
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.ruby(spec, &proc)
|
106
|
+
Ruby.new(spec, &proc)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
data/lib/autobuild/parallel.rb
CHANGED
@@ -62,6 +62,10 @@ module Autobuild
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def discover_dependencies(all_tasks, reverse_dependencies, t)
|
65
|
+
if t.already_invoked?
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
65
69
|
return if all_tasks.include?(t) # already discovered or being discovered
|
66
70
|
all_tasks << t
|
67
71
|
|
@@ -79,15 +83,19 @@ module Autobuild
|
|
79
83
|
attr_reader :queue
|
80
84
|
attr_reader :priorities
|
81
85
|
|
82
|
-
def initialize(reverse_dependencies
|
86
|
+
def initialize(reverse_dependencies)
|
83
87
|
@reverse_dependencies = reverse_dependencies
|
84
88
|
@processed = Set.new
|
85
89
|
@active_packages = Set.new
|
86
90
|
@priorities = Hash.new
|
87
91
|
@started_packages = Hash.new
|
88
92
|
@queue = Hash.new
|
89
|
-
|
90
|
-
|
93
|
+
end
|
94
|
+
|
95
|
+
def push(task, base_priority = 1)
|
96
|
+
if task.respond_to?(:package)
|
97
|
+
queue[task] = started_packages[task.package] || base_priority
|
98
|
+
else queue[task] = base_priority
|
91
99
|
end
|
92
100
|
end
|
93
101
|
|
@@ -111,17 +119,20 @@ module Autobuild
|
|
111
119
|
end
|
112
120
|
end
|
113
121
|
|
122
|
+
def ready?(task)
|
123
|
+
task.prerequisite_tasks.all? do |t|
|
124
|
+
t.already_invoked?
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
114
128
|
def process_finished_task(task)
|
115
129
|
if task.respond_to?(:package)
|
116
130
|
active_packages.delete(task.package)
|
117
131
|
end
|
118
132
|
processed << task
|
119
133
|
reverse_dependencies[task].each do |candidate|
|
120
|
-
if !
|
121
|
-
|
122
|
-
queue[candidate] = started_packages[candidate.package] || priorities[task]
|
123
|
-
else queue[candidate] = priorities[task]
|
124
|
-
end
|
134
|
+
if !candidate.already_invoked? && ready?(candidate)
|
135
|
+
push(candidate, priorities[task])
|
125
136
|
end
|
126
137
|
end
|
127
138
|
end
|
@@ -139,7 +150,15 @@ module Autobuild
|
|
139
150
|
required_tasks.each do |t|
|
140
151
|
discover_dependencies(tasks, reverse_dependencies, t)
|
141
152
|
end
|
142
|
-
|
153
|
+
# The queue is the set of tasks for which all prerequisites have
|
154
|
+
# been successfully executed (or where not needed). I.e. it is the
|
155
|
+
# set of tasks that can be queued for execution.
|
156
|
+
state = ProcessingState.new(reverse_dependencies)
|
157
|
+
tasks.each do |t|
|
158
|
+
if state.ready?(t)
|
159
|
+
state.push(t)
|
160
|
+
end
|
161
|
+
end
|
143
162
|
|
144
163
|
# Build a reverse dependency graph (i.e. a mapping from a task to
|
145
164
|
# the tasks that depend on it)
|
@@ -148,10 +167,6 @@ module Autobuild
|
|
148
167
|
# topological sort since we would then have to scan all tasks each
|
149
168
|
# time for tasks that have no currently running prerequisites
|
150
169
|
|
151
|
-
# The queue is the set of tasks for which all prerequisites have
|
152
|
-
# been successfully executed (or where not needed). I.e. it is the
|
153
|
-
# set of tasks that can be queued for execution.
|
154
|
-
state = ProcessingState.new(reverse_dependencies, roots.to_a)
|
155
170
|
while true
|
156
171
|
pending_task = state.pop
|
157
172
|
if !pending_task
|
@@ -172,7 +187,8 @@ module Autobuild
|
|
172
187
|
Worker.execute_task(pending_task)
|
173
188
|
state.process_finished_task(pending_task)
|
174
189
|
next
|
175
|
-
elsif pending_task.
|
190
|
+
elsif pending_task.already_invoked? || !pending_task.needed?
|
191
|
+
pending_task.already_invoked = true
|
176
192
|
state.process_finished_task(pending_task)
|
177
193
|
next
|
178
194
|
end
|
@@ -197,10 +213,33 @@ module Autobuild
|
|
197
213
|
worker.queue(pending_task)
|
198
214
|
end
|
199
215
|
|
200
|
-
|
201
|
-
|
202
|
-
|
216
|
+
not_processed = tasks.find_all { |t| !t.already_invoked? }
|
217
|
+
if !not_processed.empty?
|
218
|
+
cycle = resolve_cycle(not_processed)
|
219
|
+
raise "cycle in task graph: #{cycle.map(&:name).sort.join(", ")}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def resolve_cycle(tasks)
|
224
|
+
chain = []
|
225
|
+
next_task = tasks.first
|
226
|
+
while true
|
227
|
+
task = next_task
|
228
|
+
chain << task
|
229
|
+
tasks.delete(next_task)
|
230
|
+
next_task = task.prerequisite_tasks.find do |dep_task|
|
231
|
+
if chain.include?(dep_task)
|
232
|
+
reject = chain.take_while { |t| t != dep_task }
|
233
|
+
return chain[reject.size..-1]
|
234
|
+
elsif tasks.include?(dep_task)
|
235
|
+
true
|
236
|
+
end
|
237
|
+
end
|
238
|
+
if !next_task
|
239
|
+
raise "something fishy while resolving a cycle in #{tasks.map(&:name).join(", ")}. Some of these packages might have added new dependencies during the task resolution, which is forbidden"
|
240
|
+
end
|
203
241
|
end
|
242
|
+
chain
|
204
243
|
end
|
205
244
|
|
206
245
|
class Worker
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Autobuild
|
2
|
+
module RakeTaskExtension
|
3
|
+
def already_invoked?
|
4
|
+
!!@already_invoked
|
5
|
+
end
|
6
|
+
|
7
|
+
def already_invoked=(value)
|
8
|
+
@already_invoked = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def disable!
|
12
|
+
@already_invoked = true
|
13
|
+
def self.needed?; false end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
class Rake::Task
|
18
|
+
include Autobuild::RakeTaskExtension
|
19
|
+
end
|
data/lib/autobuild/reporting.rb
CHANGED
@@ -1,20 +1,3 @@
|
|
1
|
-
begin
|
2
|
-
require 'rmail'
|
3
|
-
require 'rmail/serialize'
|
4
|
-
Autobuild::HAS_RMAIL = true
|
5
|
-
rescue LoadError
|
6
|
-
Autobuild::HAS_RMAIL = false
|
7
|
-
end
|
8
|
-
|
9
|
-
require 'net/smtp'
|
10
|
-
require 'socket'
|
11
|
-
require 'etc'
|
12
|
-
require 'find'
|
13
|
-
|
14
|
-
require 'autobuild/config'
|
15
|
-
require 'autobuild/exceptions'
|
16
|
-
require 'thread'
|
17
|
-
|
18
1
|
module Autobuild
|
19
2
|
class << self
|
20
3
|
attr_reader :display_lock
|
@@ -66,9 +49,11 @@ module Autobuild
|
|
66
49
|
else 0
|
67
50
|
end
|
68
51
|
|
69
|
-
|
70
|
-
|
71
|
-
|
52
|
+
if !silent?
|
53
|
+
puts "\r#{msg}#{" " * [size - msg.size, 0].max}"
|
54
|
+
if @last_progress_msg
|
55
|
+
print "#{@last_progress_msg}"
|
56
|
+
end
|
72
57
|
end
|
73
58
|
end
|
74
59
|
|
data/lib/autobuild/subcommand.rb
CHANGED
@@ -71,11 +71,6 @@ module Autobuild
|
|
71
71
|
return @processor_count
|
72
72
|
end
|
73
73
|
|
74
|
-
#No parralel build on windows yet, since CPU detection is not easy do able
|
75
|
-
if(RbConfig::CONFIG["host_os"] =~%r!(msdos|mswin|djgpp|mingw|[Ww]indows)!)
|
76
|
-
return 1
|
77
|
-
end
|
78
|
-
|
79
74
|
if File.file?('/proc/cpuinfo')
|
80
75
|
cpuinfo = File.readlines('/proc/cpuinfo')
|
81
76
|
physical_ids, core_count, processor_ids = [], [], []
|
@@ -98,7 +93,7 @@ module Autobuild
|
|
98
93
|
while (id = physical_ids.shift)
|
99
94
|
info[id] = core_count.shift
|
100
95
|
end
|
101
|
-
@processor_count = info.inject(&:+)
|
96
|
+
@processor_count = info.compact.inject(&:+)
|
102
97
|
else
|
103
98
|
@processor_count = processor_ids.size
|
104
99
|
end
|
@@ -116,6 +111,11 @@ module Autobuild
|
|
116
111
|
if !@processor_count
|
117
112
|
# Hug... What kind of system is it ?
|
118
113
|
Autobuild.message "INFO: cannot autodetect the number of CPUs on this sytem"
|
114
|
+
Autobuild.message "INFO: turning parallel builds off"
|
115
|
+
Autobuild.message "INFO: you can manually set the number of parallel build processes to N"
|
116
|
+
Autobuild.message "INFO: (and therefore turn this message off)"
|
117
|
+
Autobuild.message "INFO: with"
|
118
|
+
Autobuild.message " Autobuild.parallel_build_level = N"
|
119
119
|
@processor_count = 1
|
120
120
|
end
|
121
121
|
|
data/lib/autobuild/timestamps.rb
CHANGED
@@ -0,0 +1,164 @@
|
|
1
|
+
module Autobuild
|
2
|
+
# Utilities are post-build things that can be executed on packages
|
3
|
+
#
|
4
|
+
# Canonical examples are documentation generation and tests
|
5
|
+
class Utility
|
6
|
+
# This utility's name
|
7
|
+
attr_reader :name
|
8
|
+
# @return [Package] the package on which this utility object acts
|
9
|
+
attr_reader :package
|
10
|
+
# @return [String,nil] the reference directory for {#source_dir=}. If
|
11
|
+
# nil, will use the package's source directory
|
12
|
+
attr_accessor :source_ref_dir
|
13
|
+
|
14
|
+
def initialize(name, package)
|
15
|
+
@name = name
|
16
|
+
@package = package
|
17
|
+
@enabled = true
|
18
|
+
@source_ref_dir = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# Directory in which the utility will generate some files The
|
22
|
+
# interpretation of relative directories is package-specific. The
|
23
|
+
# default implementation interpret them as relative to the source
|
24
|
+
# directory. Set {#source_ref_dir=}
|
25
|
+
#
|
26
|
+
# @return [String,nil] the target directory, or nil if this utility does
|
27
|
+
# not need any special source directory
|
28
|
+
attr_writer :source_dir
|
29
|
+
|
30
|
+
# Absolute path to where this utulity should output its results. Returns nil if
|
31
|
+
# {source_dir} has not been set.
|
32
|
+
def source_dir
|
33
|
+
if @source_dir
|
34
|
+
File.expand_path(@source_dir, source_ref_dir || package.srcdir)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Directory in which the utility would install some files.
|
39
|
+
# If it is relative, it is interpreted as relative to the utility's
|
40
|
+
# prefix directory (Autobuild.#{name}_prefix)
|
41
|
+
#
|
42
|
+
# @return [String,nil] the target directory, or nil if this utility does
|
43
|
+
# not install anything
|
44
|
+
attr_writer :target_dir
|
45
|
+
|
46
|
+
# Absolute path to where the utility product files have to be installed.
|
47
|
+
# Returns nil if {target_dir} is not set.
|
48
|
+
#
|
49
|
+
# @return [String,nil]
|
50
|
+
def target_dir
|
51
|
+
if @target_dir
|
52
|
+
File.expand_path(@target_dir, File.expand_path(Autobuild.send("#{name}_prefix") || name, package.prefix))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Defines the task code for this utility. The given block is called and
|
57
|
+
# then the utility byproducts get installed (if any).
|
58
|
+
#
|
59
|
+
# The block is invoked in the package's source directory
|
60
|
+
#
|
61
|
+
# In general, specific package types define a meaningful #with_XXX
|
62
|
+
# method that call this method internally
|
63
|
+
#
|
64
|
+
# @return [Rake::Task]
|
65
|
+
def task(&block)
|
66
|
+
return if @task
|
67
|
+
@task = package.task task_name do
|
68
|
+
# This flag allows to disable this utility's task
|
69
|
+
# once {task} has been called
|
70
|
+
if enabled?
|
71
|
+
@installed = false
|
72
|
+
catch(:disabled) do
|
73
|
+
package.isolate_errors { call_task_block(&block) }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
package.task name => task_name
|
79
|
+
@task
|
80
|
+
end
|
81
|
+
|
82
|
+
def call_task_block
|
83
|
+
yield if block_given?
|
84
|
+
|
85
|
+
# Allow the user to install manually in the task
|
86
|
+
# block
|
87
|
+
if !@installed && target_dir
|
88
|
+
install
|
89
|
+
end
|
90
|
+
|
91
|
+
rescue Interrupt
|
92
|
+
raise
|
93
|
+
rescue ::Exception => e
|
94
|
+
if Autobuild.send("pass_#{name}_errors")
|
95
|
+
raise
|
96
|
+
else
|
97
|
+
package.warn "%s: failed to call #{name}"
|
98
|
+
if e.kind_of?(SubcommandFailed)
|
99
|
+
package.warn "%s: see #{e.logfile} for more details"
|
100
|
+
else
|
101
|
+
package.warn "%s: #{e.message}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# True if this utility would do something, and false otherwise
|
107
|
+
#
|
108
|
+
# This will return true only if a task has been by calling {task} _and_
|
109
|
+
# the utility has not been explicitly disabled by setting the {enabled}
|
110
|
+
# attribute to false
|
111
|
+
def enabled?
|
112
|
+
if !@enabled
|
113
|
+
return false
|
114
|
+
else
|
115
|
+
return source_dir && @task
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Allows to force {enabled?} to return false, regardless of whether
|
120
|
+
# {task} has been called or not
|
121
|
+
#
|
122
|
+
# This is mainly used for package types that have an e.g. documentation
|
123
|
+
# task by default, so that some packages can disable it.
|
124
|
+
attr_writer :enabled
|
125
|
+
|
126
|
+
def install
|
127
|
+
if !File.directory?(source_dir)
|
128
|
+
raise "#{source_dir} was expected to be a directory, but it is not. Check the package's #{name} generation. The generated #{name} products should be in #{source_dir}"
|
129
|
+
end
|
130
|
+
|
131
|
+
target_dir = self.target_dir
|
132
|
+
source_dir = self.source_dir
|
133
|
+
FileUtils.rm_rf target_dir
|
134
|
+
FileUtils.mkdir_p File.dirname(target_dir)
|
135
|
+
FileUtils.cp_r source_dir, target_dir
|
136
|
+
|
137
|
+
@installed = true
|
138
|
+
end
|
139
|
+
|
140
|
+
# Can be called in the block given to {task} to announce that the
|
141
|
+
# utility is to be disabled for that package. This is mainly used
|
142
|
+
# when a runtime check is necessary to know if a package can run
|
143
|
+
# this utility or not.
|
144
|
+
def disabled
|
145
|
+
throw :disabled
|
146
|
+
end
|
147
|
+
|
148
|
+
# The name of the Rake task
|
149
|
+
#
|
150
|
+
# @return [String]
|
151
|
+
def task_name
|
152
|
+
"#{package.name}-#{name}"
|
153
|
+
end
|
154
|
+
|
155
|
+
# True if the underlying package already has a task generated by this
|
156
|
+
# utility
|
157
|
+
#
|
158
|
+
# @return [Boolean]
|
159
|
+
def has_task?
|
160
|
+
!!Rake.application.lookup(task_name)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|