buildr 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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