mguymon-buildr 1.4.5-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. data/CHANGELOG +1291 -0
  2. data/LICENSE +176 -0
  3. data/NOTICE +26 -0
  4. data/README.rdoc +134 -0
  5. data/Rakefile +44 -0
  6. data/_buildr +35 -0
  7. data/_jbuildr +35 -0
  8. data/addon/buildr/antlr.rb +65 -0
  9. data/addon/buildr/bnd.rb +147 -0
  10. data/addon/buildr/cobertura.rb +22 -0
  11. data/addon/buildr/drb.rb +281 -0
  12. data/addon/buildr/emma.rb +22 -0
  13. data/addon/buildr/hibernate.rb +149 -0
  14. data/addon/buildr/javacc.rb +85 -0
  15. data/addon/buildr/jaxb_xjc.rb +72 -0
  16. data/addon/buildr/jdepend.rb +60 -0
  17. data/addon/buildr/jetty.rb +248 -0
  18. data/addon/buildr/jibx.rb +86 -0
  19. data/addon/buildr/nailgun.rb +221 -0
  20. data/addon/buildr/openjpa.rb +88 -0
  21. data/addon/buildr/org/apache/buildr/BuildrNail$Main.class +0 -0
  22. data/addon/buildr/org/apache/buildr/BuildrNail.class +0 -0
  23. data/addon/buildr/org/apache/buildr/BuildrNail.java +41 -0
  24. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  25. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  26. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  27. data/addon/buildr/org/apache/buildr/JettyWrapper.java +144 -0
  28. data/addon/buildr/protobuf.rb +88 -0
  29. data/addon/buildr/xmlbeans.rb +93 -0
  30. data/bin/buildr +19 -0
  31. data/buildr.buildfile +58 -0
  32. data/buildr.gemspec +78 -0
  33. data/doc/_config.yml +1 -0
  34. data/doc/_layouts/default.html +90 -0
  35. data/doc/_layouts/preface.html +22 -0
  36. data/doc/artifacts.textile +217 -0
  37. data/doc/building.textile +276 -0
  38. data/doc/contributing.textile +268 -0
  39. data/doc/css/default.css +236 -0
  40. data/doc/css/print.css +101 -0
  41. data/doc/css/syntax.css +23 -0
  42. data/doc/download.textile +151 -0
  43. data/doc/extending.textile +212 -0
  44. data/doc/images/1442160941-frontcover.jpg +0 -0
  45. data/doc/images/asf-logo.gif +0 -0
  46. data/doc/images/asf-logo.png +0 -0
  47. data/doc/images/buildr-hires.png +0 -0
  48. data/doc/images/buildr.png +0 -0
  49. data/doc/images/favicon.png +0 -0
  50. data/doc/images/growl-icon.tiff +0 -0
  51. data/doc/images/note.png +0 -0
  52. data/doc/images/project-structure.png +0 -0
  53. data/doc/images/tip.png +0 -0
  54. data/doc/images/zbuildr.png +0 -0
  55. data/doc/images/zbuildr.tif +0 -0
  56. data/doc/index.textile +109 -0
  57. data/doc/installing.textile +284 -0
  58. data/doc/languages.textile +599 -0
  59. data/doc/mailing_lists.textile +29 -0
  60. data/doc/more_stuff.textile +845 -0
  61. data/doc/packaging.textile +618 -0
  62. data/doc/preface.textile +54 -0
  63. data/doc/projects.textile +276 -0
  64. data/doc/quick_start.textile +210 -0
  65. data/doc/releasing.textile +117 -0
  66. data/doc/scripts/buildr-git.rb +512 -0
  67. data/doc/scripts/gitflow.rb +296 -0
  68. data/doc/scripts/install-jruby.sh +44 -0
  69. data/doc/scripts/install-linux.sh +73 -0
  70. data/doc/scripts/install-osx.sh +52 -0
  71. data/doc/settings_profiles.textile +287 -0
  72. data/doc/testing.textile +247 -0
  73. data/etc/KEYS +189 -0
  74. data/lib/buildr.rb +44 -0
  75. data/lib/buildr/clojure.rb +34 -0
  76. data/lib/buildr/clojure/shell.rb +52 -0
  77. data/lib/buildr/core.rb +34 -0
  78. data/lib/buildr/core/application.rb +700 -0
  79. data/lib/buildr/core/build.rb +516 -0
  80. data/lib/buildr/core/cc.rb +166 -0
  81. data/lib/buildr/core/checks.rb +253 -0
  82. data/lib/buildr/core/common.rb +151 -0
  83. data/lib/buildr/core/compile.rb +622 -0
  84. data/lib/buildr/core/doc.rb +276 -0
  85. data/lib/buildr/core/environment.rb +129 -0
  86. data/lib/buildr/core/filter.rb +404 -0
  87. data/lib/buildr/core/generate.rb +197 -0
  88. data/lib/buildr/core/help.rb +119 -0
  89. data/lib/buildr/core/jrebel.rb +42 -0
  90. data/lib/buildr/core/linux.rb +30 -0
  91. data/lib/buildr/core/osx.rb +46 -0
  92. data/lib/buildr/core/progressbar.rb +161 -0
  93. data/lib/buildr/core/project.rb +975 -0
  94. data/lib/buildr/core/run.rb +43 -0
  95. data/lib/buildr/core/shell.rb +137 -0
  96. data/lib/buildr/core/test.rb +843 -0
  97. data/lib/buildr/core/transports.rb +575 -0
  98. data/lib/buildr/core/util.rb +537 -0
  99. data/lib/buildr/groovy.rb +20 -0
  100. data/lib/buildr/groovy/bdd.rb +106 -0
  101. data/lib/buildr/groovy/compiler.rb +153 -0
  102. data/lib/buildr/groovy/doc.rb +76 -0
  103. data/lib/buildr/groovy/shell.rb +57 -0
  104. data/lib/buildr/ide.rb +19 -0
  105. data/lib/buildr/ide/eclipse.rb +427 -0
  106. data/lib/buildr/ide/eclipse/java.rb +53 -0
  107. data/lib/buildr/ide/eclipse/plugin.rb +71 -0
  108. data/lib/buildr/ide/eclipse/scala.rb +68 -0
  109. data/lib/buildr/ide/idea.rb +576 -0
  110. data/lib/buildr/java.rb +25 -0
  111. data/lib/buildr/java/ant.rb +94 -0
  112. data/lib/buildr/java/bdd.rb +460 -0
  113. data/lib/buildr/java/cobertura.rb +297 -0
  114. data/lib/buildr/java/commands.rb +223 -0
  115. data/lib/buildr/java/compiler.rb +135 -0
  116. data/lib/buildr/java/deprecated.rb +141 -0
  117. data/lib/buildr/java/doc.rb +86 -0
  118. data/lib/buildr/java/ecj.rb +69 -0
  119. data/lib/buildr/java/emma.rb +244 -0
  120. data/lib/buildr/java/external.rb +73 -0
  121. data/lib/buildr/java/jruby.rb +122 -0
  122. data/lib/buildr/java/jtestr_result.rb +295 -0
  123. data/lib/buildr/java/jtestr_runner.rb.erb +116 -0
  124. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  125. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +142 -0
  126. data/lib/buildr/java/packaging.rb +734 -0
  127. data/lib/buildr/java/pom.rb +178 -0
  128. data/lib/buildr/java/rjb.rb +154 -0
  129. data/lib/buildr/java/test_result.rb +101 -0
  130. data/lib/buildr/java/tests.rb +362 -0
  131. data/lib/buildr/java/version_requirement.rb +172 -0
  132. data/lib/buildr/packaging.rb +25 -0
  133. data/lib/buildr/packaging/archive.rb +535 -0
  134. data/lib/buildr/packaging/artifact.rb +904 -0
  135. data/lib/buildr/packaging/artifact_namespace.rb +984 -0
  136. data/lib/buildr/packaging/artifact_search.rb +140 -0
  137. data/lib/buildr/packaging/gems.rb +105 -0
  138. data/lib/buildr/packaging/package.rb +249 -0
  139. data/lib/buildr/packaging/repository_array.rb +108 -0
  140. data/lib/buildr/packaging/tar.rb +189 -0
  141. data/lib/buildr/packaging/version_requirement.rb +192 -0
  142. data/lib/buildr/packaging/zip.rb +178 -0
  143. data/lib/buildr/packaging/ziptask.rb +356 -0
  144. data/lib/buildr/resources/buildr.icns +0 -0
  145. data/lib/buildr/resources/completed.png +0 -0
  146. data/lib/buildr/resources/failed.png +0 -0
  147. data/lib/buildr/resources/icons-license.txt +17 -0
  148. data/lib/buildr/run.rb +195 -0
  149. data/lib/buildr/scala.rb +26 -0
  150. data/lib/buildr/scala/bdd.rb +118 -0
  151. data/lib/buildr/scala/compiler.rb +242 -0
  152. data/lib/buildr/scala/doc.rb +142 -0
  153. data/lib/buildr/scala/org/apache/buildr/SpecsSingletonRunner.class +0 -0
  154. data/lib/buildr/scala/org/apache/buildr/SpecsSingletonRunner.java +57 -0
  155. data/lib/buildr/scala/shell.rb +52 -0
  156. data/lib/buildr/scala/tests.rb +171 -0
  157. data/lib/buildr/shell.rb +185 -0
  158. data/lib/buildr/version.rb +18 -0
  159. data/rakelib/all-in-one.rake +113 -0
  160. data/rakelib/checks.rake +57 -0
  161. data/rakelib/doc.rake +137 -0
  162. data/rakelib/metrics.rake +39 -0
  163. data/rakelib/package.rake +73 -0
  164. data/rakelib/release.rake +160 -0
  165. data/rakelib/rspec.rake +91 -0
  166. data/rakelib/setup.rake +66 -0
  167. data/rakelib/stage.rake +220 -0
  168. data/spec/addon/bnd_spec.rb +330 -0
  169. data/spec/addon/drb_spec.rb +328 -0
  170. data/spec/addon/jaxb_xjc_spec.rb +125 -0
  171. data/spec/core/application_spec.rb +631 -0
  172. data/spec/core/build_spec.rb +837 -0
  173. data/spec/core/cc_spec.rb +224 -0
  174. data/spec/core/checks_spec.rb +519 -0
  175. data/spec/core/common_spec.rb +725 -0
  176. data/spec/core/compile_spec.rb +658 -0
  177. data/spec/core/doc_spec.rb +195 -0
  178. data/spec/core/extension_spec.rb +201 -0
  179. data/spec/core/generate_spec.rb +33 -0
  180. data/spec/core/project_spec.rb +772 -0
  181. data/spec/core/run_spec.rb +93 -0
  182. data/spec/core/shell_spec.rb +146 -0
  183. data/spec/core/test_spec.rb +1320 -0
  184. data/spec/core/transport_spec.rb +544 -0
  185. data/spec/core/util_spec.rb +141 -0
  186. data/spec/groovy/bdd_spec.rb +80 -0
  187. data/spec/groovy/compiler_spec.rb +251 -0
  188. data/spec/groovy/doc_spec.rb +65 -0
  189. data/spec/ide/eclipse_spec.rb +739 -0
  190. data/spec/ide/idea_spec.rb +1145 -0
  191. data/spec/java/ant_spec.rb +37 -0
  192. data/spec/java/bdd_spec.rb +374 -0
  193. data/spec/java/cobertura_spec.rb +112 -0
  194. data/spec/java/commands_spec.rb +93 -0
  195. data/spec/java/compiler_spec.rb +252 -0
  196. data/spec/java/doc_spec.rb +56 -0
  197. data/spec/java/ecj_spec.rb +115 -0
  198. data/spec/java/emma_spec.rb +121 -0
  199. data/spec/java/external_spec.rb +56 -0
  200. data/spec/java/java_spec.rb +132 -0
  201. data/spec/java/packaging_spec.rb +1266 -0
  202. data/spec/java/run_spec.rb +78 -0
  203. data/spec/java/test_coverage_helper.rb +257 -0
  204. data/spec/java/tests_spec.rb +497 -0
  205. data/spec/packaging/archive_spec.rb +775 -0
  206. data/spec/packaging/artifact_namespace_spec.rb +743 -0
  207. data/spec/packaging/artifact_spec.rb +1074 -0
  208. data/spec/packaging/packaging_helper.rb +63 -0
  209. data/spec/packaging/packaging_spec.rb +719 -0
  210. data/spec/packaging/repository_array_spec.rb +109 -0
  211. data/spec/sandbox.rb +165 -0
  212. data/spec/scala/bdd_spec.rb +124 -0
  213. data/spec/scala/compiler_spec.rb +289 -0
  214. data/spec/scala/doc_spec.rb +88 -0
  215. data/spec/scala/scala.rb +38 -0
  216. data/spec/scala/tests_spec.rb +283 -0
  217. data/spec/spec_helpers.rb +369 -0
  218. data/spec/version_requirement_spec.rb +143 -0
  219. data/spec/xpath_matchers.rb +121 -0
  220. metadata +600 -0
@@ -0,0 +1,172 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+
17
+ module Buildr
18
+
19
+ #
20
+ # See ArtifactNamespace#need
21
+ class VersionRequirement
22
+
23
+ CMP_PROCS = Gem::Requirement::OPS.dup
24
+ CMP_REGEX = Gem::Requirement::OP_RE.dup
25
+ CMP_CHARS = CMP_PROCS.keys.join
26
+ BOOL_CHARS = '\|\&\!'
27
+ VER_CHARS = '\w\.\-'
28
+
29
+ class << self
30
+ # is +str+ a version string?
31
+ def version?(str)
32
+ /^\s*[#{VER_CHARS}]+\s*$/ === str
33
+ end
34
+
35
+ # is +str+ a version requirement?
36
+ def requirement?(str)
37
+ /[#{BOOL_CHARS}#{CMP_CHARS}\(\)]/ === str
38
+ end
39
+
40
+ # :call-seq:
41
+ # VersionRequirement.create(" >1 <2 !(1.5) ") -> requirement
42
+ #
43
+ # parse the +str+ requirement
44
+ def create(str)
45
+ instance_eval normalize(str)
46
+ rescue StandardError => e
47
+ raise "Failed to parse #{str.inspect} due to: #{e}"
48
+ end
49
+
50
+ private
51
+ def requirement(req)
52
+ unless req =~ /^\s*(#{CMP_REGEX})?\s*([#{VER_CHARS}]+)\s*$/
53
+ raise "Invalid requirement string: #{req}"
54
+ end
55
+ comparator, version = $1, $2
56
+ version = Gem::Version.new(0).tap { |v| v.version = version }
57
+ VersionRequirement.new(nil, [$1, version])
58
+ end
59
+
60
+ def negate(vreq)
61
+ vreq.negative = !vreq.negative
62
+ vreq
63
+ end
64
+
65
+ def normalize(str)
66
+ str = str.strip
67
+ if str[/[^\s\(\)#{BOOL_CHARS + VER_CHARS + CMP_CHARS}]/]
68
+ raise "version string #{str.inspect} contains invalid characters"
69
+ end
70
+ str.gsub!(/\s+(and|\&\&)\s+/, ' & ')
71
+ str.gsub!(/\s+(or|\|\|)\s+/, ' | ')
72
+ str.gsub!(/(^|\s*)not\s+/, ' ! ')
73
+ pattern = /(#{CMP_REGEX})?\s*[#{VER_CHARS}]+/
74
+ left_pattern = /[#{VER_CHARS}\)]$/
75
+ right_pattern = /^(#{pattern}|\()/
76
+ str = str.split.inject([]) do |ary, i|
77
+ ary << '&' if ary.last =~ left_pattern && i =~ right_pattern
78
+ ary << i
79
+ end
80
+ str = str.join(' ')
81
+ str.gsub!(/!([^=])?/, ' negate \1')
82
+ str.gsub!(pattern) do |expr|
83
+ case expr.strip
84
+ when 'not', 'negate' then 'negate '
85
+ else 'requirement("' + expr + '")'
86
+ end
87
+ end
88
+ str.gsub!(/negate\s+\(/, 'negate(')
89
+ str
90
+ end
91
+ end
92
+
93
+ def initialize(op, *requirements) #:nodoc:
94
+ @op, @requirements = op, requirements
95
+ end
96
+
97
+ # Is this object a composed requirement?
98
+ # VersionRequirement.create('1').composed? -> false
99
+ # VersionRequirement.create('1 | 2').composed? -> true
100
+ # VersionRequirement.create('1 & 2').composed? -> true
101
+ def composed?
102
+ requirements.size > 1
103
+ end
104
+
105
+ # Return the last requirement on this object having an = operator.
106
+ def default
107
+ default = nil
108
+ requirements.reverse.find do |r|
109
+ if Array === r
110
+ if !negative && (r.first.nil? || r.first.include?('='))
111
+ default = r.last.to_s
112
+ end
113
+ else
114
+ default = r.default
115
+ end
116
+ end
117
+ default
118
+ end
119
+
120
+ # Test if this requirement can be satisfied by +version+
121
+ def satisfied_by?(version)
122
+ return false unless version
123
+ unless version.kind_of?(Gem::Version)
124
+ raise "Invalid version: #{version.inspect}" unless self.class.version?(version)
125
+ version = Gem::Version.new(0).tap { |v| v.version = version.strip }
126
+ end
127
+ message = op == :| ? :any? : :all?
128
+ result = requirements.send message do |req|
129
+ if Array === req
130
+ cmp, rv = *req
131
+ CMP_PROCS[cmp || '='].call(version, rv)
132
+ else
133
+ req.satisfied_by?(version)
134
+ end
135
+ end
136
+ negative ? !result : result
137
+ end
138
+
139
+ # Either modify the current requirement (if it's already an or operation)
140
+ # or create a new requirement
141
+ def |(other)
142
+ operation(:|, other)
143
+ end
144
+
145
+ # Either modify the current requirement (if it's already an and operation)
146
+ # or create a new requirement
147
+ def &(other)
148
+ operation(:&, other)
149
+ end
150
+
151
+ # return the parsed expression
152
+ def to_s
153
+ str = requirements.map(&:to_s).join(" " + @op.to_s + " ").to_s
154
+ str = "( " + str + " )" if negative || requirements.size > 1
155
+ str = "!" + str if negative
156
+ str
157
+ end
158
+
159
+ attr_accessor :negative
160
+ protected
161
+ attr_reader :requirements, :op
162
+ def operation(op, other)
163
+ @op ||= op
164
+ if negative == other.negative && @op == op && other.requirements.size == 1
165
+ @requirements << other.requirements.first
166
+ self
167
+ else
168
+ self.class.new(op, self, other)
169
+ end
170
+ end
171
+ end # VersionRequirement
172
+ end
@@ -0,0 +1,25 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+
17
+ require 'buildr/packaging/artifact'
18
+ require 'buildr/packaging/package'
19
+ require 'buildr/packaging/archive'
20
+ require 'buildr/packaging/ziptask'
21
+ require 'buildr/packaging/tar'
22
+ require 'buildr/packaging/gems'
23
+ require 'buildr/packaging/zip'
24
+ autoload :Zlib, 'zlib'
25
+
@@ -0,0 +1,535 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+
17
+ module Buildr
18
+
19
+ # Base class for ZipTask, TarTask and other archives.
20
+ class ArchiveTask < Rake::FileTask
21
+
22
+ # Which files go where. All the rules for including, excluding and merging files
23
+ # are handled by this object.
24
+ class Path #:nodoc:
25
+
26
+ # Returns the archive from this path.
27
+ attr_reader :root
28
+
29
+ def initialize(root, path)
30
+ @root = root
31
+ @path = path.empty? ? path : "#{path}/"
32
+ @includes = FileList[]
33
+ @excludes = []
34
+ # Expand source files added to this path.
35
+ expand_src = proc { @includes.map{ |file| file.to_s }.uniq }
36
+ @sources = [ expand_src ]
37
+ # Add files and directories added to this path.
38
+ @actions = [] << proc do |file_map|
39
+ expand_src.call.each do |path|
40
+ unless excluded?(path)
41
+ if File.directory?(path)
42
+ in_directory path do |file, rel_path|
43
+ dest = "#{@path}#{rel_path}"
44
+ unless excluded?(dest)
45
+ trace "Adding #{dest}"
46
+ file_map[dest] = file
47
+ end
48
+ end
49
+ end
50
+ unless File.basename(path) == "."
51
+ trace "Adding #{@path}#{File.basename(path)}"
52
+ file_map["#{@path}#{File.basename(path)}"] = path
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ # :call-seq:
60
+ # include(*files) => self
61
+ # include(*files, :path=>path) => self
62
+ # include(file, :as=>name) => self
63
+ # include(:from=>path) => self
64
+ # include(*files, :merge=>true) => self
65
+ def include(*args)
66
+ options = args.pop if Hash === args.last
67
+ files = to_artifacts(args)
68
+ raise 'AchiveTask.include() values should not include nil' if files.include? nil
69
+
70
+ if options.nil? || options.empty?
71
+ @includes.include *files.flatten
72
+ elsif options[:path]
73
+ sans_path = options.reject { |k,v| k == :path }
74
+ path(options[:path]).include *files + [sans_path]
75
+ elsif options[:as]
76
+ raise 'You can only use the :as option in combination with the :path option' unless options.size == 1
77
+ raise 'You can only use one file with the :as option' unless files.size == 1
78
+ include_as files.first.to_s, options[:as]
79
+ elsif options[:from]
80
+ raise 'You can only use the :from option in combination with the :path option' unless options.size == 1
81
+ raise 'You cannot use the :from option with file names' unless files.empty?
82
+ fail 'AchiveTask.include() :from value should not be nil' if [options[:from]].flatten.include? nil
83
+ [options[:from]].flatten.each { |path| include_as path.to_s, '.' }
84
+ elsif options[:merge]
85
+ raise 'You can only use the :merge option in combination with the :path option' unless options.size == 1
86
+ files.each { |file| merge file }
87
+ else
88
+ raise "Unrecognized option #{options.keys.join(', ')}"
89
+ end
90
+ self
91
+ end
92
+ alias :add :include
93
+ alias :<< :include
94
+
95
+ # :call-seq:
96
+ # exclude(*files) => self
97
+ def exclude(*files)
98
+ files = to_artifacts(files)
99
+ @excludes |= files
100
+ @excludes |= files.reject { |f| f =~ /\*$/ }.map { |f| "#{f}/*" }
101
+ self
102
+ end
103
+
104
+ # :call-seq:
105
+ # merge(*files) => Merge
106
+ # merge(*files, :path=>name) => Merge
107
+ def merge(*args)
108
+ options = Hash === args.last ? args.pop : {}
109
+ files = to_artifacts(args)
110
+ rake_check_options options, :path
111
+ raise ArgumentError, "Expected at least one file to merge" if files.empty?
112
+ path = options[:path] || @path
113
+ expanders = files.collect do |file|
114
+ @sources << proc { file.to_s }
115
+ expander = ZipExpander.new(file)
116
+ @actions << proc do |file_map|
117
+ file.invoke() if file.is_a?(Rake::Task)
118
+ expander.expand(file_map, path)
119
+ end
120
+ expander
121
+ end
122
+ Merge.new(expanders)
123
+ end
124
+
125
+ # Returns a Path relative to this one.
126
+ def path(path)
127
+ return self if path.nil?
128
+ return root.path(path[1..-1]) if path[0] == ?/
129
+ root.path("#{@path}#{path}")
130
+ end
131
+
132
+ # Returns all the source files.
133
+ def sources #:nodoc:
134
+ @sources.map{ |source| source.call }.flatten
135
+ end
136
+
137
+ def add_files(file_map) #:nodoc:
138
+ @actions.each { |action| action.call(file_map) }
139
+ end
140
+
141
+ # :call-seq:
142
+ # exist => boolean
143
+ #
144
+ # Returns true if this path exists. This only works if the path has any entries in it,
145
+ # so exist on path happens to be the opposite of empty.
146
+ def exist?
147
+ !entries.empty?
148
+ end
149
+
150
+ # :call-seq:
151
+ # empty? => boolean
152
+ #
153
+ # Returns true if this path is empty (has no other entries inside).
154
+ def empty?
155
+ entries.all? { |entry| entry.empty? }
156
+ end
157
+
158
+ # :call-seq:
159
+ # contain(file*) => boolean
160
+ #
161
+ # Returns true if this ZIP file path contains all the specified files. You can use relative
162
+ # file names and glob patterns (using *, **, etc).
163
+ def contain?(*files)
164
+ files.all? { |file| entries.detect { |entry| File.fnmatch(file, entry.to_s) } }
165
+ end
166
+
167
+ # :call-seq:
168
+ # entry(name) => ZipEntry
169
+ #
170
+ # Returns a ZIP file entry. You can use this to check if the entry exists and its contents,
171
+ # for example:
172
+ # package(:jar).path("META-INF").entry("LICENSE").should contain(/Apache Software License/)
173
+ def entry(name)
174
+ root.entry("#{@path}#{name}")
175
+ end
176
+
177
+ def to_s
178
+ @path
179
+ end
180
+
181
+ protected
182
+
183
+ # Convert objects to artifacts, where applicable
184
+ def to_artifacts(files)
185
+ files.flatten.inject([]) do |set, file|
186
+ case file
187
+ when ArtifactNamespace
188
+ set |= file.artifacts
189
+ when Symbol, Hash
190
+ set |= [artifact(file)]
191
+ when /([^:]+:){2,4}/ # A spec as opposed to a file name.
192
+ set |= [Buildr.artifact(file)]
193
+ when Project
194
+ set |= Buildr.artifacts(file.packages)
195
+ when Rake::Task
196
+ set |= [file]
197
+ when Struct
198
+ set |= Buildr.artifacts(file.values)
199
+ else
200
+ # non-artifacts passed as-is; in particular, String paths are
201
+ # unmodified since Rake FileTasks don't use absolute paths
202
+ set |= [file]
203
+ end
204
+ end
205
+ end
206
+
207
+ def include_as(source, as)
208
+ @sources << proc { source }
209
+ @actions << proc do |file_map|
210
+ file = source.to_s
211
+ unless excluded?(file)
212
+ if File.directory?(file)
213
+ in_directory file do |file, rel_path|
214
+ path = rel_path.split('/')[1..-1]
215
+ path.unshift as unless as == '.'
216
+ dest = "#{@path}#{path.join('/')}"
217
+ unless excluded?(dest)
218
+ trace "Adding #{dest}"
219
+ file_map[dest] = file
220
+ end
221
+ end
222
+ unless as == "."
223
+ trace "Adding #{@path}#{as}/"
224
+ file_map["#{@path}#{as}/"] = nil # :as is a folder, so the trailing / is required.
225
+ end
226
+ else
227
+ file_map["#{@path}#{as}"] = file
228
+ end
229
+
230
+ end
231
+ end
232
+ end
233
+
234
+ def in_directory(dir)
235
+ prefix = Regexp.new('^' + Regexp.escape(File.dirname(dir) + File::SEPARATOR))
236
+ Util.recursive_with_dot_files(dir).reject { |file| excluded?(file) }.
237
+ each { |file| yield file, file.sub(prefix, '') }
238
+ end
239
+
240
+ def excluded?(file)
241
+ @excludes.any? { |exclude| File.fnmatch(exclude, file) }
242
+ end
243
+
244
+ def entries #:nodoc:
245
+ return root.entries unless @path
246
+ @entries ||= root.entries.inject([]) { |selected, entry|
247
+ selected << entry.name.sub(@path, "") if entry.name.index(@path) == 0
248
+ selected
249
+ }
250
+ end
251
+
252
+ end
253
+
254
+
255
+ class Merge
256
+ def initialize(expanders)
257
+ @expanders = expanders
258
+ end
259
+
260
+ def include(*files)
261
+ @expanders.each { |expander| expander.include(*files) }
262
+ self
263
+ end
264
+ alias :<< :include
265
+
266
+ def exclude(*files)
267
+ @expanders.each { |expander| expander.exclude(*files) }
268
+ self
269
+ end
270
+ end
271
+
272
+
273
+ # Extend one Zip file into another.
274
+ class ZipExpander #:nodoc:
275
+
276
+ def initialize(zip_file)
277
+ @zip_file = zip_file.to_s
278
+ @includes = []
279
+ @excludes = []
280
+ end
281
+
282
+ def include(*files)
283
+ @includes |= files
284
+ self
285
+ end
286
+ alias :<< :include
287
+
288
+ def exclude(*files)
289
+ @excludes |= files
290
+ self
291
+ end
292
+
293
+ def expand(file_map, path)
294
+ @includes = ['*'] if @includes.empty?
295
+ Zip::ZipFile.open(@zip_file) do |source|
296
+ source.entries.reject { |entry| entry.directory? }.each do |entry|
297
+ if @includes.any? { |pattern| File.fnmatch(pattern, entry.name) } &&
298
+ !@excludes.any? { |pattern| File.fnmatch(pattern, entry.name) }
299
+ dest = path =~ /^\/?$/ ? entry.name : Util.relative_path(path + "/" + entry.name)
300
+ trace "Adding #{dest}"
301
+ file_map[dest] = lambda { |output| output.write source.read(entry) }
302
+ end
303
+ end
304
+ end
305
+ end
306
+
307
+ end
308
+
309
+
310
+ def initialize(*args) #:nodoc:
311
+ super
312
+ clean
313
+
314
+ # Make sure we're the last enhancements, so other enhancements can add content.
315
+ enhance do
316
+ @file_map = {}
317
+ enhance do
318
+ send 'create' if respond_to?(:create)
319
+ # We're here because the archive file does not exist, or one of the files is newer than the archive contents;
320
+ # we need to make sure the archive doesn't exist (e.g. opening an existing Zip will add instead of create).
321
+ # We also want to protect against partial updates.
322
+ rm name rescue nil
323
+ mkpath File.dirname(name)
324
+ begin
325
+ @paths.each do |name, object|
326
+ @file_map[name] = nil unless name.empty?
327
+ object.add_files(@file_map)
328
+ end
329
+ create_from @file_map
330
+ rescue
331
+ rm name rescue nil
332
+ raise
333
+ end
334
+ end
335
+ end
336
+ end
337
+
338
+ # :call-seq:
339
+ # clean => self
340
+ #
341
+ # Removes all previously added content from this archive.
342
+ # Use this method if you want to remove default content from a package.
343
+ # For example, package(:jar) by default includes compiled classes and resources,
344
+ # using this method, you can create an empty jar and afterwards add the
345
+ # desired content to it.
346
+ #
347
+ # package(:jar).clean.include path_to('desired/content')
348
+ def clean
349
+ @paths = { '' => Path.new(self, '') }
350
+ @prepares = []
351
+ self
352
+ end
353
+
354
+ # :call-seq:
355
+ # include(*files) => self
356
+ # include(*files, :path=>path) => self
357
+ # include(file, :as=>name) => self
358
+ # include(:from=>path) => self
359
+ # include(*files, :merge=>true) => self
360
+ #
361
+ # Include files in this archive, or when called on a path, within that path. Returns self.
362
+ #
363
+ # The first form accepts a list of files, directories and glob patterns and adds them to the archive.
364
+ # For example, to include the file foo, directory bar (including all files in there) and all files under baz:
365
+ # zip(..).include('foo', 'bar', 'baz/*')
366
+ #
367
+ # The second form is similar but adds files/directories under the specified path. For example,
368
+ # to add foo as bar/foo:
369
+ # zip(..).include('foo', :path=>'bar')
370
+ # The :path option is the same as using the path method:
371
+ # zip(..).path('bar').include('foo')
372
+ # All other options can be used in combination with the :path option.
373
+ #
374
+ # The third form adds a file or directory under a different name. For example, to add the file foo under the
375
+ # name bar:
376
+ # zip(..).include('foo', :as=>'bar')
377
+ #
378
+ # The fourth form adds the contents of a directory using the directory as a prerequisite:
379
+ # zip(..).include(:from=>'foo')
380
+ # Unlike <code>include('foo')</code> it includes the contents of the directory, not the directory itself.
381
+ # Unlike <code>include('foo/*')</code>, it uses the directory timestamp for dependency management.
382
+ #
383
+ # The fifth form includes the contents of another archive by expanding it into this archive. For example:
384
+ # zip(..).include('foo.zip', :merge=>true).include('bar.zip')
385
+ # You can also use the method #merge.
386
+ def include(*files)
387
+ fail "AchiveTask.include() called with nil values" if files.include? nil
388
+ @paths[''].include *files if files.compact.size > 0
389
+ self
390
+ end
391
+ alias :add :include
392
+ alias :<< :include
393
+
394
+ # :call-seq:
395
+ # exclude(*files) => self
396
+ #
397
+ # Excludes files and returns self. Can be used in combination with include to prevent some files from being included.
398
+ def exclude(*files)
399
+ @paths[''].exclude *files
400
+ self
401
+ end
402
+
403
+ # :call-seq:
404
+ # merge(*files) => Merge
405
+ # merge(*files, :path=>name) => Merge
406
+ #
407
+ # Merges another archive into this one by including the individual files from the merged archive.
408
+ #
409
+ # Returns an object that supports two methods: include and exclude. You can use these methods to merge
410
+ # only specific files. For example:
411
+ # zip(..).merge('src.zip').include('module1/*')
412
+ def merge(*files)
413
+ @paths[''].merge *files
414
+ end
415
+
416
+ # :call-seq:
417
+ # path(name) => Path
418
+ #
419
+ # Returns a path object. Use the path object to include files under a path, for example, to include
420
+ # the file 'foo' as 'bar/foo':
421
+ # zip(..).path('bar').include('foo')
422
+ #
423
+ # Returns a Path object. The Path object implements all the same methods, like include, exclude, merge
424
+ # and so forth. It also implements path and root, so that:
425
+ # path('foo').path('bar') == path('foo/bar')
426
+ # path('foo').root == root
427
+ def path(name)
428
+ return @paths[''] if name.nil?
429
+ normalized = name.split('/').inject([]) do |path, part|
430
+ case part
431
+ when '.', nil, ''
432
+ path
433
+ when '..'
434
+ path[0...-1]
435
+ else
436
+ path << part
437
+ end
438
+ end.join('/')
439
+ @paths[normalized] ||= Path.new(self, normalized)
440
+ end
441
+
442
+ # :call-seq:
443
+ # root => ArchiveTask
444
+ #
445
+ # Call this on an archive to return itself, and on a path to return the archive.
446
+ def root
447
+ self
448
+ end
449
+
450
+ # :call-seq:
451
+ # with(options) => self
452
+ #
453
+ # Passes options to the task and returns self. Some tasks support additional options, for example,
454
+ # the WarTask supports options like :manifest, :libs and :classes.
455
+ #
456
+ # For example:
457
+ # package(:jar).with(:manifest=>'MANIFEST_MF')
458
+ def with(options)
459
+ options.each do |key, value|
460
+ begin
461
+ send "#{key}=", value
462
+ rescue NoMethodError
463
+ raise ArgumentError, "#{self.class.name} does not support the option #{key}"
464
+ end
465
+ end
466
+ self
467
+ end
468
+
469
+ def invoke_prerequisites(args, chain) #:nodoc:
470
+ @prepares.each { |prepare| prepare.call(self) }
471
+ @prepares.clear
472
+
473
+ file_map = {}
474
+ @paths.each do |name, path|
475
+ path.add_files(file_map)
476
+ end
477
+
478
+ # filter out Procs (dynamic content), nils and others
479
+ @prerequisites |= file_map.values.select { |src| src.is_a?(String) || src.is_a?(Rake::Task) }
480
+
481
+ super
482
+ end
483
+
484
+ def needed? #:nodoc:
485
+ return true unless File.exist?(name)
486
+ # You can do something like:
487
+ # include('foo', :path=>'foo').exclude('foo/bar', path=>'foo').
488
+ # include('foo/bar', :path=>'foo/bar')
489
+ # This will play havoc if we handled all the prerequisites together
490
+ # under the task, so instead we handle them individually for each path.
491
+ #
492
+ # We need to check that any file we include is not newer than the
493
+ # contents of the Zip. The file itself but also the directory it's
494
+ # coming from, since some tasks touch the directory, e.g. when the
495
+ # content of target/classes is included into a WAR.
496
+ most_recent = @paths.collect { |name, path| path.sources }.flatten.
497
+ select { |file| File.exist?(file) }.collect { |file| File.stat(file).mtime }.max
498
+ File.stat(name).mtime < (most_recent || Rake::EARLY) || super
499
+ end
500
+
501
+ # :call-seq:
502
+ # empty? => boolean
503
+ #
504
+ # Returns true if this ZIP file is empty (has no other entries inside).
505
+ def empty?
506
+ path("").empty
507
+ end
508
+
509
+ # :call-seq:
510
+ # contain(file*) => boolean
511
+ #
512
+ # Returns true if this ZIP file contains all the specified files. You can use absolute
513
+ # file names and glob patterns (using *, **, etc).
514
+ def contain?(*files)
515
+ path("").contain?(*files)
516
+ end
517
+
518
+ protected
519
+
520
+ # Adds a prepare block. These blocks are called early on for adding more content to
521
+ # the archive, before invoking prerequsities. Anything you add here will be invoked
522
+ # as a prerequisite and used to determine whether or not to generate this archive.
523
+ # In contrast, enhance blocks are evaluated after it was decided to create this archive.
524
+ def prepare(&block)
525
+ @prepares << block
526
+ end
527
+
528
+ def []=(key, value) #:nodoc:
529
+ raise ArgumentError, "This task does not support the option #{key}."
530
+ end
531
+
532
+ end
533
+
534
+
535
+ end