autobuild 1.3.3 → 1.4.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.
@@ -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