buildr 0.20.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ 0.21 (4/20/2007)
2
+ * Added: Methods to read and write a file (shortcut for File.read/File.open.write).
3
+ * Changed: Filter task now takes a source directory and target directory, and copies all included (sans excluded) files between the two.
4
+ * Changed: Artifact type is now symbol instead of string (so :jar instead of "jar"). You can still specify a string, but the return value from #to_spec or #type is a symbol.
5
+ * Changed: Eclipse task now adds "src/main/resources", "src/test/java", "src/test/resources" to build path, and excludes ".svn" and "CVS" directories from being copied into target directories.
6
+ * Changed: The test task will now run JUnit test cases from classes ending with Test or Suite. And the inclusion pattern is always set.
7
+ * Fixed: Project property not inherited if false.
8
+
1
9
  0.20 (4/18/2007)
2
10
  * Added: JavadocTask to generate Javadoc documentation for the project, javadoc method on the project itself to return its javadoc task, and Java.javadoc to do all the heavy lifting.
3
11
  * Changed: Release code is now implemented as module instead of class. SVN copy made from working copy instead of double commit.
@@ -22,46 +30,33 @@
22
30
  * Added: jetty:start and jetty:stop tasks to start/stop the server from the console.
23
31
  * Added: jetty:use to start Jetty inside the build or hook to an existing server.
24
32
  * Added: jetty:setup and jetty:teardown to perform tasks around jetty:use.
25
- * Added: The local build task will now execute the local test task. So building a project (or sub-project)
26
- will run the test cases on that project (or sub-project) but not any of its dependencies.
33
+ * Added: The local build task will now execute the local test task. So building a project (or sub-project) will run the test cases on that project (or sub-project) but not any of its dependencies.
27
34
  * Added: ZipTask accepts nested path (i.e. calling path inside a path).
28
- * Added: package(:war) by defaults picks libraries from the compiler classpath. You can always override by
29
- passing the :libs option.
30
- * Changed: Eclipse task now generates library path with M2_REPO variable or project-relative paths
31
- where appropriate
32
- * Changed: compile.target (CompileTask) and resources.target (Filter) are now file tasks, not strings.
33
- So passing the target to someone else will hopefully convience them to invoke or enhance it.
35
+ * Added: package(:war) by defaults picks libraries from the compiler classpath. You can always override by passing the :libs option.
36
+ * Changed: Eclipse task now generates library path with M2_REPO variable or project-relative paths where appropriate
37
+ * Changed: compile.target (CompileTask) and resources.target (Filter) are now file tasks, not strings. So passing the target to someone else will hopefully convience them to invoke or enhance it.
34
38
  * Changed: Java related tasks like OpenJPA, XMLBeans, JavaCC all moved to the Buildr::Java module.
35
39
  * Changed: Handling of package_as arguments to support JBI packaging.
36
40
  * Changed: meta_inf project property is an array accepting filenames (strings) and file tasks.
37
41
  * Changed: meta_info by default only includes the LICENSE file from the top-level project.
38
42
  * Changed: The WarTask :classes argument is now a directory name, and will include all files in this directory.
39
43
  * Changed: WarTask and JarTask accept meta_inf argument.
40
- * Changed: Behavior of needed? and prerequsities in base Rake::Task. This will probably not affect you,
41
- but don't be surprised if it disappears (see lib/core/rake_ext.rb for details).
42
- * Changed: Were previous the test task would link to test.run, it now executes the entire test lifecycle,
43
- and is the major point for extending the test lifecycle.
44
+ * Changed: Behavior of needed? and prerequsities in base Rake::Task. This will probably not affect you, but don't be surprised if it disappears (see lib/core/rake_ext.rb for details).
45
+ * Changed: Were previous the test task would link to test.run, it now executes the entire test lifecycle, and is the major point for extending the test lifecycle.
44
46
  * Changed: test.run is now test.junit.
45
47
  * Changed: Ant.define is now Ant.declarative, Ant.execute is now Ant.executable.
46
- * Changed: The filter method now returns a Filter class that can be used to set a filter, but is not itself
47
- a task. Instead, it creates a task when setting its target.
48
- * Changed: Project.resources now returns a ResourceTask that includes, but is not itself a filter, accessed
49
- using the accessor filter.
50
- * Changed: UnzipTask eliminated and replaced with Unzip which you now have to run directly by calling extract.
51
- However, unzip method creates a file task and returns an Unzip object that can be used as a reference to
52
- that file task.
48
+ * Changed: The filter method now returns a Filter class that can be used to set a filter, but is not itself a task. Instead, it creates a task when setting its target.
49
+ * Changed: Project.resources now returns a ResourceTask that includes, but is not itself a filter, accessed using the accessor filter.
50
+ * Changed: UnzipTask eliminated and replaced with Unzip which you now have to run directly by calling extract. However, unzip method creates a file task and returns an Unzip object that can be used as a reference to that file task.
53
51
  * Changed: Attributes is now InheritedAttributes.
54
- * Changed: The first call to package configures the package task from the options, the second call only returns
55
- the package task.
52
+ * Changed: The first call to package configures the package task from the options, the second call only returns the package task.
56
53
  * Removed: :cp argument, always use :classpath.
57
54
  * Removed: src_dir, java_src_dir, target_dir, webapp_src_dir and all other premature configuration attributes.
58
- * Removed: Project tests method deprecated in favor of a single test method; it now accepts an enhancement
59
- block, not an instance_eval block.
55
+ * Removed: Project tests method deprecated in favor of a single test method; it now accepts an enhancement block, not an instance_eval block.
60
56
  * Removed: FilterTask is dead.
61
57
  * Removed: sub_projects method. Is anyone using this?
62
58
  * Fixed: Local buildr.rb not loaded from running from inside a sub-project directory.
63
- * Fixed: Eclipse task now executed whenever a change is made in the Rakefile, or any file it requires,
64
- include buildr.rb and task files.
59
+ * Fixed: Eclipse task now executed whenever a change is made in the Rakefile, or any file it requires, include buildr.rb and task files.
65
60
  * Fixed: Circular dependency in release task.
66
61
 
67
62
  0.18 (3/26/2007)
@@ -30,7 +30,7 @@ end
30
30
 
31
31
 
32
32
  module Buildr
33
- VERSION = "0.20.0"
33
+ VERSION = "0.21.0"
34
34
  end
35
35
 
36
36
 
@@ -77,7 +77,7 @@ module Buildr
77
77
  fail "Uncommitted SVN files violate the First Principle Of Release!\n#{status}" unless
78
78
  status.empty?
79
79
  end
80
-
80
+
81
81
  # :call-seq:
82
82
  # with_next_version() { |filename| ... } => version
83
83
  #
@@ -154,7 +154,7 @@ module Buildr
154
154
  # Last, we commit what we currently have in the working copy.
155
155
  def commit(version)
156
156
  rakefile = File.read(Rake.application.rakefile).
157
- gsub(THIS_VERSION_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{version}"}) }.
157
+ gsub(THIS_VERSION_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{version}"}) }
158
158
  File.open(Rake.application.rakefile, "w") { |file| file.write rakefile }
159
159
  svn "commit", "-m", "Changed version number to #{version}", Rake.application.rakefile
160
160
  end
@@ -0,0 +1,260 @@
1
+ require "tempfile"
2
+ require "pathname"
3
+ require "core/transports"
4
+
5
+ module Buildr
6
+
7
+ # :call-seq:
8
+ # write(name, content)
9
+ # write(name) { ... }
10
+ #
11
+ # Write the contents into a file. The second form calls the block and writes the result.
12
+ #
13
+ # For example:
14
+ # write "TIMESTAMP", Time.now
15
+ # write("TIMESTAMP") { Time.now }
16
+ #
17
+ # Yields to the block before writing the file, so you can chain read and write together.
18
+ # For example:
19
+ # write("README") { read("README").sub("${build}", Time.now) }
20
+ def write(name, content = nil)
21
+ mkpath File.dirname(name)
22
+ content = yield if block_given?
23
+ File.open(name.to_s, "w") { |file| file.write content.to_s }
24
+ content.to_s
25
+ end
26
+
27
+ # :call-seq:
28
+ # read(name) => string
29
+ # read(name) { |string| ... } => result
30
+ #
31
+ # Reads and returns the contents of a file. The second form yields to the block and returns
32
+ # the result of the block.
33
+ #
34
+ # For example:
35
+ # puts read("README")
36
+ # read("README") { |text| puts text }
37
+ def read(name)
38
+ if block_given?
39
+ yield File.read(name.to_s)
40
+ else
41
+ File.read(name.to_s)
42
+ end
43
+ end
44
+
45
+ # :call-seq:
46
+ # download(url_or_uri) => task
47
+ # download(path=>url_or_uri) =>task
48
+ #
49
+ # Create a task that will download a file from a URL.
50
+ #
51
+ # Takes a single argument, a hash with one pair. The key is the file being
52
+ # created, the value if the URL to download. The task executes only if the
53
+ # file does not exist; the URL is not checked for updates.
54
+ #
55
+ # The task will show download progress on the console; if there are MD5/SHA1
56
+ # checksums on the server it will verify the download before saving it.
57
+ #
58
+ # For example:
59
+ # download "image.jpg"=>"http://example.com/theme/image.jpg"
60
+ def download(args)
61
+ if String === args || URI === args
62
+ # Given only a download URL, download into a temporary file.
63
+ # You can infer the file from task name.
64
+ temp = Tempfile.new(File.basename(args.to_s))
65
+ task = file_create(temp.path) do |task|
66
+ Transports.download task.source, task.name
67
+ end
68
+ task.sources << args
69
+ else
70
+ # Download to a file created by the task.
71
+ fail unless args.keys.size == 1
72
+ url = args.values.first
73
+ task = file_create(args.keys.first) do |task|
74
+ mkpath File.dirname(task.name), :verbose=>false
75
+ Transports.download task.source, task.name
76
+ end
77
+ task.sources << url
78
+ end
79
+ task
80
+ end
81
+
82
+ # A filter knows how to copy files from one directory to another, applying mappings to the
83
+ # contents of these files.
84
+ #
85
+ # You can specify the mapping using a Hash, and it will map ${key} fields found in each source
86
+ # file into the appropriate value in the target file. For example:
87
+ # filter.using "version"=>"1.2", "build"=>Time.now
88
+ # will replace all occurrences of <tt>${version}</tt> with <tt>1.2</tt>, and <tt>${build}</tt>
89
+ # with the current date/time.
90
+ #
91
+ # You can also specify the mapping by passing a proc or a method, that will be called for
92
+ # each source file, with the file name and content, returning the modified content.
93
+ #
94
+ # Without any mapping, the filter simply copies files from the source directory into the target
95
+ # directory.
96
+ #
97
+ # See Buildr#filter.
98
+ class Filter
99
+
100
+ def initialize() #:nodoc:
101
+ @include = []
102
+ @exclude = []
103
+ end
104
+
105
+ # The source directory as a file task.
106
+ attr_accessor :source
107
+
108
+ # :call-seq:
109
+ # from(dir) => self
110
+ #
111
+ # Sets the source directory from which files are copied and returns self.
112
+ #
113
+ # For example:
114
+ # filter.from("src").into("target").using("build"=>Time.now)
115
+ def from(dir)
116
+ @source = file(File.expand_path(dir.to_s))
117
+ self
118
+ end
119
+
120
+ # The target directory as a file task.
121
+ attr_reader :target
122
+
123
+ # :call-seq:
124
+ # into(dir) => self
125
+ #
126
+ # Sets the target directory into which files are copied and returns self.
127
+ #
128
+ # For example:
129
+ # filter.from("src").into("target").using("build"=>Time.now)
130
+ def into(dir)
131
+ @target = file(File.expand_path(dir.to_s))
132
+ self
133
+ end
134
+
135
+ # :call-seq:
136
+ # include(*files) => self
137
+ #
138
+ # Specifies files to include and returns self. See FileList#include.
139
+ #
140
+ # By default all files are included. You can use this method to only include specific
141
+ # files form the source directory.
142
+ def include(*files)
143
+ @include += files
144
+ self
145
+ end
146
+ alias :add :include
147
+
148
+ # :call-seq:
149
+ # exclude(*files) => self
150
+ #
151
+ # Specifies files to exclude and returns self. See FileList#exclude.
152
+ def exclude(*files)
153
+ @exclude += files
154
+ self
155
+ end
156
+
157
+ # The mapping. See #using.
158
+ attr_accessor :mapping
159
+
160
+ # :call-seq:
161
+ # using(mapping) => self
162
+ # using() { |file_name, contents| ... } => self
163
+ #
164
+ # Specifies the mapping to use and returns self.
165
+ #
166
+ # The mapping can be a proc or a method called with the file name and content, returning
167
+ # the modified content. Or the mapping can be a Hash for mapping each ${key} into a value.
168
+ # Without any mapping, all files are copied as is.
169
+ #
170
+ # For example:
171
+ # filter.using "version"=>"1.2"
172
+ # will replace all occurrences of "${version}" with "1.2".
173
+ def using(mapping, &block)
174
+ self.mapping = mapping || block
175
+ self
176
+ end
177
+
178
+ # Runs the filter.
179
+ def run()
180
+ if needed?
181
+ unless copy_map.empty?
182
+ verbose(Rake.application.options.trace || false) do
183
+ mkpath target.to_s
184
+ copy_map do |dest, src|
185
+ mkpath File.dirname(dest) rescue nil
186
+ case mapping
187
+ when Proc, Method # Call on input, accept output.
188
+ mapped = mapping.call(src, File.open(src, "rb") { |file| file.read })
189
+ File.open(dest, "wb") { |file| file.write mapped }
190
+ when Hash # Map ${key} to value
191
+ mapped = File.open(src, "rb") { |file| file.read }.
192
+ gsub(/\$\{.*\}/) { |str| mapping[str[2..-2]] || str }
193
+ File.open(dest, "wb") { |file| file.write mapped }
194
+ when nil # No mapping.
195
+ cp src, dest
196
+ else
197
+ fail "Filter can be a hash (key=>value), or a proc/method; I don't understand #{mapping}"
198
+ end
199
+ end
200
+ touch target.to_s
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ # Returns the target directory.
207
+ def to_s()
208
+ @target.to_s
209
+ end
210
+
211
+ private
212
+
213
+ def needed?()
214
+ return false if target.nil? || source.nil? || !File.exist?(source.to_s)
215
+ return true unless File.exist?(target.to_s)
216
+ !copy_map.empty?
217
+ end
218
+
219
+ # Return a copy map of all the files that need copying: the key is the file to copy to,
220
+ # the value is the source file. If called with a block, yields with each dest/source pair.
221
+ def copy_map(&block)
222
+ unless @copy_map
223
+ @include = ["*"] if @include.empty?
224
+ base = Pathname.new(source.to_s)
225
+ @copy_map = Dir[File.join(source.to_s, "**/*")].reject { |file| File.directory?(file) }.
226
+ map { |src| Pathname.new(src).relative_path_from(base).to_s }.
227
+ select { |file| @include.any? { |pattern| File.fnmatch(pattern, file) } }.
228
+ reject { |file| @exclude.any? { |pattern| File.fnmatch(pattern, file) } }.
229
+ map { |file| [File.expand_path(file, target.to_s), File.expand_path(file, source.to_s)] }.
230
+ select { |dest, src| !File.exist?(dest) || File.stat(src).mtime > File.stat(dest).mtime }
231
+ end
232
+ if block_given?
233
+ @copy_map.each(&block)
234
+ else
235
+ @copy_map
236
+ end
237
+ end
238
+
239
+ end
240
+
241
+ # :call-seq:
242
+ # filter(target=>source) => Filter
243
+ #
244
+ # Creates a filter that will copy files from the source directory into the target directory.
245
+ # You can extend the filter to modify files by mapping <tt>${key}</tt> into values in each
246
+ # of the copied files, and by including or excluding specific files.
247
+ #
248
+ # A filter is not a task, you must call the Filter#run method to execute it.
249
+ #
250
+ # For example, to copy all files from one directory to another:
251
+ # filter("target/classes"=>"src/files")
252
+ # To include only the text files, and replace each instance of <tt>${build}</tt> with the current
253
+ # date/time:
254
+ # filter("target/classes"=>"src/files").include("*.txt").using("build"=>Time.now)
255
+ def filter(args)
256
+ target, source = Rake.application.resolve_args(args)
257
+ Filter.new.into(target).tap { |filter| filter.from(source) if source }
258
+ end
259
+
260
+ end
@@ -31,7 +31,8 @@ module Buildr
31
31
  block ||= proc { default }
32
32
  attr_accessor symbol
33
33
  define_method "#{symbol}_with_inheritence" do
34
- unless value = send("#{symbol}_without_inheritence")
34
+ value = send("#{symbol}_without_inheritence")
35
+ if value.nil?
35
36
  value = parent ? parent.send(symbol) : self.instance_eval(&block)
36
37
  send "#{symbol}=", value
37
38
  end
@@ -454,6 +455,7 @@ module Buildr
454
455
  end
455
456
 
456
457
  def execute() #:nodoc:
458
+ # Reset the namespace, so all tasks are automatically defined in the project's namespace.
457
459
  Rake.application.in_namespace ":#{name}" do
458
460
  # Everything we do inside the project is relative to its working directory.
459
461
  Dir.chdir(base_dir) { super }
@@ -29,7 +29,7 @@ module Buildr
29
29
  attr_reader :id
30
30
  # The group identifier.
31
31
  attr_reader :group
32
- # The file type.
32
+ # The file type. (Symbol)
33
33
  attr_reader :type
34
34
  # The version number.
35
35
  attr_reader :version
@@ -44,7 +44,7 @@ module Buildr
44
44
  # becomes:
45
45
  # { :group=>"com.example",
46
46
  # :id=>"app",
47
- # :type=>"jar",
47
+ # :type=>:jar,
48
48
  # :version=>"1.2" }
49
49
  def to_spec_hash()
50
50
  base = { :group=>group, :id=>id, :type=>type, :version=>version }
@@ -68,8 +68,8 @@ module Buildr
68
68
  #
69
69
  # Convenience method that returns a POM artifact.
70
70
  def pom()
71
- return self if type.to_s == "pom"
72
- artifact(:group=>group, :id=>id, :version=>version, :type=>"pom", :classifier=>classifier)
71
+ return self if type == :pom
72
+ artifact(:group=>group, :id=>id, :version=>version, :type=>:pom, :classifier=>classifier)
73
73
  end
74
74
 
75
75
  protected
@@ -94,8 +94,8 @@ module Buildr
94
94
  # a site that doesn't have a remote repository structure, copy it from a different disk, etc.
95
95
  class Artifact < Rake::FileCreationTask
96
96
 
97
- # The default file type for artifacts, if not specified.
98
- DEFAULT_FILE_TYPE = "jar"
97
+ # The default artifact type.
98
+ DEFAULT_TYPE = :jar
99
99
 
100
100
  include ActsAsArtifact
101
101
 
@@ -142,7 +142,7 @@ module Buildr
142
142
  fail "Missing group identifier for #{spec.inspect}" if spec[:group].blank?
143
143
  fail "Missing artifact identifier for #{spec.inspect}" if spec[:id].blank?
144
144
  fail "Missing version for #{spec.inspect}" if spec[:version].blank?
145
- spec[:type] = DEFAULT_FILE_TYPE if spec[:type].blank?
145
+ spec[:type] = spec[:type].blank? ? DEFAULT_TYPE : spec[:type].to_sym
146
146
  spec
147
147
  elsif String === spec
148
148
  group, id, type, version, *rest = spec.split(":")
@@ -166,7 +166,7 @@ module Buildr
166
166
  hash = to_hash(hash) unless Hash === hash
167
167
  version = ":#{hash[:version]}" unless hash[:version].blank?
168
168
  classifier = ":#{hash[:classifier]}" unless hash[:classifier].blank?
169
- "#{hash[:group]}:#{hash[:id]}:#{hash[:type] || DEFAULT_FILE_TYPE}#{classifier}#{version}"
169
+ "#{hash[:group]}:#{hash[:id]}:#{hash[:type] || DEFAULT_TYPE}#{classifier}#{version}"
170
170
  end
171
171
 
172
172
  # :call-seq:
@@ -176,7 +176,7 @@ module Buildr
176
176
  def hash_to_file_name(hash)
177
177
  version = "-#{hash[:version]}" unless hash[:version].blank?
178
178
  classifier = "-#{hash[:classifier]}" unless hash[:classifier].blank?
179
- "#{hash[:id]}#{version}#{classifier}.#{hash[:type] || DEFAULT_FILE_TYPE}"
179
+ "#{hash[:id]}#{version}#{classifier}.#{hash[:type] || DEFAULT_TYPE}"
180
180
  end
181
181
 
182
182
  end
@@ -1,8 +1,8 @@
1
1
  require "core/project"
2
2
  require "core/build"
3
+ require "core/common"
3
4
  require "java/artifact"
4
5
  require "java/java"
5
- require "tasks/filter"
6
6
 
7
7
  module Buildr
8
8
  module Java
@@ -253,7 +253,7 @@ module Buildr
253
253
 
254
254
  def initialize(*args) #:nodoc:
255
255
  super
256
- @filter = Buildr::filter
256
+ @filter = Buildr::Filter.new
257
257
  enhance { filter.run }
258
258
  end
259
259
 
@@ -275,8 +275,24 @@ module Buildr
275
275
  self
276
276
  end
277
277
 
278
+ # :call-seq:
279
+ # source() => task
280
+ #
281
+ # Returns the filter's source directory as a file task.
282
+ def source()
283
+ filter.source
284
+ end
285
+
286
+ # :call-seq:
287
+ # target() => task
288
+ #
289
+ # Returns the filter's target directory as a file task.
290
+ def target()
291
+ filter.target
292
+ end
293
+
278
294
  def prerequisites() #:nodoc:
279
- super + filter.sources
295
+ super + [filter.source].compact
280
296
  end
281
297
 
282
298
  end
@@ -520,7 +536,7 @@ module Buildr
520
536
  prepare = task("prepare")
521
537
  # Resources task is a filter.
522
538
  resources = Java::ResourcesTask.define_task("resources")
523
- project.path_to("src/main/resources").tap { |dir| resources.filter.include project.path_to(dir, "*") if File.exist?(dir) }
539
+ resources.filter.from project.path_to("src/main/resources")
524
540
  # Compile task requires prepare and performs resources, if anything compiled.
525
541
  compile = Java::CompileTask.define_task("compile"=>[prepare, resources]) { |task| project.resources.invoke }
526
542
  project.path_to("src/main/java").tap { |dir| compile.from dir if File.exist?(dir) }
@@ -37,32 +37,71 @@ module Buildr
37
37
  path = path.__send__(msg)
38
38
  Pathname.new(path).relative_path_from(Pathname.new(project.path_to)).to_s
39
39
  end
40
+
40
41
  m2repo = Buildr::Repositories.instance.local
42
+ excludes = [ '**/.svn/', '**/CVS/' ].join('|')
41
43
 
42
44
  File.open(task.name, "w") do |file|
43
45
  xml = Builder::XmlMarkup.new(:target=>file, :indent=>2)
44
46
  xml.classpath do
45
- # Internal: projects that create artifacts we find on the classpath.
46
- # External: other artifacts, typically from the local repository.
47
- internal, external = project.compile.classpath.map(&:to_s).
48
- map { |path| projects.detect { |prj| prj.packages.detect { |pkg| pkg.to_s == path } } || path }.
49
- partition { |path| path.is_a?(Project) }
50
- vars, libs = external.partition { |path| path.to_s.index(m2repo) == 0 }
51
- generated, libs = libs.partition { |path| path.to_s.index(project.path_to.to_s) == 0 }
47
+ # Note: Use the test classpath since Eclipse compiles both "main" and "test" classes using the same classpath
48
+ cp = project.test.compile.classpath.map(&:to_s) - [ project.compile.target.to_s ]
49
+
50
+ # Convert classpath elements into applicable Project objects
51
+ cp.collect! { |path| projects.detect { |prj| prj.packages.detect { |pkg| pkg.to_s == path } } || path }
52
+
53
+ # project_libs: artifacts created by other projects
54
+ project_libs, others = cp.partition { |path| path.is_a?(Project) }
55
+
56
+ # Separate artifacts from Maven2 repository
57
+ m2_libs, others = others.partition { |path| path.to_s.index(m2repo) == 0 }
58
+
59
+ # Generated: classpath elements in the project are assumed to be generated
60
+ generated, libs = others.partition { |path| path.to_s.index(project.path_to.to_s) == 0 }
61
+
52
62
  xml.classpathentry :kind=>'con', :path=>'org.eclipse.jdt.launching.JRE_CONTAINER'
53
- # Collect all the classpaths, key is the kind, value is
54
- # string or array (or anything responding to to_a).
55
- { :src => project.compile.sources.map { |src| relative[src] } + generated.map { |src| relative[src] },
56
- :output => relative[project.compile.target],
63
+
64
+ srcs = project.compile.sources.map { |src| relative[src] } + generated.map { |src| relative[src] }
65
+ srcs.sort.uniq.each do |path|
66
+ xml.classpathentry :kind=>'src', :path=>path, :excluding=>excludes
67
+ end
68
+
69
+ { :output => relative[project.compile.target],
57
70
  :lib => libs.map(&:to_s),
58
- :var => vars.map { |path| path.to_s.sub(m2repo, 'M2_REPO') }
71
+ :var => m2_libs.map { |path| path.to_s.sub(m2repo, 'M2_REPO') }
59
72
  }.each do |kind, paths|
60
73
  paths.sort.uniq.each do |path|
61
74
  xml.classpathentry :kind=>kind, :path=>path
62
75
  end
63
76
  end
64
- internal.map(&:name).sort.uniq.each do |prj_name|
65
- xml.classpathentry :kind=>"src", :combineaccessrules=>"false", :path=>"/#{prj_name}"
77
+
78
+ # Classpath elements from other projects
79
+ project_libs.map(&:name).sort.uniq.each do |prj_name|
80
+ xml.classpathentry :kind=>'src', :combineaccessrules=>"false", :path=>"/#{prj_name}"
81
+ end
82
+
83
+ # Main resources implicitly copied into project.compile.target
84
+ # TODO: find solution that uses project.test.resources.filter.sources
85
+ [ "src/main/resources" ].each do |path|
86
+ if File.exist? project.path_to(path)
87
+ xml.classpathentry :kind=>'src', :path=>path, :excluding=>excludes
88
+ end
89
+ end
90
+
91
+ # Test classes are generated in a separate output directory
92
+ test_sources = project.test.compile.sources.map { |src| relative[src] }
93
+ test_sources.each do |paths|
94
+ paths.sort.uniq.each do |path|
95
+ xml.classpathentry :kind=>'src', :path=>path, :output => relative[project.test.compile.target], :excluding=>excludes
96
+ end
97
+ end
98
+
99
+ # Test resources go in separate output directory as well
100
+ # TODO: find solution that uses project.test.resources.filter.sources
101
+ [ "src/test/resources" ].each do |path|
102
+ if File.exist? project.path_to(path)
103
+ xml.classpathentry :kind=>'src', :path=>path, :output => relative[project.test.compile.target], :excluding=>excludes
104
+ end
66
105
  end
67
106
  end
68
107
  end
@@ -23,6 +23,7 @@ module Buildr
23
23
  # * A hash of manifest properties (name/value pairs).
24
24
  # * An array of hashes, one for each section of the manifest.
25
25
  # * A string providing the name of an existing manifest file.
26
+ # * A file task can be used the same way.
26
27
  # * Proc or method called to return the contents of the manifest file.
27
28
  # * False to not generate a manifest file.
28
29
  #
@@ -50,7 +51,7 @@ module Buildr
50
51
  if key.to_sym == :manifest
51
52
  self.manifest = value
52
53
  elsif key.to_sym == :meta_inf
53
- self.meta_inf = value
54
+ self.meta_inf = [value].flatten
54
55
  else
55
56
  super key, value
56
57
  end
@@ -59,32 +60,30 @@ module Buildr
59
60
 
60
61
  def prerequisites() #:nodoc:
61
62
  super + [ String === manifest ? file(manifest) : nil ].compact +
62
- meta_inf.map { |file| String === file ? file(file) : file }
63
+ [meta_inf].flatten.map { |file| String === file ? file(file) : file }
63
64
  end
64
65
 
65
66
  protected
66
67
 
67
68
  def create(zip) #:nodoc:
68
- meta_inf.map(&:to_s).uniq.each { |file| zip.add "META-INF/#{File.basename(file)}", file }
69
+ [meta_inf].flatten.map(&:to_s).uniq.each { |file| zip.add "META-INF/#{File.basename(file)}", file }
69
70
  unless manifest == false
70
71
  zip.file.open("META-INF/MANIFEST.MF", "w") do |output|
71
- output.write MANIFEST_HEADER
72
+ output << MANIFEST_HEADER
72
73
  if manifest
73
74
  case manifest
74
75
  when Hash
75
- output.write manifest.map { |pair| pair.join(": ") }.sort.join("\n")
76
+ output << manifest.map { |pair| pair.map(&:to_s).join(": ") }.sort.join("\n")
76
77
  when Array
77
- manifest.each do |section|
78
- output.write "\n"
79
- output.write section.map { |pair| pair.join(": ") }.sort.join("\n")
80
- end
78
+ output << manifest.reject { |section| section.empty? }.map { |section|
79
+ section.map { |pair| pair.join(": ") }.sort.join("\n").concat("\n")
80
+ }.join("\n")
81
81
  when Proc, Method
82
- output.write manifest.call
83
- when String
84
- output.write File.read(manifest)
82
+ output << manifest.call
83
+ when String, Task
84
+ output << File.read(manifest.to_s)
85
85
  end
86
86
  end
87
- output.write "\n"
88
87
  end
89
88
  end
90
89
  super zip
@@ -124,21 +123,35 @@ module Buildr
124
123
 
125
124
  class Project
126
125
 
126
+ # Options accepted by #package method for all package types.
127
+ PACKAGE_OPTIONS = [:group, :id, :version, :type, :classifier]
128
+
129
+ # The project's identifier. Same as the project name, with colons replaced by dashes.
130
+ # The ID for project foo:bar is foo-bar.
131
+ attr_reader :id
132
+ def id()
133
+ name.gsub(":", "-")
134
+ end
135
+
127
136
  # Group used for packaging. Inherited from parent project. Defaults to the top-level project name.
128
137
  attr_accessor :group
129
138
  inherited_attr(:group) { |project| project.name }
139
+
130
140
  # Version used for packaging. Inherited from parent project.
131
141
  attr_accessor :version
132
142
  inherited_attr :version
133
- # Manifest used for packaging. Inherited from parent project. The default value
134
- # is a hash that includes the Build-By, Build-Jdk and Implementation-Version values.
135
- # The later is taken from the project's version number.
143
+
144
+ # Manifest used for packaging. Inherited from parent project. The default value is a hash that includes
145
+ # the Build-By, Build-Jdk, Implementation-Title and Implementation-Version values.
146
+ # The later are taken from the project's comment (or name) and version number.
136
147
  attr_accessor :manifest
137
148
  inherited_attr :manifest do |project|
138
149
  manifest = { "Build-By"=>ENV['USER'], "Build-Jdk"=>Java.version }
150
+ manifest["Implementation-Title"] = self.comment || self.name
139
151
  manifest["Implementation-Version"] = project.version if project.version
140
152
  manifest
141
153
  end
154
+
142
155
  # Files to always include in the package META-INF directory. The default value include
143
156
  # the LICENSE file if one exists in the project's base directory.
144
157
  attr_accessor :meta_inf
@@ -147,13 +160,6 @@ module Buildr
147
160
  File.exist?(license.to_s) ? [license] : []
148
161
  end
149
162
 
150
- # The project's identifier. Same as the project name, with colons replaced by dashes.
151
- # The ID for project foo:bar is foo-bar.
152
- attr_reader :id
153
- def id()
154
- name.gsub(":", "-")
155
- end
156
-
157
163
  # :call-seq:
158
164
  # package(type, options?) => task
159
165
  #
@@ -221,7 +227,7 @@ module Buildr
221
227
  # that accepts two arguments, the file name and a hash of options. The method must yield to the
222
228
  # block with the package only when first called to define the package, and must return the package
223
229
  # from each call.
224
- def package(type, options = nil)
230
+ def package(type = :jar, options = nil)
225
231
  options = options.nil? ? {} : options.dup
226
232
  options[:id] ||= self.id
227
233
  options[:group] ||= self.group
@@ -230,7 +236,7 @@ module Buildr
230
236
  file_name = path_to("target", Artifact.hash_to_file_name(options))
231
237
 
232
238
  packager = method("package_as_#{type}") rescue
233
- fail("Do not know how to create a package of type #{:type}")
239
+ fail("Don't know how to create a package of type #{type}")
234
240
  packager.call(file_name, options) do |package|
235
241
  # Make it an artifact using the specifications, and tell it how to create a POM.
236
242
  package.extend ActsAsArtifact
@@ -299,8 +305,9 @@ module Buildr
299
305
 
300
306
  def package_as_jar(file_name, options) #:nodoc:
301
307
  unless Rake::Task.task_defined?(file_name)
308
+ fu_check_options options, *PACKAGE_OPTIONS + [:manifest, :meta_inf, :include]
302
309
  Java::Packaging::JarTask.define_task(file_name).tap do |jar|
303
- jar.manifest = options[:manifest] || manifest.merge("Implementation-Title"=>self.comment)
310
+ jar.manifest = options.has_key?(:manifest) ? options[:manifest] : manifest
304
311
  jar.meta_inf = options[:meta_inf] || meta_inf
305
312
  if options[:include]
306
313
  jar.include options[:include]
@@ -310,14 +317,17 @@ module Buildr
310
317
  end
311
318
  yield jar
312
319
  end
320
+ else
321
+ fu_check_options options, *PACKAGE_OPTIONS
313
322
  end
314
323
  file(file_name)
315
324
  end
316
325
 
317
326
  def package_as_war(file_name, options) #:nodoc:
318
327
  unless Rake::Task.task_defined?(file_name)
328
+ fu_check_options options, *PACKAGE_OPTIONS + [:manifest, :meta_inf, :classes, :libs, :include]
319
329
  Java::Packaging::WarTask.define_task(file_name).tap do |war|
320
- war.manifest = options[:manifest] || manifest.merge("Implementation-Title"=>self.comment)
330
+ war.manifest = options.has_key?(:manifest) ? options[:manifest] : manifest
321
331
  war.meta_inf = options[:meta_inf] || meta_inf
322
332
  # Add libraries in WEB-INF lib, and classes in WEB-INF classes
323
333
  if options[:classes]
@@ -340,18 +350,23 @@ module Buildr
340
350
  end
341
351
  yield war
342
352
  end
353
+ else
354
+ fu_check_options options, *PACKAGE_OPTIONS
343
355
  end
344
356
  file(file_name)
345
357
  end
346
358
 
347
359
  def package_as_zip(file_name, options) #:nodoc:
348
360
  unless Rake::Task.task_defined?(file_name)
361
+ fu_check_options options, *PACKAGE_OPTIONS + [:include]
349
362
  ZipTask.define_task(file_name).tap do |zip|
350
363
  if options[:include]
351
364
  zip.include options[:include]
352
365
  end
353
366
  yield zip
354
367
  end
368
+ else
369
+ fu_check_options options, *PACKAGE_OPTIONS
355
370
  end
356
371
  file(file_name)
357
372
  end
@@ -19,7 +19,7 @@ module Buildr
19
19
  super
20
20
  @classpath = []
21
21
  @paths = []
22
- @include = []
22
+ @include = ["*Test", "*Suite"]
23
23
  @exclude = []
24
24
  enhance do |task|
25
25
  unless test_cases.empty?
@@ -43,10 +43,9 @@ module Buildr
43
43
  # test.include "com.example.Module*"
44
44
  # test.include "*.{First,Second}Test"
45
45
  #
46
- # If you do not specify any inclusion pattern explicitly, the default pattern is used.
47
- # This pattern picks up all classes with a name ending with Test (same as test.include "*Test").
48
- # Use the Test suffix to specify test case classes, and avoid the Test suffix for classes
49
- # that do not implement test cases (e.g. mock objects, helpers, etc).
46
+ # By default, all classes that have a name ending with Test or Suite are included.
47
+ # Use these suffixes for your test and test suite classes respectively, to distinguish them
48
+ # from stubs, helper classes, etc.
50
49
  def include(*classes)
51
50
  @include += classes
52
51
  self
@@ -85,7 +84,6 @@ module Buildr
85
84
 
86
85
  def test_cases()
87
86
  unless @cases
88
- @include << "*Test" if @include.empty?
89
87
  @cases = @paths.map do |path|
90
88
  base = Pathname.new(path.to_s)
91
89
  FileList["#{path}/**/*.class"].
@@ -164,9 +162,9 @@ module Buildr
164
162
  # Returns the JUnit task. This task executes JUnit test cases, from classes compiled by
165
163
  # the test task.
166
164
  #
167
- # By default it includes all classes with the suffix Test, and excludes all other classes.
168
- # Use the Test suffix for classes that implement test cases, avoid this suffix for other
169
- # classes (e.g. mocks, helper objects).
165
+ # By default it includes all classes with the suffix Test or Suite, and excludes all other classes.
166
+ # Use the Test/Suite suffix for classes that implement test cases, avoid this suffix for other
167
+ # classes (e.g. stubs, helper objects).
170
168
  #
171
169
  # You can also include only specific test cases, or exclude otherwise included test cases
172
170
  # using #include and #exclude.
@@ -267,7 +265,7 @@ module Buildr
267
265
  project.recursive_task("test")
268
266
  # Similar to the regular resources task but using different paths.
269
267
  resources = Java::ResourcesTask.define_task("test:resources")
270
- project.path_to("src/test/resources").tap { |dir| resources.filter.include project.path_to(dir, "*") if File.exist?(dir) }
268
+ resources.filter.from project.path_to("src/test/resources")
271
269
  # Similar to the regular compile task but using different paths.
272
270
  compile = Java::CompileTask.define_task("test:compile"=>[project.compile, project.test.prepare, project.test.resources])
273
271
  compile.enhance { project.test.resources.invoke }
@@ -312,7 +312,7 @@ module Buildr
312
312
  # Or:
313
313
  # package(:jar)[:manifest] = "MANIFEST_MF"
314
314
  def []=(key, value)
315
- fail "#{self.class} does not support the attribute #{key}"
315
+ raise ArgumentError, "#{self.class} does not support the option #{key}"
316
316
  end
317
317
 
318
318
  def prerequisites() #:nodoc:
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: buildr
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.20.0
7
- date: 2007-04-18 00:00:00 -07:00
6
+ version: 0.21.0
7
+ date: 2007-04-20 00:00:00 -07:00
8
8
  summary: A build system that doesn't suck
9
9
  require_paths:
10
10
  - lib
@@ -33,14 +33,13 @@ files:
33
33
  - lib/core
34
34
  - lib/buildr.rb
35
35
  - lib/java
36
- - lib/tasks/download.rb
37
- - lib/tasks/filter.rb
38
36
  - lib/tasks/concat.rb
39
37
  - lib/tasks/zip.rb
40
38
  - lib/core/transports.rb
41
39
  - lib/core/build.rb
42
40
  - lib/core/project.rb
43
41
  - lib/core/rake_ext.rb
42
+ - lib/core/common.rb
44
43
  - lib/java/test.rb
45
44
  - lib/java/eclipse.rb
46
45
  - lib/java/jetty.rb
@@ -68,6 +67,7 @@ rdoc_options:
68
67
  - --main
69
68
  - README
70
69
  - --line-numbers
70
+ - -inline-source
71
71
  extra_rdoc_files:
72
72
  - README
73
73
  - CHANGELOG
@@ -1,43 +0,0 @@
1
- require "tempfile"
2
- require "core/transports"
3
-
4
- module Buildr
5
-
6
- # :call-seq:
7
- # download(url_or_uri) => task
8
- # download(path=>url_or_uri) =>task
9
- #
10
- # Create a task that will download a file from a URL.
11
- #
12
- # Takes a single argument, a hash with one pair. The key is the file being
13
- # created, the value if the URL to download. The task executes only if the
14
- # file does not exist; the URL is not checked for updates.
15
- #
16
- # The task will show download progress on the console; if there are MD5/SHA1
17
- # checksums on the server it will verify the download before saving it.
18
- #
19
- # For example:
20
- # download "image.jpg"=>"http://example.com/theme/image.jpg"
21
- def download(args)
22
- if String === args || URI === args
23
- # Given only a download URL, download into a temporary file.
24
- # You can infer the file from task name.
25
- temp = Tempfile.new(File.basename(args.to_s))
26
- task = file_create(temp.path) do |task|
27
- Transports.download task.source, task.name
28
- end
29
- task.sources << args
30
- else
31
- # Download to a file created by the task.
32
- fail unless args.keys.size == 1
33
- url = args.values.first
34
- task = file_create(args.keys.first) do |task|
35
- mkpath File.dirname(task.name), :verbose=>false
36
- Transports.download task.source, task.name
37
- end
38
- task.sources << url
39
- end
40
- task
41
- end
42
-
43
- end
@@ -1,159 +0,0 @@
1
- module Buildr
2
-
3
- # A filter knows how to copy a set of source files into a target directory, and apply
4
- # mapping to these files.
5
- #
6
- # You can specify the mapping using a Hash, and it will map ${key} fields found in each
7
- # source file into the appropriate value. For example:
8
- # filter.using "version"=>"1.2"
9
- # will replace all occurrences of "${version}" with "1.2".
10
- #
11
- # You can also specify the mapping by passing a proc or a method, that will be called for
12
- # each source file, with the file name and content, returning the modified content.
13
- #
14
- # Without any mapping, the filter simply copies the source files into the target directory.
15
- #
16
- # See Buildr#filter.
17
- class Filter
18
-
19
- # The target directory.
20
- attr_reader :target
21
- # The mapping. See #using.
22
- attr_accessor :mapping
23
- # The source files and directories.
24
- attr_accessor :sources
25
-
26
- def initialize() #:nodoc:
27
- @sources = FileList[]
28
- end
29
-
30
- # :call-seq:
31
- # include(*files) => self
32
- #
33
- # Specifies files to include and returns self. See FileList#include.
34
- def include(*files)
35
- @sources.include *files
36
- self
37
- end
38
- alias :add :include
39
-
40
- # :call-seq:
41
- # exclude(*files) => self
42
- #
43
- # Specifies files to exclude and returns self. See FileList#exclude.
44
- def exclude(*files)
45
- @sources.exclude *files
46
- self
47
- end
48
-
49
- # :call-seq:
50
- # into(dir) => self
51
- #
52
- # Specifies the target directory and return self. This tells the filter task where
53
- # to copy the source files to.
54
- #
55
- # For example:
56
- # filter.include("*.HTML").into("docs").run
57
- def into(dir)
58
- @target = File.expand_path(dir.to_s)
59
- self
60
- end
61
-
62
- # :call-seq:
63
- # using(mapping) => self
64
- # using() { |file_name, contents| ... } => self
65
- #
66
- # Specifies the mapping to use and returns self.
67
- #
68
- # The mapping can be a proc or a method called with the file name and content, returning
69
- # the modified content. Or the mapping can be a Hash for mapping each ${key} into a value.
70
- # Without any mapping, all files are copied as is.
71
- #
72
- # For example:
73
- # filter.using "version"=>"1.2"
74
- # will replace all occurrences of "${version}" with "1.2".
75
- def using(mapping, &block)
76
- self.mapping = mapping || block
77
- self
78
- end
79
-
80
- # Run the filter.
81
- def run()
82
- #@sources.each { |src| Rake.application[src, Rake.application.current_scope].invoke }
83
- if needed?
84
- fail "No target directory specified" if !target || (File.exist?(target.to_s) && !File.directory?(target.to_s))
85
- unless copy_map.empty?
86
- verbose(Rake.application.options.trace || false) do
87
- mkpath target.to_s
88
- copy_map do |dest, src|
89
- mkpath File.dirname(dest) rescue nil
90
- case mapping
91
- when Proc, Method # Call on input, accept output.
92
- mapped = mapping.call(src, File.read(src))
93
- File.open(dest, "w") { |file| file.write mapped }
94
- when Hash # Map ${key} to value
95
- mapped = File.read(src).gsub(/\$\{.*\}/) { |str| mapping[str[2..-2]] || str }
96
- File.open(dest, "w") { |file| file.write mapped }
97
- when nil # No mapping.
98
- cp src, dest
99
- else
100
- fail "Filter can be a hash (key=>value), or a proc/method; I don't understand #{mapping}"
101
- end
102
- end
103
- touch target.to_s
104
- end
105
- end
106
- end
107
- end
108
-
109
- # Returns the target directory.
110
- def to_s()
111
- @target.to_s
112
- end
113
-
114
- private
115
-
116
- def needed?()
117
- return false if target.nil? || copy_map.empty?
118
- return true unless File.exist?(target.to_s)
119
- return true if copy_map.any? { |dest, src| !File.exist?(dest) || File.mtime(src) > File.mtime(dest) }
120
- false
121
- end
122
-
123
- # Return a copy map of all the files that need copying: the key is the file to copy to,
124
- # the value is the source file. If called with a block, yields with each dest/source pair.
125
- def copy_map(&block)
126
- # Create a map between the source file and the similarly named file in the target directory,
127
- # including all files nested inside directories.
128
- @copy_map ||= @sources.map(&:to_s).inject({}) do |map, path|
129
- if File.directory?(path)
130
- Dir["#{path}/**/*"].each do |file|
131
- map[file.sub(File.dirname(path), target.to_s)] = file unless
132
- File.directory?(file) || @sources.exclude?(file)
133
- end
134
- elsif File.exist?(path)
135
- map[File.join(target.to_s, File.basename(path))] = path
136
- end
137
- map
138
- end.reject do |dest, src|
139
- # ... while ignoring that which does not need updating.
140
- File.exist?(dest) && File.stat(dest).mtime > File.stat(src).mtime
141
- end
142
- if block_given?
143
- @copy_map.each(&block)
144
- else
145
- @copy_map
146
- end
147
- end
148
-
149
- end
150
-
151
- # :call-seq:
152
- # filter(*files) => Filter
153
- #
154
- # Creates a filter task to operate on all the specified files.
155
- def filter(*files)
156
- Filter.new.include *files
157
- end
158
-
159
- end