buildr 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
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: