realityforge-buildr 1.5.9

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.
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