buildr 1.2.2 → 1.2.3

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,10 @@
1
+ 1.2.3 (7/26/2007)
2
+ * Added: Get your buildfile created form existing POM, just run buildr on existing Maven project (Anatol Pomozov).
3
+ * Added: package(:tar), package(:tgz), TarballTask dn TarTask (Tommy Knowlton).
4
+ * Changed: The ArchiveTask needs no introduction: it's a base task that provides common functionality for ZipTask, TarTask and friends.
5
+ * Fixed: Release runs buildr instead of buildr.cmd on Windows (Chris Power).
6
+ * Fixed: Cobertura reports broken (Anatol Pomozov).
7
+
1
8
  1.2.2 (7/18/2007)
2
9
  * Added: resources.using and filter.using now accepts a format as the first argument, default being :maven, but you can also use :ant, :ruby or pass a regular expression (http://groups.google.com/group/buildr-talk/browse_thread/thread/5216d5ae8bfff29b).
3
10
  * Fixed: Sleek upload with changelog for each release courtesy of Anatol Pomozov.
data/Rakefile CHANGED
@@ -26,16 +26,18 @@ spec = Gem::Specification.new do |spec|
26
26
  spec.executables = ["buildr"]
27
27
 
28
28
  # Tested against these dependencies.
29
- spec.add_dependency "rake", "= 0.7.3"
30
- spec.add_dependency "facets", "= 1.8.54"
31
- spec.add_dependency "builder", "= 2.1.2"
32
- spec.add_dependency "net-ssh", "= 1.1.2"
33
- spec.add_dependency "net-sftp", "= 1.1.0"
34
- spec.add_dependency "rubyzip", "= 0.9.1"
35
- spec.add_dependency "highline", "= 1.2.9"
36
- spec.add_dependency "rjb", "= 1.0.6"
37
- spec.add_dependency "Antwrap", "= 0.6.0"
38
- spec.add_dependency "rspec", "= 1.0.5"
29
+ spec.add_dependency "rake", "= 0.7.3"
30
+ spec.add_dependency "facets", "= 1.8.54"
31
+ spec.add_dependency "builder", "= 2.1.2"
32
+ spec.add_dependency "net-ssh", "= 1.1.2"
33
+ spec.add_dependency "net-sftp", "= 1.1.0"
34
+ spec.add_dependency "rubyzip", "= 0.9.1"
35
+ spec.add_dependency "highline", "= 1.2.9"
36
+ spec.add_dependency "rjb", "= 1.0.6"
37
+ spec.add_dependency "Antwrap", "= 0.6.0"
38
+ spec.add_dependency "rspec", "= 1.0.5"
39
+ spec.add_dependency "xml-simple", "= 1.0.11"
40
+ spec.add_dependency "archive-tar-minitar", "= 0.5.1"
39
41
  end
40
42
 
41
43
 
@@ -18,12 +18,13 @@ require "facet/array/head"
18
18
  require "facet/string/starts_with"
19
19
  require "facet/openobject"
20
20
  require "facets/core/kernel/tap"
21
+ require "facets/core/enumerable/uniq_by"
21
22
  # A different kind of buildr, one we use to create XML.
22
23
  require "builder"
23
24
 
24
25
 
25
26
  module Buildr
26
- VERSION = "1.2.2".freeze
27
+ VERSION = "1.2.3".freeze
27
28
  end
28
29
 
29
30
 
@@ -118,9 +119,7 @@ unless defined?(Rake)
118
119
  if Dir.pwd == here || options.nosearch
119
120
  error = "No Buildfile found (looking for: #{@rakefiles.join(', ')})"
120
121
  if STDIN.isatty
121
- if $terminal.agree("To use Buildr you need a buildfile. Do you want me to create one? (yes/no)")
122
- chdir(original_dir) { task("generate").invoke }
123
- end
122
+ chdir(original_dir) { task("generate").invoke }
124
123
  exit 1
125
124
  else
126
125
  raise error
@@ -51,11 +51,10 @@ module Buildr
51
51
  desc "Run the test cases and produce code coverage reports in #{report_to(:html)}"
52
52
  task "html"=>["instrument", "test:all"] do
53
53
  puts "Creating test coverage reports in #{report_to(:html)}"
54
- projects = Buildr.projects
55
54
  Buildr.ant "cobertura" do |ant|
56
55
  ant.taskdef :classpath=>requires.join(File::PATH_SEPARATOR), :resource=>"tasks.properties"
57
56
  ant.send "cobertura-report", :destdir=>report_to(:html), :format=>"html", :datafile=>data_file do
58
- ant.projects.map(&:compile).map(&:sources).flatten.each do |src|
57
+ Buildr.projects.map(&:compile).map(&:sources).flatten.each do |src|
59
58
  ant.fileset(:dir=>src.to_s) { ant.include :name=>"**/*.java" } if File.exist?(src.to_s)
60
59
  end
61
60
  end
@@ -65,11 +64,10 @@ module Buildr
65
64
  desc "Run the test cases and produce code coverage reports in #{report_to(:xml)}"
66
65
  task "xml"=>["instrument", "test:all"] do
67
66
  puts "Creating test coverage reports in #{report_to(:xml)}"
68
- projects = Buildr.projects
69
67
  Buildr.ant "cobertura" do |ant|
70
68
  ant.taskdef :classpath=>requires.join(File::PATH_SEPARATOR), :resource=>"tasks.properties"
71
69
  ant.send "cobertura-report", :destdir=>report_to(:xml), :format=>"xml", :datafile=>data_file do
72
- ant.projects.map(&:compile).map(&:sources).flatten.each do |src|
70
+ Buildr.projects.map(&:compile).map(&:sources).flatten.each do |src|
73
71
  ant.fileset :dir=>src.to_s if File.exist?(src.to_s)
74
72
  end
75
73
  end
@@ -113,13 +113,17 @@ module Buildr
113
113
  # Make a release.
114
114
  def make()
115
115
  check
116
- version = with_next_version { |filename, version| sh "buildr clean upload DEBUG=no --buildfile #{filename}" }
116
+ version = with_next_version { |filename, version| sh "#{command} clean upload DEBUG=no --buildfile #{filename}" }
117
117
  tag version
118
118
  commit version + "-SNAPSHOT"
119
119
  end
120
120
 
121
121
  protected
122
122
 
123
+ def command() #:nodoc:
124
+ Config::CONFIG["arch"] =~ /dos|win32/i ? $PROGRAM_NAME.ext("cmd") : $PROGRAM_NAME
125
+ end
126
+
123
127
  # :call-seq:
124
128
  # check()
125
129
  #
@@ -269,7 +269,7 @@ end
269
269
 
270
270
 
271
271
  module Buildr
272
- class ZipTask
272
+ class ArchiveTask
273
273
 
274
274
  class Path
275
275
 
@@ -279,7 +279,7 @@ module Buildr
279
279
  # Returns true if this path exists. This only works if the path has any entries in it,
280
280
  # so exist on path happens to be the opposite of empty.
281
281
  def exist?()
282
- !empty?
282
+ !entries.empty?
283
283
  end
284
284
 
285
285
  # :call-seq:
@@ -287,7 +287,7 @@ module Buildr
287
287
  #
288
288
  # Returns true if this path is empty (has no other entries inside).
289
289
  def empty?()
290
- check { |entries| entries.empty? }
290
+ entries.all? { |entry| entry.empty? }
291
291
  end
292
292
 
293
293
  # :call-seq:
@@ -296,9 +296,7 @@ module Buildr
296
296
  # Returns true if this ZIP file path contains all the specified files. You can use relative
297
297
  # file names and glob patterns (using *, **, etc).
298
298
  def contain?(*files)
299
- check do |entries|
300
- files.all? { |file| entries.detect { |entry| File.fnmatch(file, entry.to_s) } }
301
- end
299
+ files.all? { |file| entries.detect { |entry| File.fnmatch(file, entry.to_s) } }
302
300
  end
303
301
 
304
302
  # :call-seq:
@@ -308,21 +306,17 @@ module Buildr
308
306
  # for example:
309
307
  # package(:jar).path("META-INF").entry("LICENSE").should contain(/Apache Software License/)
310
308
  def entry(name)
311
- ::Zip::ZipEntry.new(root.name, "#{@path}#{name}")
309
+ root.entry("#{@path}#{name}")
312
310
  end
313
311
 
314
312
  protected
315
313
 
316
- def check() #:nodoc:
317
- unless @cached_entries
318
- if @path
319
- base = Regexp.new("^" + Regexp.escape(@path || ""))
320
- @cached_entries = root.path(nil).check.select { |entry| entry.name =~ base }.map { |entry| entry.name.sub(base, "") }
321
- else
322
- @cached_entries = Zip::ZipFile.open(root.name) { |zip| zip.entries }
323
- end
324
- end
325
- block_given? ? yield(@cached_entries) : @cached_entries
314
+ def entries() #:nodoc:
315
+ return root.entries unless @path
316
+ @entries ||= root.entries.inject([]) { |selected, entry|
317
+ selected << entry.name.sub(@path, "") if entry.name.starts_with?(@path)
318
+ selected
319
+ }
326
320
  end
327
321
 
328
322
  end
@@ -344,14 +338,23 @@ module Buildr
344
338
  path("").contain?(*files)
345
339
  end
346
340
 
341
+ end
342
+
343
+
344
+ class ZipTask
345
+
347
346
  # :call-seq:
348
347
  # entry(name) => Entry
349
348
  #
350
349
  # Returns a ZIP file entry. You can use this to check if the entry exists and its contents,
351
350
  # for example:
352
351
  # package(:jar).entry("META-INF/LICENSE").should contain(/Apache Software License/)
353
- def entry(name)
354
- path("").entry(name)
352
+ def entry(entry_name)
353
+ ::Zip::ZipEntry.new(name, entry_name)
354
+ end
355
+
356
+ def entries() #:nodoc:
357
+ @entries ||= Zip::ZipFile.open(name) { |zip| zip.entries }
355
358
  end
356
359
 
357
360
  end
@@ -2,20 +2,33 @@ module Buildr
2
2
  module Generate #:nodoc:
3
3
 
4
4
  task "generate" do
5
- script = Generate.from_directory(true).join("\n")
6
- buildfile = File.expand_path("buildfile")
7
- File.open(buildfile, "w") { |file| file.write script }
8
- puts "Created #{buildfile}"
5
+ script = nil
6
+ HighLine.new.choose do |menu|
7
+ menu.header = "To use Buildr you need a buildfile. Do you want me to create one?"
8
+
9
+ menu.choice("From maven2 pom file") { script = Generate.from_maven2_pom(true).join("\n") } if File.exists?("pom.xml")
10
+ menu.choice("From directory structure") { script = Generate.from_directory(true).join("\n") }
11
+ menu.choice("Skip") { }
12
+ end
13
+
14
+ if script
15
+ buildfile = File.expand_path("buildfile")
16
+ File.open(buildfile, "w") { |file| file.write script }
17
+ puts "Created #{buildfile}"
18
+ end
9
19
  end
10
20
 
11
21
  class << self
12
22
 
23
+
24
+ HEADER = "# Generated by Buildr #{Buildr::VERSION}, change to your liking\n\n"
25
+
26
+
13
27
  def from_directory(root = false)
14
28
  name = File.basename(Dir.pwd)
15
29
  if root
30
+ script = HEADER.split("\n")
16
31
  header = <<-EOF
17
- # Generated by Buildr #{Buildr::VERSION}, change to your liking
18
-
19
32
  # Version number for this release
20
33
  VERSION_NUMBER = "1.0.0"
21
34
  # Version number for the next release
@@ -34,7 +47,7 @@ define "#{name}" do
34
47
  project.group = GROUP
35
48
  manifest["Implementation-Vendor"] = COPYRIGHT
36
49
  EOF
37
- script = header.split("\n")
50
+ script += header.split("\n")
38
51
  else
39
52
  script = [ %{define "#{name}" do} ]
40
53
  end
@@ -59,7 +72,95 @@ EOF
59
72
  script.flatten
60
73
  end
61
74
 
62
- end
75
+ def from_maven2_pom(root = false)
76
+ pom = Buildr::POM.load('pom.xml')
77
+ project = pom.project
78
+
79
+ artifactId = project['artifactId']
80
+ description = project['name'] || "The #{artifactId} project"
81
+
82
+ if root
83
+ script = HEADER.split("\n")
84
+
85
+ settings_file = ENV["m2_settings"] || File.join(Gem::user_home, ".m2/settings.xml")
86
+ settings = XmlSimple.xml_in(IO.read(settings_file)) if File.exists?(settings_file)
87
+
88
+ if settings
89
+ proxy = settings['proxies'].first['proxy'].find { |proxy|
90
+ proxy["active"].nil? || proxy["active"].to_s =~ /true/
91
+ } rescue nil
92
+
93
+ if proxy
94
+ url = %{#{proxy["protocol"].first}://#{proxy["host"].first}:#{proxy["port"].first}}
95
+ exclude = proxy["nonProxyHosts"].to_s.gsub("|", ",") if proxy["nonProxyHosts"]
96
+ script << "options.proxy.http = '#{url}'"
97
+ script << "options.proxy.exclude << '#{exclude}'" if exclude
98
+ script << ''
99
+ # In addition, we need to use said proxies to download artifacts.
100
+ options.proxy.http = url
101
+ options.proxy.exclude << exclude if exclude
102
+ end
103
+ end
104
+
105
+ repositories = project["repositories"].first["repository"].select { |repository|
106
+ legacy = repository["layout"].to_s =~ /legacy/
107
+ !legacy
108
+ } rescue nil
109
+ unless repositories.nil? || repositories.empty?
110
+ repositories.each do |repository|
111
+ name, url = repository["name"], repository["url"]
112
+ script << "# #{name}"
113
+ script << "repositories.remote << '#{url}'"
114
+ # In addition we need to use said repositores to download artifacts.
115
+ Buildr.repositories.remote << url.to_s
116
+ end
117
+ script << ""
118
+ end
119
+ else
120
+ script = []
121
+ end
63
122
 
123
+ script << "desc '#{description}'"
124
+ script << "define '#{artifactId}' do"
125
+
126
+ groupId = project['groupId']
127
+ script << " project.group = '#{groupId}'" if groupId
128
+
129
+ version = project['version']
130
+ script << " project.version = '#{version}'" if version
131
+
132
+ #get plugins configurations
133
+ plugins = project['build'].first['plugins'].first['plugin'] rescue {}
134
+ compile_plugin = plugins.find{|pl| (pl['groupId'].nil? or pl['groupId'].first == 'org.apache.maven.plugins') and pl['artifactId'].first == 'maven-compiler-plugin'}
135
+ if compile_plugin
136
+ source = compile_plugin.first['configuration'].first['source'] rescue nil
137
+ target = compile_plugin.first['configuration'].first['target'] rescue nil
138
+
139
+ script << " compile.options.source = '#{source}'" if source
140
+ script << " compile.options.target = '#{target}'" if target
141
+ end
142
+
143
+ dependencies = pom.dependencies.map{|d| "'#{d}'"}.join(', ')
144
+ script << " compile.with #{dependencies}" unless dependencies.empty?
145
+
146
+ test_dependencies = pom.dependencies(['test']).map{|d| "'#{d}'"}.join(', ')
147
+ script << " test.compile.with #{test_dependencies}" unless test_dependencies.empty?
148
+
149
+ packaging = project['packaging'].first
150
+ if %w(jar war).include?(packaging)
151
+ script << " package :#{packaging}, :id => '#{artifactId}'"
152
+ end
153
+
154
+ modules = project['modules'].first['module'] rescue nil
155
+ if modules
156
+ modules.each do |mod|
157
+ chdir(mod) { script << from_maven2_pom.flatten.map { |line| " " + line } << "" }
158
+ end
159
+ end
160
+ script << "end"
161
+ script.flatten
162
+ end
163
+
164
+ end
64
165
  end
65
166
  end
@@ -4,6 +4,7 @@ require "java/java"
4
4
  require "java/compile"
5
5
  require "java/test"
6
6
  require "tasks/zip"
7
+ require "tasks/tar"
7
8
 
8
9
 
9
10
  module Buildr
@@ -23,8 +24,6 @@ module Buildr
23
24
  protected
24
25
  def included(mod)
25
26
  mod.alias_method_chain :initialize, :manifest
26
- mod.alias_method_chain :invoke_prerequisites, :manifest
27
- mod.alias_method_chain :create, :manifest
28
27
  end
29
28
  end
30
29
 
@@ -34,42 +33,41 @@ module Buildr
34
33
  # Specifies files to include in the META-INF directory.
35
34
  attr_accessor :meta_inf
36
35
 
37
- private
38
-
39
- def invoke_prerequisites_with_manifest()
40
- prerequisites << file(manifest.to_s) if String === manifest || Rake::Task === manifest
41
- [meta_inf].flatten.each { |file| prerequisites << file(file.to_s) }
42
- invoke_prerequisites_without_manifest
43
- end
44
-
45
- def initialize_with_manifest(*args)
36
+ def initialize_with_manifest(*args) #:nodoc:
37
+ initialize_without_manifest *args
46
38
  @manifest = false
47
39
  @meta_inf = []
48
- initialize_without_manifest *args
49
- end
50
40
 
51
- def create_with_manifest(zip) #:nodoc:
52
- [meta_inf].flatten.map(&:to_s).uniq.each { |file| zip.add "META-INF/#{File.basename(file)}", file }
53
- unless manifest == false
54
- zip.file.open("META-INF/MANIFEST.MF", "w") do |output|
55
- output << MANIFEST_HEADER
56
- if manifest
41
+ meta_inf_path = path("META-INF")
42
+ prepare do
43
+ @prerequisites << manifest if String === manifest || Rake::Task === manifest
44
+ [meta_inf].flatten.map { |file| file.to_s }.uniq.each { |file| meta_inf_path.include file }
45
+ end
46
+
47
+ enhance do
48
+ if manifest
49
+ # Tempfiles gets deleted on garbage collection, so we're going to hold on to it
50
+ # through instance variable not closure variable.
51
+ Tempfile.open "MANIFEST.MF" do |@manifest_tmp|
52
+ @manifest_tmp.write MANIFEST_HEADER
57
53
  case manifest
58
54
  when Hash
59
- output << manifest.map { |pair| pair.map(&:to_s).join(": ") }.sort.join("\n") << "\n"
55
+ @manifest_tmp.write(manifest.map { |pair| pair.map{ |s| s.to_s }.join(": ") }.sort.join("\n") << "\n")
60
56
  when Array
61
- output << manifest.reject { |section| section.empty? }.map { |section|
57
+ @manifest_tmp.write(manifest.reject { |section| section.empty? }.map { |section|
62
58
  section.map { |pair| pair.join(": ") }.sort.join("\n").concat("\n")
63
- }.join("\n") << "\n"
59
+ }.join("\n") << "\n")
64
60
  when Proc, Method
65
- output << manifest.call
61
+ @manifest_tmp.write manifest.call
66
62
  when String, Rake::Task
67
- output << File.read(manifest.to_s)
63
+ @manifest_tmp.write File.read(manifest.to_s)
64
+ else
65
+ fail "Invalid manifest, expecting Hash, Array, file name/task or proc/method."
68
66
  end
67
+ meta_inf_path.include @manifest_tmp.path, :as=>"MANIFEST.MF"
69
68
  end
70
69
  end
71
70
  end
72
- create_without_manifest zip
73
71
  end
74
72
 
75
73
  end
@@ -142,12 +140,10 @@ module Buildr
142
140
  super
143
141
  @classes = []
144
142
  @libs = []
145
- end
146
-
147
- def invoke_prerequisites() #:nodoc:
148
- @classes.to_a.flatten.each { |classes| path("WEB-INF/classes").include classes, :as=>"." }
149
- path("WEB-INF/lib").include Buildr.artifacts(@libs.to_a.flatten)
150
- super
143
+ prepare do
144
+ @classes.to_a.flatten.each { |classes| path("WEB-INF/classes").include classes, :as=>"." }
145
+ path("WEB-INF/lib").include Buildr.artifacts(@libs) unless @libs.nil? || @libs.empty?
146
+ end
151
147
  end
152
148
 
153
149
  def libs=(value) #:nodoc:
@@ -157,7 +153,7 @@ module Buildr
157
153
  def classes=(value) #:nodoc:
158
154
  @classes |= [value].flatten.map { |dir| file(dir.to_s) }
159
155
  end
160
-
156
+
161
157
  end
162
158
 
163
159
  end
@@ -415,6 +411,20 @@ module Buildr
415
411
  file(file_name)
416
412
  end
417
413
 
414
+ def package_as_tar(file_name, options) #:nodoc:
415
+ unless Rake::Task.task_defined?(file_name)
416
+ TarballTask.define_task(file_name).with(options)
417
+ end
418
+ file(file_name)
419
+ end
420
+
421
+ def package_as_tgz(file_name, options) #:nodoc:
422
+ unless Rake::Task.task_defined?(file_name)
423
+ TarballTask.define_task(file_name).with(options)
424
+ end
425
+ file(file_name)
426
+ end
427
+
418
428
  def package_as_sources(file_name, options) #:nodoc:
419
429
  rake_check_options options, *PACKAGE_OPTIONS
420
430
  options.merge!(:type=>:zip, :classifier=>"sources")
@@ -0,0 +1,157 @@
1
+ require "xmlsimple"
2
+ require "java/artifact"
3
+
4
+
5
+ module Buildr
6
+ class POM
7
+
8
+ POM_TO_SPEC_MAP = { :group=>"groupId", :id=>"artifactId", :type=>"type",
9
+ :version=>"version", :classifier=>"classifier", :scope=>"scope" }
10
+ SCOPES_TRANSITIVE = [nil, "compile", "runtime"]
11
+ SCOPES_WE_USE = SCOPES_TRANSITIVE + ["provided"]
12
+
13
+ # POM project as Hash (using XmlSimple).
14
+ attr_reader :project
15
+ # Parent POM if referenced by this POM.
16
+ attr_reader :parent
17
+
18
+ class << self
19
+
20
+ # :call-seq:
21
+ # POM.load(arg)
22
+ #
23
+ # Load new POM object form various kind of sources such as artifact, hash representing spec, filename, XML.
24
+ def load(source)
25
+ case source
26
+ when Hash
27
+ load(Buildr.artifact(source).pom)
28
+ when Artifact
29
+ load(source.pom.to_s)
30
+ when String, Rake::FileTask
31
+ filename = File.expand_path(source)
32
+ file(filename).invoke
33
+ unless pom = cache[filename]
34
+ puts "Loading m2 pom file from #{filename}" if Rake.application.options.trace
35
+ pom = POM.new(IO.read(filename))
36
+ cache[filename] = pom
37
+ end
38
+ pom
39
+ else
40
+ raise ArgumentError, "Expecting Hash spec, Artifact, file name or file task"
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def cache()
47
+ @cache ||= {}
48
+ end
49
+
50
+ end
51
+
52
+ def initialize(xml) #:nodoc:
53
+ @project = XmlSimple.xml_in(xml)
54
+ @parent = POM.load(pom_to_hash(project["parent"].first)) if project["parent"]
55
+ end
56
+
57
+ # :call-seq:
58
+ # dependencies(scopes?) => artifacts
59
+ #
60
+ # Returns list of required dependencies as specified by the POM. You can specify which scopes
61
+ # to use (e.g. "compile", "runtime"); use +nil+ for dependencies with unspecified scope.
62
+ # The default scopes are +nil+, "compile" and "runtime" (aka SCOPES_WE_USE).
63
+ def dependencies(scopes = SCOPES_WE_USE)
64
+ #try to cache dependencies also
65
+ @depends_for_scopes ||= {}
66
+ unless depends = @depends_for_scopes[scopes]
67
+ declared = project["dependencies"].first["dependency"] rescue nil
68
+ depends = (declared || []).reject { |dep| value_of(dep["optional"]) =~ /true/ }.
69
+ map { |dep|
70
+ spec = pom_to_hash(dep, properties)
71
+ apply = managed(spec)
72
+ spec = apply.merge(spec) if apply
73
+
74
+ #calculate transitive dependencies
75
+ if scopes.include?(spec[:scope])
76
+ spec.delete(:scope)
77
+
78
+ exclusions = dep["exclusions"]["exclusion"] rescue nil
79
+ transitive_deps = POM.load(spec).dependencies(SCOPES_TRANSITIVE)
80
+ transitive_deps = transitive_deps.reject{|dep|
81
+ exclusions.find {|ex| dep.index("#{dep['groupdId'].first}:#{dep['artifactId'].first}:") == 0}
82
+ } if exclusions
83
+
84
+ [Artifact.to_spec(spec.except(:scope))] + transitive_deps
85
+ else
86
+ nil
87
+ end
88
+ }.flatten.compact.uniq_by{|spec| art = spec.split(':'); "#{art[0]}:#{art[1]}"}
89
+
90
+ @depends_for_scopes[scopes] = depends
91
+ end
92
+ depends
93
+ end
94
+
95
+ # :call-seq:
96
+ # properties() => hash
97
+ #
98
+ # Returns properties available to this POM as hash. Includes explicit properties and pom.xxx/project.xxx
99
+ # properties for groupId, artifactId, version and packaging.
100
+ def properties()
101
+ @properties ||= begin
102
+ pom = ["groupId", "artifactId", "version", "packaging"].inject({}) { |hash, key|
103
+ value = project[key] || (parent ? parent.project[key] : nil)
104
+ hash["pom.#{key}"] = hash["project.#{key}"] = value_of(value) if value
105
+ hash
106
+ }
107
+ props = project["properties"].first rescue {}
108
+ props = props.inject({}) { |mapped, pair| mapped[pair.first] = value_of(pair.last, pom) ; mapped }
109
+ (parent ? parent.properties.merge(props) : props).merge(pom)
110
+ end
111
+ end
112
+
113
+ # :call-seq:
114
+ # managed() => hash
115
+ # managed(hash) => hash
116
+ #
117
+ # The first form returns all the managed dependencies specified by this POM in dependencyManagement.
118
+ # The second form uses a single spec hash and expands it from the current/parent POM. Used to determine
119
+ # the version number if specified in dependencyManagement instead of dependencies.
120
+ def managed(spec = nil)
121
+ return managed.detect { |dep| [:group, :id, :type, :classifier].all? { |key| spec[key] == dep[key] } } ||
122
+ (parent ? parent.managed(spec) : nil) if spec
123
+ @managed ||= begin
124
+ managed = project["dependencyManagement"].first["dependencies"].first["dependency"] rescue []
125
+ managed.map { |dep| pom_to_hash(dep, properties) }
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ # :call-seq:
132
+ # value_of(element) => string
133
+ # value_of(element, true) => string
134
+ #
135
+ # Returns the normalized text value of an element from its XmlSimple value. The second form performs
136
+ # property substitution.
137
+ def value_of(element, substitute = nil)
138
+ value = element.to_a.join.strip
139
+ substitute ? value.gsub(/\$\{([^}]+)\}/) { |key| substitute[$1] } : value
140
+ end
141
+
142
+ # :call-seq:
143
+ # pom_to_hash(element) => hash
144
+ # pom_to_hash(element, true) => hash
145
+ #
146
+ # Return the spec hash from an XmlSimple POM referencing element (e.g. project, parent, dependency).
147
+ # The second form performs property substitution.
148
+ def pom_to_hash(element, substitute = nil)
149
+ hash = POM_TO_SPEC_MAP.inject({}) { |spec, pair|
150
+ spec[pair.first] = value_of(element[pair.last], substitute) if element[pair.last]
151
+ spec
152
+ }
153
+ { :type=>"jar" }.merge(hash)
154
+ end
155
+
156
+ end
157
+ end
@@ -0,0 +1,112 @@
1
+ require 'buildr'
2
+ require 'archive/tar/minitar'
3
+
4
+ module Buildr
5
+ class TarTask < Rake::FileTask
6
+
7
+ attr_reader :included
8
+
9
+ def initialize(*args)
10
+ super
11
+ @included = {}
12
+ enhance do
13
+ $stdout << "Creating #{t.name}.\n" if verbose
14
+ rm(name, :verbose=>false) rescue nil
15
+ mkdir_p(File.dirname(name), :verbose=>false)
16
+ begin
17
+ out = File.new(name, "w+")
18
+ out = Zlib::GzipWriter.new(out) if (/.tgz$/ =~ name)
19
+ create_tar_internal(out)
20
+ rescue
21
+ rm(name, :verbose=>false) rescue nil
22
+ raise
23
+ end
24
+ end
25
+ end
26
+
27
+ def with(options)
28
+ options.each do |k,v|
29
+ send "#{k}=", v
30
+ end
31
+ end
32
+
33
+ def include(*args)
34
+ options = (Hash === args.last) ? args.pop : {}
35
+ args = args.flatten
36
+ options[:path] ||= "/"
37
+ check_add_path_internal options
38
+ if options[:as]
39
+ raise "Only use :as with one include file at a time" if args.length > 1
40
+ dest_file = File.join(options[:path], options[:as])
41
+ include_internal(dest_file, args.pop, options)
42
+ else
43
+ args.each do |f|
44
+ dest_file = File.join(options[:path], File.basename(f.to_s))
45
+ include_internal(dest_file, f, options)
46
+ end
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def check_add_path_internal(opts)
53
+ unless @included.has_key?(opts[:path])
54
+ include_internal(opts[:path], :mkdir_in_tar, opts)
55
+ end
56
+ end
57
+
58
+ def include_internal(dst, src, opts)
59
+ raise %Q("#{dst}" was already included in the archive with source path "#{@included[dst][:source_path]}".) if @included[dst]
60
+ @included[dst] = opts.merge({:source_path => src})
61
+ enhance([src]) unless :mkdir_in_tar == src
62
+ end
63
+
64
+ def create_tar_internal(out)
65
+ begin
66
+ Archive::Tar::Minitar::Writer.open(out) do |tar|
67
+ @included.keys.sort.each do |dst|
68
+ opts = @included[dst]
69
+ src = opts[:source_path]
70
+ if :mkdir_in_tar == src
71
+ $stdout << "adding directory #{dst}.\n" if verbose
72
+ tar.mkdir(dst, {:mode=>"0755", :mtime=>Time.now}.merge(opts.reject{|k,v| not [:mode, :uid, :gid, :mtime].include?(k)}))
73
+ else
74
+ $stdout << "adding #{dst} from #{src}\n" if verbose
75
+ is = File.new(src, "rb")
76
+ opts[:size] = is.stat.size
77
+ opts[:mode] ||= is.stat.mode
78
+ opts[:mtime] ||= is.stat.mtime
79
+ opts[:uid] ||= 80
80
+ opts[:gid] ||= 80
81
+ tar.add_file_simple(dst, opts.reject{|k,v| not [:size, :mode, :uid, :gid, :mtime].include?(k)}) do |os|
82
+ while data = is.read(4096)
83
+ os.write(data)
84
+ $stdout << "." if verbose
85
+ end
86
+ end
87
+ $stdout << "\n" if verbose
88
+ end
89
+ end
90
+ end
91
+ ensure out.close
92
+ end
93
+ end
94
+ end
95
+
96
+ class TarballTask < TarTask
97
+
98
+ def initialize(*args)
99
+ super
100
+ end
101
+
102
+ def include(*args)
103
+ options = (Hash === args.last) ? args.pop : {}
104
+ args = args.flatten
105
+ options[:path] ||= "/"
106
+ options[:path] = File.join(name.pathmap("%n"), options[:path])
107
+ super args, options
108
+ end
109
+
110
+ end
111
+
112
+ end
@@ -4,69 +4,67 @@ require "zip/zipfilesystem"
4
4
 
5
5
  module Buildr
6
6
 
7
- # The ZipTask creates a new ZIP file. You can include any number of files and
8
- # and directories, use exclusion patterns, and include files into specific
9
- # directories.
10
- #
11
- # For example:
12
- # zip("test.zip").tap do |task|
13
- # task.include "srcs"
14
- # task.include "README", "LICENSE"
15
- # end
16
- #
17
- # See Buildr#zip.
18
- class ZipTask < Rake::FileTask
7
+ # Base class for ZipTask, TarTask and other archives.
8
+ class ArchiveTask < Rake::FileTask
19
9
 
20
10
  # Which files go where. All the rules for including, excluding and merging files
21
- # are handled by this object. A zip has at least one path.
11
+ # are handled by this object.
22
12
  class Path #:nodoc:
23
13
 
24
- attr_reader :actions
14
+ # Returns the archive from this path.
15
+ attr_reader :root
25
16
 
26
- def initialize(zip, path)
27
- @zip = zip
17
+ def initialize(root, path)
18
+ @root = root
28
19
  @path = "#{path}/" if path
29
- expand_src = proc { (@files || []).map(&:to_s).uniq }
20
+ @files = FileList[]
21
+ # Expand source files added to this path.
22
+ expand_src = proc { @files.map{ |file| file.to_s }.uniq }
30
23
  @sources = [ expand_src ]
31
- @actions = [] << proc do |zip|
24
+ # Add files and directories added to this path.
25
+ @actions = [] << proc do |file_map|
26
+ file_map[@path] = nil if @path
32
27
  expand_src.call.each do |path|
33
28
  if File.directory?(path)
34
29
  in_directory(path, @files) do |file, rel_path|
35
- puts "Adding #{@path}#{rel_path}" if Rake.application.options.trace
36
- zip.add("#{@path}#{rel_path}", file) { true }
30
+ dest = "#{@path}#{rel_path}"
31
+ puts "Adding #{dest}" if Rake.application.options.trace
32
+ file_map[dest] = file
37
33
  end
38
34
  else
39
35
  puts "Adding #{@path}#{File.basename(path)}" if Rake.application.options.trace
40
- zip.add("#{@path}#{File.basename(path)}", path) { true }
36
+ file_map["#{@path}#{File.basename(path)}"] = path
41
37
  end
42
38
  end
43
39
  end
44
40
  end
45
41
 
46
- # Documented in ZipTask.
47
- def include(*files)
48
- if Hash === files.last
49
- options = files.pop
50
- else
51
- options = {}
52
- end
53
- files = files.flatten
54
-
55
- if options[:path]
56
- path(options[:path]).include *files +[ options.reject { |k,v| k == :path } ]
42
+ # :call-seq:
43
+ # include(*files) => self
44
+ # include(*files, :path=>path) => self
45
+ # include(file, :as=>name) => self
46
+ # include(:from=>path) => self
47
+ # include(*files, :merge=>true) => self
48
+ def include(*args)
49
+ options = args.pop if Hash === args.last
50
+ files = args.flatten
51
+
52
+ if options.nil? || options.empty?
53
+ @files.include *files.map { |file| file.to_s }
54
+ elsif options[:path]
55
+ sans_path = options.reject { |k,v| k == :path }
56
+ path(options[:path]).include *files + [sans_path]
57
57
  elsif options[:as]
58
- raise "You can only use the :as option in combination with the :path option" unless options.keys.size == 1
58
+ raise "You can only use the :as option in combination with the :path option" unless options.size == 1
59
59
  raise "You can only use one file with the :as option" unless files.size == 1
60
- include_as(files.first.to_s, options[:as])
60
+ include_as files.first.to_s, options[:as]
61
61
  elsif options[:from]
62
- raise "You can only use the :from option in combination with the :path option" unless options.keys.size == 1
62
+ raise "You can only use the :from option in combination with the :path option" unless options.size == 1
63
63
  raise "You canont use the :from option with file names" unless files.empty?
64
- [options[:from]].flatten.each { |path| include_as(path.to_s, ".") }
64
+ [options[:from]].flatten.each { |path| include_as path.to_s, "." }
65
65
  elsif options[:merge]
66
- raise "You can only use the :merge option in combination with the :path option" unless options.keys.size == 1
66
+ raise "You can only use the :merge option in combination with the :path option" unless options.size == 1
67
67
  files.each { |file| merge file }
68
- elsif options.keys.empty?
69
- (@files ||= FileList[]).include files.map(&:to_s)
70
68
  else
71
69
  raise "Unrecognized option #{options.keys.join(", ")}"
72
70
  end
@@ -74,43 +72,48 @@ module Buildr
74
72
  end
75
73
  alias :add :include
76
74
 
77
- # Documented in ZipTask.
75
+ # :call-seq:
76
+ # exclude(*files) => self
78
77
  def exclude(*files)
79
- (@files ||= FileList[]).exclude *files
78
+ @files.exclude *files
80
79
  self
81
80
  end
82
81
 
83
- # Documented in ZipTask.
84
- def merge(*files)
85
- options = files.pop if Hash === files.last
82
+ # :call-seq:
83
+ # merge(*files) => Merge
84
+ # merge(*files, :path=>name) => Merge
85
+ def merge(*args)
86
+ options = args.pop if Hash === args.last
87
+ files = args.flatten
86
88
 
87
- if options && options[:path]
88
- path(options[:path]).merge *files +[ options.reject { |k,v| k == :path } ]
89
- elsif options.nil? || options.keys.empty?
89
+ if options.nil? || options.empty?
90
90
  files.collect do |file|
91
91
  @sources << proc { file.to_s }
92
92
  expander = ZipExpander.new(file)
93
- @actions << proc { |zip| expander.expand(zip, @path) }
93
+ @actions << proc { |file_map| expander.expand(file_map, @path) }
94
94
  expander
95
95
  end.first
96
+ elsif options[:path]
97
+ sans_path = options.reject { |k,v| k == :path }
98
+ path(options[:path]).merge *files + [sans_path]
99
+ self
96
100
  else
97
101
  raise "Unrecognized option #{options.keys.join(", ")}"
98
102
  end
99
103
  end
100
104
 
101
- # Documented in ZipTask.
105
+ # Returns a Path relative to this one.
102
106
  def path(path)
103
- path.blank? ? self : @zip.path("#{@path}#{path}")
107
+ path.blank? ? self : @root.path("#{@path}#{path}")
104
108
  end
105
109
 
106
- # Documented in ZipTask.
107
- def root()
108
- @zip
110
+ # Returns all the source files.
111
+ def sources() #:nodoc:
112
+ @sources.map{ |source| source.call }.flatten
109
113
  end
110
114
 
111
- # Returns all the source files.
112
- def sources()
113
- @sources.map(&:call).flatten
115
+ def add_files(file_map) #:nodoc:
116
+ @actions.each { |action| action.call(file_map) }
114
117
  end
115
118
 
116
119
  def to_s()
@@ -121,62 +124,60 @@ module Buildr
121
124
 
122
125
  def include_as(source, as)
123
126
  @sources << proc { source }
124
- @actions << proc do |zip|
127
+ @actions << proc do |file_map|
125
128
  file = source.to_s
129
+ file_map[@path] = nil if @path
126
130
  if File.directory?(file)
127
131
  in_directory(file) do |file, rel_path|
128
- if as == "."
129
- dest = (@path || "") + rel_path.split("/")[1..-1].join("/")
130
- else
131
- dest = "#{@path}#{as}#{rel_path}"
132
- end
132
+ dest = as == "." ? (@path || "") + rel_path.split("/")[1..-1].join("/") : "#{@path}#{as}#{rel_path}"
133
133
  puts "Adding #{dest}" if Rake.application.options.trace
134
- zip.add(dest, file) { true }
134
+ file_map[dest] = file
135
135
  end
136
136
  else
137
137
  puts "Adding #{@path}#{as}" if Rake.application.options.trace
138
- zip.add("#{@path}#{as}", file) { true }
138
+ file_map["#{@path}#{as}"] = file
139
139
  end
140
140
  end
141
141
  end
142
142
 
143
143
  def in_directory(dir, excludes = nil)
144
144
  prefix = Regexp.new("^" + Regexp.escape(File.dirname(dir) + File::SEPARATOR))
145
- Dir["#{dir}/**/*"].
145
+ FileList["#{dir}/**/*"].
146
146
  reject { |file| File.directory?(file) || (excludes && excludes.exclude?(file)) }.
147
147
  each { |file| yield file, file.sub(prefix, "") }
148
148
  end
149
149
 
150
150
  end
151
151
 
152
+
152
153
  # Extend one Zip file into another.
153
154
  class ZipExpander #:nodoc:
154
155
 
155
156
  def initialize(zip_file)
156
157
  @zip_file = zip_file.to_s
158
+ @includes = []
159
+ @excludes = []
157
160
  end
158
161
 
159
162
  def include(*files)
160
- (@includes ||= [])
161
163
  @includes |= files
162
164
  self
163
165
  end
164
166
 
165
167
  def exclude(*files)
166
- (@excludes ||= [])
167
168
  @excludes |= files
168
169
  self
169
170
  end
170
171
 
171
- def expand(zip, path)
172
- @includes ||= ["*"]
173
- @excludes ||= []
172
+ def expand(file_map, path)
173
+ @includes = ["*"] if @includes.empty?
174
174
  Zip::ZipFile.open(@zip_file) do |source|
175
175
  source.entries.reject { |entry| entry.directory? }.each do |entry|
176
176
  if @includes.any? { |pattern| File.fnmatch(pattern, entry.name) } &&
177
177
  !@excludes.any? { |pattern| File.fnmatch(pattern, entry.name) }
178
- puts "Adding #{path}#{entry.name}" if Rake.application.options.trace
179
- zip.get_output_stream("#{path}#{entry.name}") { |output| output.write source.read(entry) }
178
+ dest = "#{path}#{entry.name}"
179
+ puts "Adding #{dest}" if Rake.application.options.trace
180
+ file_map[dest] = lambda { |output| output.write source.read(entry) }
180
181
  end
181
182
  end
182
183
  end
@@ -184,25 +185,29 @@ module Buildr
184
185
 
185
186
  end
186
187
 
188
+
187
189
  def initialize(*args) #:nodoc:
188
190
  super
189
191
  @paths = { nil=>Path.new(self, nil) }
190
- enhance do |task|
191
- puts "Creating #{task.name}" if verbose
192
- # We're here because the Zip file does not exist, or one of the files is
193
- # newer than the Zip contents; in the later case, opening the Zip file
194
- # will add to its contents instead of replacing it, so we want the Zip
195
- # gone before we change it. We also don't want to see any partial updates.
196
- rm task.name, :verbose=>false rescue nil
197
- mkpath File.dirname(task.name), :verbose=>false
198
- begin
199
- Zip::ZipFile.open(task.name, Zip::ZipFile::CREATE) do |zip|
200
- zip.restore_permissions = true
201
- create zip
192
+ @prepares = []
193
+
194
+ # Make sure we're the last enhancements, so other enhancements can add content.
195
+ enhance do
196
+ @file_map = {}
197
+ enhance do
198
+ send "create" if respond_to?(:create)
199
+ # We're here because the archive file does not exist, or one of the files is newer than the archive contents;
200
+ # we need to make sure the archive doesn't exist (e.g. opening an existing Zip will add instead of create).
201
+ # We also want to protect against partial updates.
202
+ rm name, :verbose=>false rescue nil
203
+ mkpath File.dirname(name), :verbose=>false
204
+ begin
205
+ @paths.each { |name, object| object.add_files(@file_map) }
206
+ create_from @file_map
207
+ rescue
208
+ rm name, :verbose=>false rescue nil
209
+ raise
202
210
  end
203
- rescue
204
- rm task.name, :verbose=>false rescue nil
205
- raise
206
211
  end
207
212
  end
208
213
  end
@@ -211,30 +216,34 @@ module Buildr
211
216
  # include(*files) => self
212
217
  # include(*files, :path=>path) => self
213
218
  # include(file, :as=>name) => self
214
- # include(*zips, :merge=>true) => self
219
+ # include(:from=>path) => self
220
+ # include(*files, :merge=>true) => self
221
+ #
222
+ # Include files in this archive, or when called on a path, within that path. Returns self.
215
223
  #
216
- # Include files in the ZIP (or current path) and returns self.
224
+ # The first form accepts a list of files, directories and glob patterns and adds them to the archive.
225
+ # For example, to include the file foo, directory bar (including all files in there) and all files under baz:
226
+ # zip(..).include("foo", "bar", "baz/*")
217
227
  #
218
- # This method accepts three options. You can use :path to include files under
219
- # a specific path, for example:
228
+ # The second form is similar but adds files/directories under the specified path. For example,
229
+ # to add foo as bar/foo:
220
230
  # zip(..).include("foo", :path=>"bar")
221
- # includes the file bar as bar/foo. See also #path.
231
+ # The :path option is the same as using the path method:
232
+ # zip(..).path("bar").include("foo")
233
+ # All other options can be used in combination with the :path option.
222
234
  #
223
- # You can use :as to include a file under a different name, for example:
235
+ # The third form adds a file or directory under a different name. For example, to add the file foo under the
236
+ # name bar:
224
237
  # zip(..).include("foo", :as=>"bar")
225
- # You can use the :as option in combination with the :path option, but only with
226
- # a single file at a time.
227
238
  #
228
- # As a special case, you can include the entire contents of a directory by including
229
- # the directory and using :as=>".". This:
230
- # zip(..).include("srcs", :as=>".")
231
- # will include all the source files, using the directory as a prerequisite. This:
232
- # zip(..).include("srcs/*")
233
- # includes all the same source files, using the source files as a prerequisite.
239
+ # The fourth form adds the contents of a directory using the directory as a prerequisite:
240
+ # zip(..).include(:from=>"foo")
241
+ # Unlike <code>include("foo")</code> it includes the contents of the directory, not the directory itself.
242
+ # Unlike <code>include("foo/*")</code>, it uses the directory timestamp for dependency management.
234
243
  #
235
- # You can use :merge option to include the contents of another ZIP file, for example:
236
- # zip(..).include("foo.zip", :merge=>true)
237
- # You can use the :merge option in combination with the :path option. See also #merge.
244
+ # The fifth form includes the contents of another archive by expanding it into this archive. For example:
245
+ # zip(..).include("foo.zip", :merge=>true).include("bar.zip")
246
+ # You can also use the method #merge.
238
247
  def include(*files)
239
248
  @paths[nil].include *files
240
249
  self
@@ -244,8 +253,7 @@ module Buildr
244
253
  # :call-seq:
245
254
  # exclude(*files) => self
246
255
  #
247
- # Excludes files and returns self. Can be used in combination with include to
248
- # prevent some files from being included.
256
+ # Excludes files and returns self. Can be used in combination with include to prevent some files from being included.
249
257
  def exclude(*files)
250
258
  @paths[nil].exclude *files
251
259
  self
@@ -255,14 +263,11 @@ module Buildr
255
263
  # merge(*files) => Merge
256
264
  # merge(*files, :path=>name) => Merge
257
265
  #
258
- # Merges ZIP files and returns a merge object. The contents of the merged ZIP file is
259
- # extracted into this ZIP file (or current path).
266
+ # Merges another archive into this one by including the individual files from the merged archive.
260
267
  #
261
- # The returned object supports two methods: include and exclude. You can use these to
262
- # merge only specific files from the ZIP. For example:
268
+ # Returns an object that supports two methods: include and exclude. You can use these methods to merge
269
+ # only specific files. For example:
263
270
  # zip(..).merge("src.zip").include("module1/*")
264
- #
265
- # This differs from include with the :merge option, which returns self.
266
271
  def merge(*files)
267
272
  @paths[nil].merge *files
268
273
  end
@@ -270,25 +275,23 @@ module Buildr
270
275
  # :call-seq:
271
276
  # path(name) => Path
272
277
  #
273
- # Returns a path object. You can use the path object to include files in a given
274
- # path inside the ZIP file. The path object implements the include, exclude, merge,
275
- # path and root methods.
276
- #
277
- # For example:
278
+ # Returns a path object. Use the path object to include files under a path, for example, to include
279
+ # the file "foo" as "bar/foo":
278
280
  # zip(..).path("bar").include("foo")
279
- # Will add the file foo under the name bar/foo.
280
281
  #
281
- # As a shorthand, you can also use the :path option:
282
- # zip(..).include("foo", :path=>"bar")
282
+ # Returns a Path object. The Path object implements all the same methods, like include, exclude, merge
283
+ # and so forth. It also implements path and root, so that:
284
+ # path("foo").path("bar") == path("foo/bar")
285
+ # path("foo").root == root
283
286
  def path(name)
284
- name.blank? ? @paths[nil] : (@paths[name] ||= Path.new(self, name))
287
+ return @paths[nil] if name.blank?
288
+ @paths[name] ||= Path.new(self, name)
285
289
  end
286
290
 
287
291
  # :call-seq:
288
- # root() => ZipTask
292
+ # root() => ArchiveTask
289
293
  #
290
- # Returns the root path, essentially the ZipTask object itself. In case you are wondering
291
- # down paths and want to go back.
294
+ # Call this on an archive to return itself, and on a path to return the archive.
292
295
  def root()
293
296
  self
294
297
  end
@@ -296,8 +299,8 @@ module Buildr
296
299
  # :call-seq:
297
300
  # with(options) => self
298
301
  #
299
- # Pass options to the task. Returns self. ZipTask itself does not support any options,
300
- # but other tasks (e.g. JarTask, WarTask) do.
302
+ # Passes options to the task and returns self. Some tasks support additional options, for example,
303
+ # the WarTask supports options like :manifest, :libs and :classes.
301
304
  #
302
305
  # For example:
303
306
  # package(:jar).with(:manifest=>"MANIFEST_MF")
@@ -318,7 +321,9 @@ module Buildr
318
321
  end
319
322
 
320
323
  def invoke_prerequisites() #:nodoc:
321
- prerequisites.concat @paths.collect { |name, path| path.sources }.flatten
324
+ @prepares.each { |prepare| prepare.call(self) }
325
+ @prepares.clear
326
+ @prerequisites |= @paths.collect { |name, path| path.sources }.flatten
322
327
  super
323
328
  end
324
329
 
@@ -331,7 +336,7 @@ module Buildr
331
336
  # under the task, so instead we handle them individually for each path.
332
337
  #
333
338
  # We need to check that any file we include is not newer than the
334
- # contents of the ZIP. The file itself but also the directory it's
339
+ # contents of the Zip. The file itself but also the directory it's
335
340
  # coming from, since some tasks touch the directory, e.g. when the
336
341
  # content of target/classes is included into a WAR.
337
342
  most_recent = @paths.collect { |name, path| path.sources }.flatten.
@@ -342,10 +347,12 @@ module Buildr
342
347
 
343
348
  protected
344
349
 
345
- # Sub-classes override this method to perform additional creation tasks,
346
- # e.g. creating a manifest file in a JAR.
347
- def create(zip)
348
- @paths.each { |name, obj| obj.actions.each { |action| action[zip] } }
350
+ # Adds a prepare block. These blocks are called early on for adding more content to
351
+ # the archive, before invoking prerequsities. Anything you add here will be invoked
352
+ # as a prerequisite and used to determine whether or not to generate this archive.
353
+ # In contrast, enhance blocks are evaluated after it was decided to create this archive.
354
+ def prepare(&block)
355
+ @prepares << block
349
356
  end
350
357
 
351
358
  def []=(key, value) #:nodoc:
@@ -354,10 +361,40 @@ module Buildr
354
361
 
355
362
  end
356
363
 
364
+
365
+
366
+ # The ZipTask creates a new Zip file. You can include any number of files and and directories,
367
+ # use exclusion patterns, and include files into specific directories.
368
+ #
369
+ # For example:
370
+ # zip("test.zip").tap do |task|
371
+ # task.include "srcs"
372
+ # task.include "README", "LICENSE"
373
+ # end
374
+ #
375
+ # See Buildr#zip and ArchiveTask.
376
+ class ZipTask < ArchiveTask
377
+
378
+ private
379
+
380
+ def create_from(file_map)
381
+ Zip::ZipFile.open(name, Zip::ZipFile::CREATE) do |zip|
382
+ zip.restore_permissions = true
383
+ file_map.each do |path, content|
384
+ zip.mkdir path unless content || zip.find_entry(path)
385
+ zip.add path, content if String === content
386
+ zip.get_output_stream(path) { |output| content.call(output) } if content.respond_to?(:call)
387
+ end
388
+ end
389
+ end
390
+
391
+ end
392
+
393
+
357
394
  # :call-seq:
358
395
  # zip(file) => ZipTask
359
396
  #
360
- # The ZipTask creates a new ZIP file. You can include any number of files and
397
+ # The ZipTask creates a new Zip file. You can include any number of files and
361
398
  # and directories, use exclusion patterns, and include files into specific
362
399
  # directories.
363
400
  #
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: buildr
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.2.2
7
- date: 2007-07-18 00:00:00 -07:00
6
+ version: 1.2.3
7
+ date: 2007-07-26 00:00:00 -07:00
8
8
  summary: A build system that doesn't suck
9
9
  require_paths:
10
10
  - lib
@@ -30,6 +30,7 @@ authors:
30
30
  - Assaf Arkin
31
31
  files:
32
32
  - lib/tasks
33
+ - lib/tasks/tar.rb
33
34
  - lib/tasks/concat.rb
34
35
  - lib/tasks/zip.rb
35
36
  - lib/core
@@ -59,6 +60,7 @@ files:
59
60
  - lib/java/test.rb
60
61
  - lib/java/idea.rb
61
62
  - lib/java/eclipse.rb
63
+ - lib/java/pom.rb
62
64
  - lib/java/java.rb
63
65
  - lib/java/ant.rb
64
66
  - lib/java/artifact.rb
@@ -179,3 +181,21 @@ dependencies:
179
181
  - !ruby/object:Gem::Version
180
182
  version: 1.0.5
181
183
  version:
184
+ - !ruby/object:Gem::Dependency
185
+ name: xml-simple
186
+ version_requirement:
187
+ version_requirements: !ruby/object:Gem::Version::Requirement
188
+ requirements:
189
+ - - "="
190
+ - !ruby/object:Gem::Version
191
+ version: 1.0.11
192
+ version:
193
+ - !ruby/object:Gem::Dependency
194
+ name: archive-tar-minitar
195
+ version_requirement:
196
+ version_requirements: !ruby/object:Gem::Version::Requirement
197
+ requirements:
198
+ - - "="
199
+ - !ruby/object:Gem::Version
200
+ version: 0.5.1
201
+ version: