autobuild 1.3.3 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,11 @@
1
+ == Version 1.4.0
2
+ * cmake package handler now displays progress value
3
+ * added support for parallel builds
4
+ * added the long-awaited --force-build and --rebuild options.
5
+ The first one forces the call to all the build steps, but without deleting the
6
+ build products. The second one deletes all build products and retriggers a
7
+ full build.
8
+
1
9
  == Version 1.3.3
2
10
  * fix: changing Orogen.corba now affects packages that have already been
3
11
  declared but for which the #corba attribute has not been set explicitely to
@@ -18,6 +18,7 @@ lib/autobuild/importer.rb
18
18
  lib/autobuild/package.rb
19
19
  lib/autobuild/packages/autotools.rb
20
20
  lib/autobuild/packages/cmake.rb
21
+ lib/autobuild/packages/dummy.rb
21
22
  lib/autobuild/packages/genom.rb
22
23
  lib/autobuild/packages/import.rb
23
24
  lib/autobuild/packages/orogen.rb
data/Rakefile CHANGED
@@ -16,3 +16,13 @@ Hoe.spec 'autobuild' do
16
16
  ['utilrb', '>= 1.3.3']
17
17
  end
18
18
 
19
+ Rake.clear_tasks(/publish_docs/)
20
+ task 'publish_docs' => 'doc' do
21
+ if !system('./update_github')
22
+ raise "cannot update the gh-pages branch for GitHub"
23
+ end
24
+ if !system('git', 'push', 'origin', 'gh-pages')
25
+ raise "cannot push the documentation"
26
+ end
27
+ end
28
+
@@ -1,5 +1,5 @@
1
1
  module Autobuild
2
- VERSION = "1.3.3" unless defined? Autobuild::VERSION
2
+ VERSION = "1.4.0" unless defined? Autobuild::VERSION
3
3
  end
4
4
 
5
5
  require 'autobuild/config'
@@ -18,6 +18,7 @@ require 'autobuild/packages/genom'
18
18
  require 'autobuild/packages/import'
19
19
  require 'autobuild/packages/orogen'
20
20
  require 'autobuild/packages/pkgconfig'
21
+ require 'autobuild/packages/dummy'
21
22
  require 'autobuild/pkgconfig'
22
23
  require 'autobuild/reporting'
23
24
  require 'autobuild/subcommand'
@@ -18,6 +18,8 @@ end
18
18
  # debug:: more verbose than 'verbose': displays Rake's debugging output
19
19
  # do_update:: if we should update the packages
20
20
  # do_build:: if we should build the packages
21
+ # do_forced_build:: if we should forcefully trigger all the packages build phases
22
+ # do_rebuild:: if we should cleanly rebuild every packages
21
23
  # do_doc:: if we should produce the documentation
22
24
  # doc_errors:: if errors during the documentation generation are treated as errors
23
25
  # daemonize:: if the build should go into daemon mode (only if the daemons gem is available)
@@ -30,7 +32,7 @@ end
30
32
  module Autobuild
31
33
  class << self
32
34
  %w{ nice srcdir prefix
33
- verbose debug do_update do_build only_doc do_doc doc_errors
35
+ verbose debug do_update do_build do_rebuild do_forced_build only_doc do_doc doc_errors
34
36
  daemonize clean_log packages default_packages
35
37
  doc_prefix keep_oldlogs}.each do |name|
36
38
  attr_accessor name
@@ -48,7 +50,7 @@ module Autobuild
48
50
  end
49
51
  DEFAULT_OPTIONS = { :nice => 0,
50
52
  :srcdir => Dir.pwd, :prefix => Dir.pwd, :logdir => nil,
51
- :verbose => false, :debug => false, :do_build => true, :do_update => true,
53
+ :verbose => false, :debug => false, :do_build => true, :do_forced_build => false, :do_rebuild => false, :do_update => true,
52
54
  :daemonize => false, :packages => [], :default_packages => [],
53
55
  :only_doc => false, :do_doc => true, :doc_errors => false,
54
56
  :doc_prefix => 'doc', :keep_oldlogs => false }
@@ -157,6 +159,8 @@ module Autobuild
157
159
  end
158
160
  opts.on("--no-update", "update already checked-out sources") do |@do_update| end
159
161
  opts.on("--no-build", "only prepare packages, do not build them") do |@do_build| end
162
+ opts.on("--forced-build", "force the trigger of all the build commands") do |@do_forced_build| end
163
+ opts.on("--rebuild", "clean and rebuild") do |@do_forced_build| end
160
164
  opts.on("--only-doc", "only generate documentation") do |@only_doc| end
161
165
  opts.on("--no-doc", "don't generate documentation") do |@do_doc| end
162
166
  opts.on("--doc-errors", "treat documentation failure as error") do |@doc_errors| end
@@ -211,6 +215,19 @@ module Autobuild
211
215
  end
212
216
  end
213
217
 
218
+ if Autobuild.do_rebuild
219
+ packages.each do |pkg_name|
220
+ Autobuild::Package[pkg_name].prepare_for_rebuild
221
+ end
222
+ # And delete the prefix !
223
+ FileUtils.rm_rf Autobuild.prefix
224
+
225
+ elsif Autobuild.do_forced_build
226
+ packages.each do |pkg_name|
227
+ Autobuild::Package[pkg_name].prepare_for_forced_build
228
+ end
229
+ end
230
+
214
231
  if Autobuild.only_doc
215
232
  phases = ['doc']
216
233
  else
@@ -50,6 +50,17 @@ module Autobuild
50
50
  Autobuild.update_environment(prefix)
51
51
  end
52
52
 
53
+ def prepare_for_forced_build
54
+ FileUtils.rm_f buildstamp
55
+ FileUtils.rm_f configurestamp
56
+ end
57
+
58
+ def prepare_for_rebuild
59
+ if File.exists?(builddir) && builddir != srcdir
60
+ FileUtils.rm_rf builddir
61
+ end
62
+ end
63
+
53
64
  def depends_on(*packages)
54
65
  super
55
66
  stamps = packages.collect { |p| Package[p.to_s].installstamp }
@@ -83,6 +83,7 @@ module Autobuild
83
83
  def initialize(spec)
84
84
  @dependencies = Array.new
85
85
  @provides = Array.new
86
+ @parallel_build_level = nil
86
87
 
87
88
  if Hash === spec
88
89
  name, depends = spec.to_a.first
@@ -127,6 +128,20 @@ module Autobuild
127
128
  @spec_dependencies = depends
128
129
  end
129
130
 
131
+ # Called before a forced build. It should remove all the timestamp and
132
+ # target files so that all the build phases of this package gets
133
+ # retriggered. However, it should not clean the build products.
134
+ def prepare_for_forced_build
135
+ if File.exists?(installstamp)
136
+ FileUtils.rm_f installstamp
137
+ end
138
+ end
139
+
140
+ # Called when the user asked for a full rebuild. It should delete the
141
+ # build products so that a full build is retriggered.
142
+ def prepare_for_rebuild
143
+ end
144
+
130
145
  # Call the importer if there is one. Autodetection of "provides" should
131
146
  # be done there as well. See the documentation of Autobuild::Package for
132
147
  # more information.
@@ -279,6 +294,31 @@ module Autobuild
279
294
  def self.[](name)
280
295
  @@packages[name.to_s] || @@provides[name.to_s]
281
296
  end
297
+
298
+ # Sets the level of parallelism authorized while building this package
299
+ #
300
+ # See #parallel_build_level and Autobuild.parallel_build_level for more
301
+ # information.
302
+ #
303
+ # Note that not all package types use this value
304
+ def parallel_build_level=(value)
305
+ @parallel_build_level = Integer(value)
306
+ end
307
+
308
+ # Returns the level of parallelism authorized during the build for this
309
+ # particular package. If not set, defaults to the system-wide option
310
+ # (Autobuild.parallel_build_level and Autobuild.parallel_build_level=).
311
+ #
312
+ # The default value is the number of CPUs on this system.
313
+ def parallel_build_level
314
+ if @parallel_build_level.nil?
315
+ Autobuild.parallel_build_level
316
+ elsif !@parallel_build_level || @parallel_build_level <= 0
317
+ 1
318
+ else
319
+ @parallel_build_level
320
+ end
321
+ end
282
322
  end
283
323
 
284
324
  def self.package_set(spec)
@@ -62,7 +62,7 @@ module Autobuild
62
62
  doc_task do
63
63
  Dir.chdir(builddir) do
64
64
  Autobuild.progress "generating documentation for #{name}"
65
- Subprocess.run(name, 'doc', Autobuild.tool(:make), target)
65
+ Subprocess.run(name, 'doc', Autobuild.tool(:make), "-j#{parallel_build_level}", target)
66
66
  yield if block_given?
67
67
  end
68
68
  end
@@ -233,7 +233,7 @@ module Autobuild
233
233
  Dir.chdir(builddir) {
234
234
  Autobuild.progress "building #{name}"
235
235
  Subprocess.run(name, 'build', './config.status')
236
- Subprocess.run(name, 'build', Autobuild.tool(:make))
236
+ Subprocess.run(name, 'build', Autobuild.tool(:make), "-j#{parallel_build_level}")
237
237
  }
238
238
  Autobuild.touch_stamp(buildstamp)
239
239
  end
@@ -242,7 +242,7 @@ module Autobuild
242
242
  def install
243
243
  Dir.chdir(builddir) {
244
244
  Autobuild.progress "installing #{name}"
245
- Subprocess.run(name, 'install', Autobuild.tool(:make), 'install')
245
+ Subprocess.run(name, 'install', Autobuild.tool(:make), "-j#{parallel_build_level}", 'install')
246
246
  }
247
247
  Autobuild.touch_stamp(installstamp)
248
248
  Autobuild.update_environment(prefix)
@@ -40,7 +40,7 @@ module Autobuild
40
40
  doc_task do
41
41
  Dir.chdir(builddir) do
42
42
  Autobuild.progress "generating documentation for #{name}"
43
- Subprocess.run(name, 'doc', Autobuild.tool(:make), target)
43
+ Subprocess.run(name, 'doc', Autobuild.tool(:make), "-j#{parallel_build_level}", target)
44
44
  yield if block_given?
45
45
  end
46
46
  end
@@ -134,11 +134,15 @@ module Autobuild
134
134
  # Do the build in builddir
135
135
  def build
136
136
  Dir.chdir(builddir) do
137
- Autobuild.progress "building #{name}"
137
+ Autobuild.progress_with_value "building #{name}"
138
138
  if always_reconfigure || !File.file?('Makefile')
139
139
  Subprocess.run(name, 'build', Autobuild.tool(:cmake), '.')
140
140
  end
141
- Subprocess.run(name, 'build', Autobuild.tool(:make))
141
+ Subprocess.run(name, 'build', Autobuild.tool(:make), "-j#{parallel_build_level}") do |line|
142
+ if line =~ /\[\s+(\d+)%\]/
143
+ Autobuild.progress_value Integer($1)
144
+ end
145
+ end
142
146
  end
143
147
  Autobuild.touch_stamp(buildstamp)
144
148
  end
@@ -147,7 +151,7 @@ module Autobuild
147
151
  def install
148
152
  Dir.chdir(builddir) do
149
153
  Autobuild.progress "installing #{name}"
150
- Subprocess.run(name, 'install', Autobuild.tool(:make), 'install')
154
+ Subprocess.run(name, 'build', Autobuild.tool(:make), "-j#{parallel_build_level}", 'install')
151
155
  Autobuild.update_environment prefix
152
156
  end
153
157
  super
@@ -0,0 +1,31 @@
1
+ module Autobuild
2
+ def self.dummy(spec)
3
+ ImporterPackage.new(spec)
4
+ end
5
+
6
+ class DummyPackage < Package
7
+ def installstamp
8
+ "#{srcdir}/#{STAMPFILE}"
9
+ end
10
+
11
+ def initialize(*args)
12
+ super
13
+ end
14
+
15
+ def import
16
+ end
17
+
18
+ def prepare
19
+ %w{import prepare build doc}.each do |phase|
20
+ Rake.task("#{name}-#{phase}")
21
+ t = Rake::Task["#{name}-#{phase}"]
22
+ def t.needed?; false end
23
+ end
24
+ Rake.task(installstamp)
25
+ t = Rake::Task[installstamp]
26
+ def t.needed?; false end
27
+ end
28
+ end
29
+ end
30
+
31
+
@@ -16,7 +16,23 @@ require 'autobuild/exceptions'
16
16
 
17
17
  module Autobuild
18
18
  def self.progress(msg)
19
- puts " #{msg}"
19
+ if @last_msg
20
+ progress_value(100)
21
+ puts
22
+ end
23
+ @last_msg = nil
24
+ puts " #{msg}"
25
+ end
26
+ def self.progress_with_value(msg)
27
+ if @last_msg
28
+ progress_value(100)
29
+ puts
30
+ end
31
+ @last_msg = msg
32
+ print " #{msg}"
33
+ end
34
+ def self.progress_value(value)
35
+ print "\r #{@last_msg} (#{value}%)"
20
36
  end
21
37
 
22
38
  ## The reporting module provides the framework
@@ -1,5 +1,59 @@
1
1
  require 'autobuild/exceptions'
2
2
  require 'autobuild/reporting'
3
+ require 'fcntl'
4
+
5
+ module Autobuild
6
+ @parallel_build_level = nil
7
+ class << self
8
+ # Sets the level of parallelism during the build
9
+ #
10
+ # See #parallel_build_level for detailed information
11
+ attr_writer :parallel_build_level
12
+
13
+ # Returns the number of processes that can run in parallel during the
14
+ # build. This is a system-wide value that can be overriden in a
15
+ # per-package fashion by using Package#parallel_build_level.
16
+ #
17
+ # If not set, defaults to the number of CPUs on the system
18
+ #
19
+ # See also #parallel_build_level=
20
+ def parallel_build_level
21
+ if @parallel_build_level.nil?
22
+ # No user-set value, return the count of processors on this
23
+ # machine
24
+ autodetect_processor_count
25
+ elsif !@parallel_build_level || @parallel_build_level <= 0
26
+ 1
27
+ else
28
+ @parallel_build_level
29
+ end
30
+ end
31
+ end
32
+
33
+ # Returns the number of CPUs present on this system
34
+ def self.autodetect_processor_count
35
+ if @processor_count
36
+ return @processor_count
37
+ end
38
+
39
+ if File.file?('/sys/devices/system/cpu/present')
40
+ range = File.read('/sys/devices/system/cpu/present').
41
+ chomp
42
+
43
+ @processor_count = Integer(range.split('-').last) + 1
44
+ elsif File.file?('/proc/cpuinfo')
45
+ # Just count the numer of processor: \d lines
46
+ @processor_count = File.readlines('/proc/cpuinfo').
47
+ find_all { |l| l =~ /^processor\s+:\s+\d+$/ }.
48
+ count
49
+ else
50
+ # Hug... What kind of system is it ?
51
+ STDERR.puts "INFO: cannot autodetect the number of CPUs on this sytem"
52
+ @processor_count = 1
53
+ end
54
+ end
55
+ end
56
+
3
57
 
4
58
  module Autobuild::Subprocess
5
59
  class Failed < Exception
@@ -12,6 +66,8 @@ module Autobuild::Subprocess
12
66
  CONTROL_COMMAND_NOT_FOUND = 1
13
67
  CONTROL_UNEXPECTED = 2
14
68
  def self.run(target, phase, *command)
69
+ STDOUT.sync = true
70
+
15
71
  # Filter nil and empty? in command
16
72
  command.reject! { |o| o.nil? || (o.respond_to?(:empty?) && o.empty?) }
17
73
  command.collect! { |o| o.to_s }
@@ -41,17 +97,29 @@ module Autobuild::Subprocess
41
97
  logfile.puts " #{command.join(" ")}"
42
98
  logfile.puts
43
99
  logfile.flush
100
+ logfile.sync = true
44
101
 
45
- pread, pwrite = IO.pipe # to feed subprocess stdin
102
+ if !input_streams.empty?
103
+ pread, pwrite = IO.pipe # to feed subprocess stdin
104
+ end
105
+ if block_given? # the caller wants the stdout/stderr stream of the process, git it to him
106
+ outread, outwrite = IO.pipe
107
+ outread.sync = true
108
+ outwrite.sync = true
109
+ end
46
110
  cread, cwrite = IO.pipe # to control that exec goes well
47
111
 
112
+ cwrite.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
113
+
48
114
  pid = fork do
49
115
  cwrite.sync = true
50
116
  begin
51
117
  Process.setpriority(Process::PRIO_PROCESS, 0, Autobuild.nice)
52
- if Autobuild.verbose
53
- $stderr.dup.reopen(logfile.dup)
54
- $stdout.dup.reopen(logfile.dup)
118
+
119
+ if outwrite
120
+ outread.close
121
+ $stderr.reopen(outwrite.dup)
122
+ $stdout.reopen(outwrite.dup)
55
123
  else
56
124
  $stderr.reopen(logfile.dup)
57
125
  $stdout.reopen(logfile.dup)
@@ -73,17 +141,19 @@ module Autobuild::Subprocess
73
141
  end
74
142
 
75
143
  # Feed the input
76
- pread.close
77
- begin
78
- input_streams.each do |infile|
79
- File.open(infile) do |instream|
80
- instream.each_line { |line| pwrite.write(line) }
144
+ if !input_streams.empty?
145
+ pread.close
146
+ begin
147
+ input_streams.each do |infile|
148
+ File.open(infile) do |instream|
149
+ instream.each_line { |line| pwrite.write(line) }
150
+ end
81
151
  end
152
+ rescue Errno::ENOENT => e
153
+ raise Failed.new, "cannot open input files: #{e.message}"
82
154
  end
83
- rescue Errno::ENOENT => e
84
- raise Failed.new, "cannot open input files: #{e.message}"
155
+ pwrite.close
85
156
  end
86
- pwrite.close
87
157
 
88
158
  # Get control status
89
159
  cwrite.close
@@ -98,6 +168,22 @@ module Autobuild::Subprocess
98
168
  end
99
169
  end
100
170
 
171
+ # If the caller asked for process output, provide it to him
172
+ # line-by-line.
173
+ if outread
174
+ outwrite.close
175
+ outread.each_line do |line|
176
+ if Autobuild.verbose
177
+ STDOUT.print line
178
+ end
179
+ logfile.puts line
180
+ if block_given?
181
+ yield(line)
182
+ end
183
+ end
184
+ outread.close
185
+ end
186
+
101
187
  childpid, childstatus = Process.wait2(pid)
102
188
  childstatus
103
189
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: autobuild
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Joyeux
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-20 00:00:00 +02:00
12
+ date: 2009-10-25 01:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -111,6 +111,7 @@ files:
111
111
  - lib/autobuild/package.rb
112
112
  - lib/autobuild/packages/autotools.rb
113
113
  - lib/autobuild/packages/cmake.rb
114
+ - lib/autobuild/packages/dummy.rb
114
115
  - lib/autobuild/packages/genom.rb
115
116
  - lib/autobuild/packages/import.rb
116
117
  - lib/autobuild/packages/orogen.rb