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.
@@ -12,7 +12,7 @@ module Autobuild
12
12
  super
13
13
  end
14
14
 
15
- def import
15
+ def import(only_local=false)
16
16
  end
17
17
 
18
18
  def prepare
@@ -17,7 +17,7 @@ module Autobuild
17
17
  use :autogen => 'autogen'
18
18
  end
19
19
 
20
- def import
20
+ def import(only_local=false)
21
21
  super
22
22
  get_provides
23
23
  end
@@ -177,7 +177,7 @@ module Autobuild
177
177
  FileUtils.rm_f genstamp
178
178
  end
179
179
 
180
- def import
180
+ def import(only_local=false)
181
181
  super
182
182
  end
183
183
 
@@ -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
+
@@ -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, initial_queue = Array.new)
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
- initial_queue.each do |t|
90
- queue[t] = 1
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 !processed.include?(candidate) && candidate.prerequisite_tasks.all? { |t| processed.include?(t) }
121
- if candidate.respond_to?(:package)
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
- roots = tasks.find_all { |t| t.prerequisite_tasks.empty? }.to_set
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.instance_variable_get(:@already_invoked) || !pending_task.needed?
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
- if state.processed.size != tasks.size
201
- with_cycle = tasks.to_set
202
- raise "cycle in task graph: #{with_cycle.map(&:name).sort.join(", ")}"
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
@@ -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
- puts "\r#{msg}#{" " * [size - msg.size, 0].max}"
70
- if @last_progress_msg
71
- print "#{@last_progress_msg}"
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
 
@@ -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
 
@@ -1,11 +1,6 @@
1
- require 'autobuild/config'
2
- require 'find'
3
- require 'rake/tasklib'
4
- require 'fileutils'
5
-
6
- STAMPFILE = "autobuild-stamp"
7
-
8
1
  module Autobuild
2
+ STAMPFILE = "autobuild-stamp"
3
+
9
4
  class << self
10
5
  # The set of global ignores for SourceTreeTask
11
6
  #
@@ -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
+