realityforge-buildr 1.5.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE +176 -0
  4. data/NOTICE +26 -0
  5. data/README.md +3 -0
  6. data/Rakefile +50 -0
  7. data/addon/buildr/checkstyle-report.xsl +104 -0
  8. data/addon/buildr/checkstyle.rb +254 -0
  9. data/addon/buildr/git_auto_version.rb +36 -0
  10. data/addon/buildr/gpg.rb +90 -0
  11. data/addon/buildr/gwt.rb +413 -0
  12. data/addon/buildr/jacoco.rb +161 -0
  13. data/addon/buildr/pmd.rb +185 -0
  14. data/addon/buildr/single_intermediate_layout.rb +71 -0
  15. data/addon/buildr/spotbugs.rb +265 -0
  16. data/addon/buildr/top_level_generate_dir.rb +37 -0
  17. data/addon/buildr/wsgen.rb +192 -0
  18. data/bin/buildr +20 -0
  19. data/buildr.gemspec +61 -0
  20. data/lib/buildr.rb +86 -0
  21. data/lib/buildr/core/application.rb +705 -0
  22. data/lib/buildr/core/assets.rb +96 -0
  23. data/lib/buildr/core/build.rb +587 -0
  24. data/lib/buildr/core/common.rb +167 -0
  25. data/lib/buildr/core/compile.rb +599 -0
  26. data/lib/buildr/core/console.rb +124 -0
  27. data/lib/buildr/core/doc.rb +275 -0
  28. data/lib/buildr/core/environment.rb +128 -0
  29. data/lib/buildr/core/filter.rb +405 -0
  30. data/lib/buildr/core/help.rb +114 -0
  31. data/lib/buildr/core/progressbar.rb +161 -0
  32. data/lib/buildr/core/project.rb +994 -0
  33. data/lib/buildr/core/test.rb +776 -0
  34. data/lib/buildr/core/transports.rb +456 -0
  35. data/lib/buildr/core/util.rb +77 -0
  36. data/lib/buildr/ide/idea.rb +1664 -0
  37. data/lib/buildr/java/commands.rb +230 -0
  38. data/lib/buildr/java/compiler.rb +85 -0
  39. data/lib/buildr/java/custom_pom.rb +300 -0
  40. data/lib/buildr/java/doc.rb +62 -0
  41. data/lib/buildr/java/packaging.rb +393 -0
  42. data/lib/buildr/java/pom.rb +191 -0
  43. data/lib/buildr/java/test_result.rb +54 -0
  44. data/lib/buildr/java/tests.rb +111 -0
  45. data/lib/buildr/packaging/archive.rb +586 -0
  46. data/lib/buildr/packaging/artifact.rb +1113 -0
  47. data/lib/buildr/packaging/artifact_namespace.rb +1010 -0
  48. data/lib/buildr/packaging/artifact_search.rb +138 -0
  49. data/lib/buildr/packaging/package.rb +237 -0
  50. data/lib/buildr/packaging/version_requirement.rb +189 -0
  51. data/lib/buildr/packaging/zip.rb +189 -0
  52. data/lib/buildr/packaging/ziptask.rb +387 -0
  53. data/lib/buildr/version.rb +18 -0
  54. data/rakelib/release.rake +99 -0
  55. data/spec/addon/checkstyle_spec.rb +58 -0
  56. data/spec/core/application_spec.rb +576 -0
  57. data/spec/core/build_spec.rb +922 -0
  58. data/spec/core/common_spec.rb +670 -0
  59. data/spec/core/compile_spec.rb +656 -0
  60. data/spec/core/console_spec.rb +65 -0
  61. data/spec/core/doc_spec.rb +194 -0
  62. data/spec/core/extension_spec.rb +200 -0
  63. data/spec/core/project_spec.rb +736 -0
  64. data/spec/core/test_spec.rb +1131 -0
  65. data/spec/core/transport_spec.rb +452 -0
  66. data/spec/core/util_spec.rb +154 -0
  67. data/spec/ide/idea_spec.rb +1952 -0
  68. data/spec/java/commands_spec.rb +79 -0
  69. data/spec/java/compiler_spec.rb +274 -0
  70. data/spec/java/custom_pom_spec.rb +165 -0
  71. data/spec/java/doc_spec.rb +55 -0
  72. data/spec/java/packaging_spec.rb +786 -0
  73. data/spec/java/pom_spec.rb +162 -0
  74. data/spec/java/test_coverage_helper.rb +257 -0
  75. data/spec/java/tests_spec.rb +224 -0
  76. data/spec/packaging/archive_spec.rb +686 -0
  77. data/spec/packaging/artifact_namespace_spec.rb +757 -0
  78. data/spec/packaging/artifact_spec.rb +1351 -0
  79. data/spec/packaging/packaging_helper.rb +63 -0
  80. data/spec/packaging/packaging_spec.rb +690 -0
  81. data/spec/sandbox.rb +166 -0
  82. data/spec/spec_helpers.rb +420 -0
  83. data/spec/version_requirement_spec.rb +145 -0
  84. data/spec/xpath_matchers.rb +123 -0
  85. metadata +295 -0
@@ -0,0 +1,167 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+ module Buildr #:nodoc:
17
+
18
+ # :call-seq:
19
+ # struct(hash) => Struct
20
+ #
21
+ # Convenience method for creating an anonymous Struct.
22
+ #
23
+ # For example:
24
+ # COMMONS = struct(
25
+ # :collections =>'commons-collections:commons-collections:jar:3.1',
26
+ # :lang =>'commons-lang:commons-lang:jar:2.1',
27
+ # :logging =>'commons-logging:commons-logging:jar:1.0.3',
28
+ # )
29
+ #
30
+ # compile.with COMMONS.logging
31
+ def struct(hash)
32
+ Struct.new(nil, *hash.keys).new(*hash.values)
33
+ end
34
+
35
+ # :call-seq:
36
+ # write(name, content)
37
+ # write(name) { ... }
38
+ #
39
+ # Write the contents into a file. The second form calls the block and writes the result.
40
+ #
41
+ # For example:
42
+ # write 'TIMESTAMP', Time.now
43
+ # write('TIMESTAMP') { Time.now }
44
+ #
45
+ # Yields to the block before writing the file, so you can chain read and write together.
46
+ # For example:
47
+ # write('README') { read('README').sub("${build}", Time.now) }
48
+ def write(name, content = nil)
49
+ filename = name.to_s
50
+ mkpath File.dirname(filename)
51
+ content = yield if block_given?
52
+ File.open(filename, 'wb') { |file| file.write content.to_s }
53
+ content.to_s
54
+ end
55
+
56
+ # :call-seq:
57
+ # read(args) => string
58
+ # read(args) { |string| ... } => result
59
+ #
60
+ # Reads and returns the contents of a file. The second form yields to the block and returns
61
+ # the result of the block. The args passed to read are passed on to File.open.
62
+ #
63
+ # For example:
64
+ # puts read('README')
65
+ # read('README') { |text| puts text }
66
+ def read(*args)
67
+ args[0] = args[0].to_s
68
+ contents = File.open(*args) { |f| f.read }
69
+ if block_given?
70
+ yield contents
71
+ else
72
+ contents
73
+ end
74
+ end
75
+
76
+ # :call-seq:
77
+ # download(url_or_uri) => task
78
+ # download(path=>url_or_uri) =>task
79
+ #
80
+ # Create a task that will download a file from a URL.
81
+ #
82
+ # Takes a single argument, a hash with one pair. The key is the file being
83
+ # created, the value if the URL to download. The task executes only if the
84
+ # file does not exist; the URL is not checked for updates.
85
+ #
86
+ # The task will show download progress on the console; if there are MD5/SHA1
87
+ # checksums on the server it will verify the download before saving it.
88
+ #
89
+ # For example:
90
+ # download 'image.jpg'=>'http://example.com/theme/image.jpg'
91
+ def download(args)
92
+ args = URI.parse(args) if String === args
93
+ if URI === args
94
+ # Given only a download URL, download into a temporary file.
95
+ # You can infer the file from task name.
96
+ temp = Tempfile.open(File.basename(args.to_s))
97
+ file(temp.path).tap do |task|
98
+ # Since temporary file exists, force a download.
99
+ class << task ; def needed? ; true ; end ; end
100
+ task.sources << args
101
+ task.enhance { args.download temp }
102
+ end
103
+ else
104
+ # Download to a file created by the task.
105
+ fail unless args.keys.size == 1
106
+ uri = URI.parse(args.values.first.to_s)
107
+ key = args.keys.first
108
+ if key.is_a?(Buildr::Artifact)
109
+ key.define_singleton_method(:source) do
110
+ uri
111
+ end
112
+ key.define_singleton_method(:download) do
113
+ trace "Downloading #{to_spec}"
114
+ begin
115
+ download_artifact(uri)
116
+ true
117
+ rescue URI::NotFoundError
118
+ false
119
+ rescue Exception => error
120
+ info error
121
+ trace error.backtrace.join("\n")
122
+ false
123
+ end || fail_download([])
124
+ end
125
+ key
126
+ else
127
+ file(key.to_s).tap do |task|
128
+ task.sources << uri
129
+ task.enhance { uri.download task.name }
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ # A file task that concatenates all its prerequisites to create a new file.
136
+ #
137
+ # For example:
138
+ # concat("master.sql"=>["users.sql", "orders.sql", reports.sql"]
139
+ #
140
+ # See also Buildr#concat.
141
+ class ConcatTask < Rake::FileTask
142
+ def initialize(*args) #:nodoc:
143
+ super
144
+ enhance do |task|
145
+ content = prerequisites.inject("") do |content, prereq|
146
+ content << File.read(prereq.to_s) if File.exists?(prereq) && !File.directory?(prereq)
147
+ content
148
+ end
149
+ File.open(task.name, "wb") { |file| file.write content }
150
+ end
151
+ end
152
+ end
153
+
154
+ # :call-seq:
155
+ # concat(target=>files) => task
156
+ #
157
+ # Creates and returns a file task that concatenates all its prerequisites to create
158
+ # a new file. See #ConcatTask.
159
+ #
160
+ # For example:
161
+ # concat("master.sql"=>["users.sql", "orders.sql", reports.sql"]
162
+ def concat(args)
163
+ file, arg_names, deps = Buildr.application.resolve_args([args])
164
+ ConcatTask.define_task(File.expand_path(file)=>deps)
165
+ end
166
+
167
+ end
@@ -0,0 +1,599 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+ module Buildr #:nodoc:
17
+
18
+ # The underlying compiler used by CompileTask.
19
+ # To add a new compiler, extend Compiler::Base and add your compiler using:
20
+ # Buildr::Compiler.add MyCompiler
21
+ module Compiler
22
+
23
+ class << self
24
+
25
+ # Returns true if the specified compiler exists.
26
+ def has?(name)
27
+ compilers.any? { |compiler| compiler.to_sym == name.to_sym }
28
+ end
29
+
30
+ # Select a compiler by its name.
31
+ def select(name)
32
+ compilers.detect { |compiler| compiler.to_sym == name.to_sym }
33
+ end
34
+
35
+ # Adds a compiler to the list of supported compiler.
36
+ #
37
+ # For example:
38
+ # Buildr::Compiler << Buildr::Javac
39
+ def add(compiler)
40
+ @compilers ||= []
41
+ @compilers |= [compiler]
42
+ end
43
+ alias :<< :add
44
+
45
+ # Returns a list of available compilers.
46
+ def compilers
47
+ @compilers ||= []
48
+ end
49
+
50
+ private
51
+
52
+ # Only used by our specs.
53
+ def compilers=(compilers)
54
+ @compilers = compilers
55
+ end
56
+ end
57
+
58
+ # Base class for all compilers, with common functionality. Extend and over-ride as you see fit
59
+ # (see Javac as an example).
60
+ class Base #:nodoc:
61
+
62
+ class << self
63
+
64
+ # The compiler's identifier (e.g. :javac). Inferred from the class name.
65
+ def to_sym
66
+ @symbol ||= name.split('::').last.downcase.to_sym
67
+ end
68
+
69
+ # The compiled language (e.g. :java).
70
+ attr_reader :language
71
+ # Source directories to use if none were specified (e.g. 'java'). Defaults to #language.
72
+ attr_reader :sources
73
+ # Extension for source files (e.g. 'java'). Defaults to language.
74
+ attr_reader :source_ext
75
+ # The target path (e.g. 'classes')
76
+ attr_reader :target
77
+ # Extension for target files (e.g. 'class').
78
+ attr_reader :target_ext
79
+ # The default packaging type (e.g. :jar).
80
+ attr_reader :packaging
81
+
82
+ # Returns true if this compiler applies to any source code found in the listed source
83
+ # directories. For example, Javac returns true if any of the source directories contains
84
+ # a .java file. The default implementation looks to see if there are any files in the
85
+ # specified path with the extension #source_ext.
86
+ def applies_to?(project, task)
87
+ paths = task.sources + [sources].flatten.map { |src| Array(project.path_to(:source, task.usage, src.to_sym)) }
88
+ paths.flatten!
89
+
90
+ paths.each { |path|
91
+ Find.find(path) {|found|
92
+ if (!File.directory?(found)) && found.match(/.*\.#{Array(source_ext).join('|')}/)
93
+ return true
94
+ end
95
+ } if File.exist? path.to_s
96
+ }
97
+ false
98
+ end
99
+
100
+ # Implementations can use this method to specify various compiler attributes.
101
+ # For example:
102
+ # specify :language=>:java, :target=>'classes', :target_ext=>'class', :packaging=>:jar
103
+ def specify(attrs)
104
+ attrs[:sources] ||= attrs[:language].to_s
105
+ attrs[:source_ext] ||= attrs[:language].to_s
106
+ attrs.each { |name, value| instance_variable_set("@#{name}", value) }
107
+ end
108
+
109
+ # Returns additional dependencies required by this language.
110
+ def dependencies
111
+ []
112
+ end
113
+
114
+ end
115
+
116
+ # Construct a new compiler with the specified options. Note that options may
117
+ # change before the compiler is run.
118
+ def initialize(project, options)
119
+ @project = project
120
+ @options = options
121
+ end
122
+
123
+ # Options for this compiler.
124
+ attr_reader :options
125
+
126
+ # Determines if the compiler needs to run by checking if the target files exist,
127
+ # and if any source files or dependencies are newer than corresponding target files.
128
+ def needed?(sources, target, dependencies)
129
+ map = compile_map(sources, target)
130
+ return false if map.empty?
131
+ return true unless File.exist?(target.to_s)
132
+ source_files_not_yet_compiled = map.select { |source, target| !File.exist?(target) }.to_a
133
+ trace "Compile needed because source file #{source_files_not_yet_compiled[0][0]} has no corresponding #{source_files_not_yet_compiled[0][1]}" unless source_files_not_yet_compiled.empty?
134
+ return true if map.any? { |source, target| !File.exist?(target) || File.stat(source).mtime > File.stat(target).mtime }
135
+ oldest = map.map { |source, target| File.stat(target).mtime }.min
136
+ return dependencies.any? { |path| file(path).timestamp > oldest }
137
+ end
138
+
139
+ # Compile all files lists in sources (files and directories) into target using the
140
+ # specified dependencies.
141
+ def compile(sources, target, dependencies)
142
+ raise 'Not implemented'
143
+ end
144
+
145
+ # Returns additional dependencies required by this language.
146
+ def dependencies
147
+ self.class.dependencies
148
+ end
149
+
150
+ protected
151
+
152
+ # Use this to complain about CompileTask options not supported by this compiler.
153
+ #
154
+ # For example:
155
+ # def compile(files, task)
156
+ # check_options task, OPTIONS
157
+ # . . .
158
+ # end
159
+ def check_options(options, *supported)
160
+ unsupported = options.to_hash.keys - supported.flatten
161
+ raise ArgumentError, "No such option: #{unsupported.join(' ')}" unless unsupported.empty?
162
+ end
163
+
164
+ # Expands a list of source directories/files into a list of files that have the #source_ext extension.
165
+ def files_from_sources(sources)
166
+ ext_glob = Array(self.class.source_ext).join(',')
167
+ sources.flatten.map { |source| File.directory?(source) ? FileList["#{source}/**/*.{#{ext_glob}}"] : source }.
168
+ flatten.reject { |file| File.directory?(file) }.map { |file| File.expand_path(file) }.uniq
169
+ end
170
+
171
+ # The compile map is a hash that associates source files with target files based
172
+ # on a list of source directories and target directory. The compile task uses this
173
+ # to determine if there are source files to compile, and which source files to compile.
174
+ # The default method maps all files in the source directories with #source_ext into
175
+ # paths in the target directory with #target_ext (e.g. 'source/foo.java'=>'target/foo.class').
176
+ def compile_map(sources, target)
177
+ target_ext = self.class.target_ext
178
+ ext_glob = Array(self.class.source_ext).join(',')
179
+ sources.flatten.map{|f| File.expand_path(f)}.inject({}) do |map, source|
180
+ if File.directory?(source)
181
+ FileList["#{source}/**/*.{#{ext_glob}}"].reject { |file| File.directory?(file) }.
182
+ each { |file| map[file] = File.join(target, Util.relative_path(file, source).ext(target_ext)) }
183
+ else
184
+ # try to extract package name from .java files
185
+ if %w(.java).include? File.extname(source)
186
+ package = findFirst(source, /^\s*package\s+([^\s;]+)\s*;?\s*/)
187
+ map[source] = package ? File.join(target, package[1].gsub('.', '/'), File.basename(source).ext(target_ext)) : target
188
+ elsif
189
+ map[source] = target
190
+ end
191
+ end
192
+ map
193
+ end
194
+ end
195
+
196
+ private
197
+
198
+ def findFirst(file, pattern)
199
+ match = nil
200
+ File.open(file, "r") do |infile|
201
+ while (line = infile.gets)
202
+ match = line.match(pattern)
203
+ break if match
204
+ end
205
+ end
206
+ match
207
+ end
208
+
209
+ end
210
+ end
211
+
212
+
213
+ # Compile task.
214
+ #
215
+ # Attempts to determine which compiler to use based on the project layout, for example,
216
+ # uses the Javac compiler if it finds any .java files in src/main/java. You can also
217
+ # select the compiler explicitly:
218
+ # compile.using(:scalac)
219
+ #
220
+ # Accepts multiple source directories that are invoked as prerequisites before compilation.
221
+ # You can pass a task as a source directory:
222
+ # compile.from(apt)
223
+ #
224
+ # Likewise, dependencies are invoked before compiling. All dependencies are evaluated as
225
+ # #artifacts, so you can pass artifact specifications and even projects:
226
+ # compile.with('module1.jar', 'log4j:log4j:jar:1.0', project('foo'))
227
+ #
228
+ # Creates a file task for the target directory, so executing that task as a dependency will
229
+ # execute the compile task first.
230
+ #
231
+ # Compiler options are inherited form a parent task, e.g. the foo:bar:compile task inherits
232
+ # its options from the foo:compile task. Even if foo is an empty project that does not compile
233
+ # any classes itself, you can use it to set compile options for all its sub-projects.
234
+ #
235
+ # Normally, the project will take care of setting the source and target directory, and you
236
+ # only need to set options and dependencies. See Project#compile.
237
+ class CompileTask < Rake::Task
238
+
239
+ def initialize(*args) #:nodoc:
240
+ super
241
+ parent_task = Project.parent_task(name)
242
+ inherit = lambda { |hash, key| parent_task.options[key] } if parent_task.respond_to?(:options)
243
+ @options = OpenObject.new &inherit
244
+ @sources = FileList[]
245
+ @dependencies = FileList[]
246
+
247
+ enhance do |task|
248
+ unless sources.empty?
249
+ raise 'No compiler selected and can\'t determine which compiler to use' unless compiler
250
+ raise 'No target directory specified' unless target
251
+ mkpath target.to_s
252
+ info "Compiling #{task.name.gsub(/:[^:]*$/, '')} into #{target.to_s}"
253
+ @compiler.compile(sources.map(&:to_s), target.to_s, dependencies.map(&:to_s))
254
+ # By touching the target we let other tasks know we did something,
255
+ # and also prevent recompiling again for dependencies.
256
+ touch target.to_s
257
+ end
258
+ end
259
+ end
260
+
261
+ # Source directories.
262
+ attr_accessor :sources
263
+
264
+ # :call-seq:
265
+ # from(*sources) => self
266
+ #
267
+ # Adds source directories and files to compile, and returns self.
268
+ #
269
+ # For example:
270
+ # compile.from('src/java').into('classes').with('module1.jar')
271
+ def from(*sources)
272
+ @sources |= sources.flatten
273
+ guess_compiler if @compiler.nil? && sources.flatten.any? { |source| File.exist?(source.to_s) }
274
+ self
275
+ end
276
+
277
+ # Compilation dependencies.
278
+ attr_accessor :dependencies
279
+
280
+ # :call-seq:
281
+ # with(*artifacts) => self
282
+ #
283
+ # Adds files and artifacts as dependencies, and returns self.
284
+ #
285
+ # Calls #artifacts on the arguments, so you can pass artifact specifications,
286
+ # tasks, projects, etc. Use this rather than setting the dependencies array directly.
287
+ #
288
+ # For example:
289
+ # compile.with('module1.jar', 'log4j:log4j:jar:1.0', project('foo'))
290
+ def with(*specs)
291
+ @dependencies |= Buildr.artifacts(specs.flatten).uniq
292
+ self
293
+ end
294
+
295
+ # The target directory for the compiled code.
296
+ attr_reader :target
297
+
298
+ # :call-seq:
299
+ # into(path) => self
300
+ #
301
+ # Sets the target directory and returns self. This will also set the compile task
302
+ # as a prerequisite to a file task on the target directory.
303
+ #
304
+ # For example:
305
+ # compile(src_dir).into(target_dir).with(artifacts)
306
+ # Both compile.invoke and file(target_dir).invoke will compile the source files.
307
+ def into(path)
308
+ @target = file(path.to_s).enhance([self]) unless @target.to_s == path.to_s
309
+ self
310
+ end
311
+
312
+ # Returns the compiler options.
313
+ attr_reader :options
314
+
315
+ # :call-seq:
316
+ # using(options) => self
317
+ #
318
+ # Sets the compiler options from a hash and returns self. Can also be used to
319
+ # select the compiler.
320
+ #
321
+ # For example:
322
+ # compile.using(:warnings=>true, :source=>'1.5')
323
+ # compile.using(:scala)
324
+ def using(*args)
325
+ args.pop.each { |key, value| options.send "#{key}=", value } if Hash === args.last
326
+ self.compiler = args.pop until args.empty?
327
+ self
328
+ end
329
+
330
+ # Returns the compiler if known. The compiler is either automatically selected
331
+ # based on existing source directories (e.g. src/main/java), or by requesting
332
+ # a specific compiler (see #using).
333
+ def compiler
334
+ guess_compiler unless @compiler
335
+ @compiler && @compiler.class.to_sym
336
+ end
337
+
338
+ # Returns the compiled language, if known. See also #compiler.
339
+ def language
340
+ compiler && @compiler.class.language
341
+ end
342
+
343
+ # Returns the default packaging type for this compiler, if known.
344
+ def packaging
345
+ compiler && @compiler.class.packaging
346
+ end
347
+
348
+ def timestamp #:nodoc:
349
+ # If we compiled successfully, then the target directory reflects that.
350
+ # If we didn't, see needed?
351
+ target ? target.timestamp : Rake::EARLY
352
+ end
353
+
354
+ # The project this task belongs to.
355
+ attr_reader :project
356
+
357
+ # The usage, one of :main or :test.
358
+ attr_reader :usage
359
+
360
+ protected
361
+
362
+ # Selects which compiler to use.
363
+ def compiler=(name) #:nodoc:
364
+ cls = Compiler.select(name) or raise ArgumentError, "No #{name} compiler available. Did you install it?"
365
+ return self if cls === @compiler
366
+ @compiler = cls.new(project, options)
367
+ from Array(cls.sources).map { |path| project.path_to(:source, usage, path) }.
368
+ select { |path| File.exist?(path) } if sources.empty?
369
+ into project.path_to(:target, usage, cls.target) unless target
370
+ with Array(@compiler.dependencies)
371
+ self
372
+ end
373
+
374
+ # Associates this task with project and particular usage (:main, :test).
375
+ def associate_with(project, usage) #:nodoc:
376
+ @project, @usage = project, usage
377
+ guess_compiler
378
+ end
379
+
380
+ # Try to guess if we have a compiler to match source files.
381
+ def guess_compiler #:nodoc:
382
+ candidate = Compiler.compilers.detect { |cls| cls.applies_to?(project, self) }
383
+ self.compiler = candidate if candidate
384
+ end
385
+
386
+ private
387
+
388
+ def needed? #:nodoc:
389
+ return false if sources.empty?
390
+ # Fail during invoke.
391
+ return true unless @compiler && target
392
+ return @compiler.needed?(sources.map(&:to_s), target.to_s, dependencies.map(&:to_s))
393
+ end
394
+
395
+ def invoke_prerequisites(args, chain) #:nodoc:
396
+ @sources = Array(@sources).map(&:to_s).uniq
397
+ @dependencies = FileList[@dependencies.uniq]
398
+ @prerequisites |= @dependencies + @sources
399
+ super
400
+ end
401
+
402
+ end
403
+
404
+
405
+ # The resources task is executed by the compile task to copy resource files over
406
+ # to the target directory. You can enhance this task in the normal way, but mostly
407
+ # you will use the task's filter.
408
+ #
409
+ # For example:
410
+ # resources.filter.using 'Copyright'=>'Acme Inc, 2007'
411
+ class ResourcesTask < Rake::Task
412
+
413
+ # Returns the filter used to copy resources over. See Buildr::Filter.
414
+ attr_reader :filter
415
+
416
+ def initialize(*args) #:nodoc:
417
+ super
418
+ @filter = Buildr::Filter.new
419
+ @filter.using Buildr.settings.profile['filter'] if Hash === Buildr.settings.profile['filter']
420
+ enhance do
421
+ target.invoke if target
422
+ end
423
+ end
424
+
425
+ # :call-seq:
426
+ # include(*files) => self
427
+ #
428
+ # Includes the specified files in the filter and returns self.
429
+ def include(*files)
430
+ filter.include *files
431
+ self
432
+ end
433
+
434
+ # :call-seq:
435
+ # exclude(*files) => self
436
+ #
437
+ # Excludes the specified files in the filter and returns self.
438
+ def exclude(*files)
439
+ filter.exclude *files
440
+ self
441
+ end
442
+
443
+ # :call-seq:
444
+ # from(*sources) => self
445
+ #
446
+ # Adds additional directories from which to copy resources.
447
+ #
448
+ # For example:
449
+ # resources.from _('src/etc')
450
+ def from(*sources)
451
+ filter.from *sources
452
+ self
453
+ end
454
+
455
+ # Returns the list of source directories (each being a file task).
456
+ def sources
457
+ filter.sources
458
+ end
459
+
460
+ # :call-seq:
461
+ # target => task
462
+ #
463
+ # Returns the filter's target directory as a file task.
464
+ def target
465
+ filter.into @project.path_to(:target, @usage, :resources) unless filter.target || sources.empty?
466
+ filter.target
467
+ end
468
+
469
+ def prerequisites #:nodoc:
470
+ super + filter.sources.flatten
471
+ end
472
+
473
+ protected
474
+
475
+ # Associates this task with project and particular usage (:main, :test).
476
+ def associate_with(project, usage) #:nodoc:
477
+ @project, @usage = project, usage
478
+ end
479
+
480
+ end
481
+
482
+
483
+ # Methods added to Project for compiling, handling of resources and generating source documentation.
484
+ module Compile
485
+
486
+ include Extension
487
+
488
+ first_time do
489
+ desc 'Compile all projects'
490
+ Project.local_task('compile') { |name| "Compiling #{name}" }
491
+ end
492
+
493
+ before_define(:compile) do |project|
494
+ resources = ResourcesTask.define_task('resources')
495
+ resources.send :associate_with, project, :main
496
+ project.path_to(:source, :main, :resources).tap { |dir| resources.from dir if File.exist?(dir) }
497
+
498
+ compile = CompileTask.define_task('compile'=>resources)
499
+ compile.send :associate_with, project, :main
500
+ project.recursive_task('compile')
501
+ end
502
+
503
+ after_define(:compile) do |project|
504
+ if project.compile.target
505
+ # This comes last because the target path is set inside the project definition.
506
+ project.build project.compile.target
507
+ project.clean do
508
+ rm_rf project.compile.target.to_s, :verbose=>false
509
+ end
510
+ end
511
+ end
512
+
513
+
514
+ # :call-seq:
515
+ # compile(*sources) => CompileTask
516
+ # compile(*sources) { |task| .. } => CompileTask
517
+ #
518
+ # The compile task does what its name suggests. This method returns the project's
519
+ # CompileTask. It also accepts a list of source directories and files to compile
520
+ # (equivalent to calling CompileTask#from on the task), and a block for any
521
+ # post-compilation work.
522
+ #
523
+ # The compile task attempts to guess which compiler to use. For example, if it finds
524
+ # any Java files in the src/main/java directory, it will use the Java compiler and
525
+ # create class files in the target/classes directory.
526
+ #
527
+ # You can also configure it yourself by telling it which compiler to use, pointing
528
+ # it as source directories and chooing a different target directory.
529
+ #
530
+ # For example:
531
+ # # Include Log4J and the api sub-project artifacts.
532
+ # compile.with 'log4j:log4j:jar:1.2', project('api')
533
+ # # For JavaC, force target compatibility.
534
+ # compile.options.source = '1.6'
535
+ # # Run the OpenJPA bytecode enhancer after compilation.
536
+ # compile { open_jpa_enhance }
537
+ # # Pick a given compiler.
538
+ # compile.using(:scalac).from('src/scala')
539
+ #
540
+ # For more information, see CompileTask.
541
+ def compile(*sources, &block)
542
+ task('compile').from(sources).enhance &block
543
+ end
544
+
545
+ # :call-seq:
546
+ # resources(*prereqs) => ResourcesTask
547
+ # resources(*prereqs) { |task| .. } => ResourcesTask
548
+ #
549
+ # The resources task is executed by the compile task to copy resources files
550
+ # from the resource directory into the target directory. By default the resources
551
+ # task copies files from the src/main/resources into the target/resources directory.
552
+ #
553
+ # This method returns the project's resources task. It also accepts a list of
554
+ # prerequisites and a block, used to enhance the resources task.
555
+ #
556
+ # Resources files are copied and filtered (see Buildr::Filter for more information).
557
+ # The default filter uses the profile properties for the current environment.
558
+ #
559
+ # For example:
560
+ # resources.from _('src/etc')
561
+ # resources.filter.using 'Copyright'=>'Acme Inc, 2007'
562
+ #
563
+ # Or in your profiles.yaml file:
564
+ # common:
565
+ # Copyright: Acme Inc, 2007
566
+ def resources(*prereqs, &block)
567
+ task('resources').enhance prereqs, &block
568
+ end
569
+
570
+ end
571
+
572
+
573
+ class Options
574
+
575
+ # Returns the debug option (environment variable DEBUG).
576
+ def debug
577
+ (ENV['DEBUG'] || ENV['debug']) !~ /(no|off|false)/
578
+ end
579
+
580
+ # Sets the debug option (environment variable DEBUG).
581
+ #
582
+ # You can turn this option off directly, or by setting the environment variable
583
+ # DEBUG to +no+. For example:
584
+ # buildr build DEBUG=no
585
+ #
586
+ # The release tasks runs a build with <tt>DEBUG=no</tt>.
587
+ def debug=(flag)
588
+ ENV['debug'] = nil
589
+ ENV['DEBUG'] = flag.to_s
590
+ end
591
+
592
+ end
593
+
594
+ end
595
+
596
+
597
+ class Buildr::Project
598
+ include Buildr::Compile
599
+ end