assaf-buildr 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. data/CHANGELOG +887 -0
  2. data/DISCLAIMER +7 -0
  3. data/LICENSE +176 -0
  4. data/NOTICE +26 -0
  5. data/README.rdoc +146 -0
  6. data/Rakefile +62 -0
  7. data/_buildr +38 -0
  8. data/addon/buildr/antlr.rb +65 -0
  9. data/addon/buildr/cobertura.rb +236 -0
  10. data/addon/buildr/emma.rb +238 -0
  11. data/addon/buildr/hibernate.rb +142 -0
  12. data/addon/buildr/javacc.rb +85 -0
  13. data/addon/buildr/jdepend.rb +60 -0
  14. data/addon/buildr/jetty.rb +248 -0
  15. data/addon/buildr/jibx.rb +86 -0
  16. data/addon/buildr/nailgun.rb +817 -0
  17. data/addon/buildr/openjpa.rb +90 -0
  18. data/addon/buildr/org/apache/buildr/BuildrNail$Main.class +0 -0
  19. data/addon/buildr/org/apache/buildr/BuildrNail.class +0 -0
  20. data/addon/buildr/org/apache/buildr/BuildrNail.java +41 -0
  21. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  22. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  23. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  24. data/addon/buildr/org/apache/buildr/JettyWrapper.java +144 -0
  25. data/addon/buildr/xmlbeans.rb +93 -0
  26. data/bin/buildr +28 -0
  27. data/buildr.buildfile +53 -0
  28. data/buildr.gemspec +58 -0
  29. data/doc/css/default.css +228 -0
  30. data/doc/css/print.css +100 -0
  31. data/doc/css/syntax.css +52 -0
  32. data/doc/images/apache-incubator-logo.png +0 -0
  33. data/doc/images/buildr-hires.png +0 -0
  34. data/doc/images/buildr.png +0 -0
  35. data/doc/images/favicon.png +0 -0
  36. data/doc/images/growl-icon.tiff +0 -0
  37. data/doc/images/note.png +0 -0
  38. data/doc/images/project-structure.png +0 -0
  39. data/doc/images/tip.png +0 -0
  40. data/doc/images/zbuildr.tif +0 -0
  41. data/doc/pages/artifacts.textile +207 -0
  42. data/doc/pages/building.textile +240 -0
  43. data/doc/pages/contributing.textile +208 -0
  44. data/doc/pages/download.textile +62 -0
  45. data/doc/pages/extending.textile +175 -0
  46. data/doc/pages/getting_started.textile +273 -0
  47. data/doc/pages/index.textile +42 -0
  48. data/doc/pages/languages.textile +407 -0
  49. data/doc/pages/mailing_lists.textile +17 -0
  50. data/doc/pages/more_stuff.textile +286 -0
  51. data/doc/pages/packaging.textile +427 -0
  52. data/doc/pages/projects.textile +274 -0
  53. data/doc/pages/recipes.textile +103 -0
  54. data/doc/pages/settings_profiles.textile +274 -0
  55. data/doc/pages/testing.textile +212 -0
  56. data/doc/pages/troubleshooting.textile +103 -0
  57. data/doc/pages/whats_new.textile +323 -0
  58. data/doc/print.haml +51 -0
  59. data/doc/print.toc.yaml +29 -0
  60. data/doc/scripts/buildr-git.rb +412 -0
  61. data/doc/scripts/install-jruby.sh +44 -0
  62. data/doc/scripts/install-linux.sh +64 -0
  63. data/doc/scripts/install-osx.sh +52 -0
  64. data/doc/site.haml +56 -0
  65. data/doc/site.toc.yaml +47 -0
  66. data/etc/KEYS +151 -0
  67. data/etc/git-svn-authors +16 -0
  68. data/lib/buildr.rb +35 -0
  69. data/lib/buildr/core.rb +27 -0
  70. data/lib/buildr/core/application.rb +489 -0
  71. data/lib/buildr/core/application_cli.rb +139 -0
  72. data/lib/buildr/core/build.rb +311 -0
  73. data/lib/buildr/core/checks.rb +382 -0
  74. data/lib/buildr/core/common.rb +154 -0
  75. data/lib/buildr/core/compile.rb +596 -0
  76. data/lib/buildr/core/environment.rb +120 -0
  77. data/lib/buildr/core/filter.rb +362 -0
  78. data/lib/buildr/core/generate.rb +195 -0
  79. data/lib/buildr/core/help.rb +118 -0
  80. data/lib/buildr/core/progressbar.rb +156 -0
  81. data/lib/buildr/core/project.rb +892 -0
  82. data/lib/buildr/core/test.rb +715 -0
  83. data/lib/buildr/core/transports.rb +558 -0
  84. data/lib/buildr/core/util.rb +289 -0
  85. data/lib/buildr/groovy.rb +18 -0
  86. data/lib/buildr/groovy/bdd.rb +105 -0
  87. data/lib/buildr/groovy/compiler.rb +138 -0
  88. data/lib/buildr/ide.rb +19 -0
  89. data/lib/buildr/ide/eclipse.rb +212 -0
  90. data/lib/buildr/ide/idea.ipr.template +300 -0
  91. data/lib/buildr/ide/idea.rb +189 -0
  92. data/lib/buildr/ide/idea7x.ipr.template +290 -0
  93. data/lib/buildr/ide/idea7x.rb +210 -0
  94. data/lib/buildr/java.rb +23 -0
  95. data/lib/buildr/java/ant.rb +92 -0
  96. data/lib/buildr/java/bdd.rb +449 -0
  97. data/lib/buildr/java/commands.rb +211 -0
  98. data/lib/buildr/java/compiler.rb +348 -0
  99. data/lib/buildr/java/deprecated.rb +141 -0
  100. data/lib/buildr/java/jruby.rb +117 -0
  101. data/lib/buildr/java/jtestr_runner.rb.erb +116 -0
  102. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  103. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +119 -0
  104. data/lib/buildr/java/packaging.rb +713 -0
  105. data/lib/buildr/java/pom.rb +178 -0
  106. data/lib/buildr/java/rjb.rb +155 -0
  107. data/lib/buildr/java/test_result.rb +308 -0
  108. data/lib/buildr/java/tests.rb +324 -0
  109. data/lib/buildr/java/version_requirement.rb +172 -0
  110. data/lib/buildr/packaging.rb +21 -0
  111. data/lib/buildr/packaging/artifact.rb +730 -0
  112. data/lib/buildr/packaging/artifact_namespace.rb +972 -0
  113. data/lib/buildr/packaging/artifact_search.rb +140 -0
  114. data/lib/buildr/packaging/gems.rb +102 -0
  115. data/lib/buildr/packaging/package.rb +233 -0
  116. data/lib/buildr/packaging/tar.rb +104 -0
  117. data/lib/buildr/packaging/zip.rb +722 -0
  118. data/lib/buildr/resources/buildr.icns +0 -0
  119. data/lib/buildr/scala.rb +19 -0
  120. data/lib/buildr/scala/compiler.rb +109 -0
  121. data/lib/buildr/scala/tests.rb +203 -0
  122. data/rakelib/apache.rake +191 -0
  123. data/rakelib/changelog.rake +57 -0
  124. data/rakelib/doc.rake +103 -0
  125. data/rakelib/package.rake +73 -0
  126. data/rakelib/release.rake +65 -0
  127. data/rakelib/rspec.rake +83 -0
  128. data/rakelib/rubyforge.rake +53 -0
  129. data/rakelib/scm.rake +49 -0
  130. data/rakelib/setup.rake +86 -0
  131. data/rakelib/stage.rake +48 -0
  132. data/spec/addon/cobertura_spec.rb +77 -0
  133. data/spec/addon/emma_spec.rb +120 -0
  134. data/spec/addon/test_coverage_spec.rb +255 -0
  135. data/spec/core/application_spec.rb +412 -0
  136. data/spec/core/artifact_namespace_spec.rb +646 -0
  137. data/spec/core/build_spec.rb +415 -0
  138. data/spec/core/checks_spec.rb +537 -0
  139. data/spec/core/common_spec.rb +664 -0
  140. data/spec/core/compile_spec.rb +566 -0
  141. data/spec/core/generate_spec.rb +33 -0
  142. data/spec/core/project_spec.rb +754 -0
  143. data/spec/core/test_spec.rb +1091 -0
  144. data/spec/core/transport_spec.rb +500 -0
  145. data/spec/groovy/bdd_spec.rb +80 -0
  146. data/spec/groovy/compiler_spec.rb +239 -0
  147. data/spec/ide/eclipse_spec.rb +243 -0
  148. data/spec/java/ant.rb +28 -0
  149. data/spec/java/bdd_spec.rb +358 -0
  150. data/spec/java/compiler_spec.rb +446 -0
  151. data/spec/java/java_spec.rb +88 -0
  152. data/spec/java/packaging_spec.rb +1103 -0
  153. data/spec/java/tests_spec.rb +466 -0
  154. data/spec/packaging/archive_spec.rb +503 -0
  155. data/spec/packaging/artifact_spec.rb +754 -0
  156. data/spec/packaging/packaging_helper.rb +63 -0
  157. data/spec/packaging/packaging_spec.rb +589 -0
  158. data/spec/sandbox.rb +137 -0
  159. data/spec/scala/compiler_spec.rb +228 -0
  160. data/spec/scala/tests_spec.rb +215 -0
  161. data/spec/spec_helpers.rb +304 -0
  162. data/spec/version_requirement_spec.rb +123 -0
  163. metadata +369 -0
@@ -0,0 +1,972 @@
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/java/version_requirement'
18
+
19
+
20
+ module Buildr
21
+
22
+ # An ArtifactNamespace is a hierarchical dictionary used to manage ArtifactRequirements.
23
+ # It can be used to have different artifact versions per project
24
+ # or to allow users to select a version for addons or modules.
25
+ #
26
+ # Namespaces are opened using the Buildr.artifact_ns method, most important methods are:
27
+ # [need] Used to create a requirement on the namespace.
28
+ # [use] Set the artifact version to use for a requirement.
29
+ # [values_at] Reference requirements by name.
30
+ # [each] Return each ArtifactRequirement in the namespace.
31
+ # The method_missing method for instances provides some syntactic sugar to these.
32
+ # See the following examples, and the methods for ArtifactRequirement.
33
+ #
34
+ # = Avoiding constant polution on buildfile
35
+ #
36
+ # Each project has its own ArtifactNamespace inheriting the one from the
37
+ # parent project up to the root namespace.
38
+ #
39
+ # Consider the following snippet, as project grows, each subproject
40
+ # may need diferent artifact combinations and/or versions. Asigning
41
+ # artifact specifications to constants can make it painful to maintain
42
+ # their references even if using structs/hashes.
43
+ #
44
+ # -- buildfile --
45
+ # SPRING = 'org.springframework:spring:jar:2.5'
46
+ # SPRING_OLD = 'org.springframework:spring:jar:1.0'
47
+ # LOGGING = ['comons-logging:commons-logging:jar:1.1.1',
48
+ # 'log4j:log4j:jar:1.2.15']
49
+ # WL_LOGGING = artifact('bea:wlcommons-logging:jar:8.1').from('path/to/wlcommons-logging.jar')
50
+ # LOGGING_WEBLOGIC = ['comons-logging:commons-logging:jar:1.1.1',
51
+ # WL_LOGGING]
52
+ # COMMONS = struct :collections => 'commons-collection:commons-collection:jar:3.1',
53
+ # :net => 'commons-net:commons-net:jar:1.4.0'
54
+ #
55
+ # define 'example1' do
56
+ # define 'one' do
57
+ # compile.with SPRING, LOGGING_WEBLOGIC, COMMONS
58
+ # end
59
+ # define 'two' do
60
+ # compile.with SPRING_OLD, LOGGING, COMMONS
61
+ # end
62
+ # define 'three' do
63
+ # compile.with "commons-collections:commons-collections:jar:2.2"
64
+ # end
65
+ # end
66
+ #
67
+ #
68
+ # With ArtifactNamespace you can do some more advanced stuff, the following
69
+ # annotated snipped could still be reduced if default artifact definitions were
70
+ # loaded from yaml file (see section bellow and ArtifactNamespace.load).
71
+ #
72
+ # -- buildfile --
73
+ # artifact_ns do |ns| # the current namespace (root if called outside a project)
74
+ # # default artifacts
75
+ # ns.spring = 'org.springframework:spring:jar:2.5'
76
+ # # default logger is log4j
77
+ # ns.logger = 'log4j:log4j:jar:1.2.15'
78
+ #
79
+ # # create a sub namespace by calling the #ns method,
80
+ # # artifacts defined on the sub-namespace can be referenced by
81
+ # # name :commons_net or by calling commons.net
82
+ # ns.ns :commons, :net => 'commons-net:commons-net:jar:1.4.0',
83
+ # :logging => 'comons-logging:commons-logging:jar:1.1.1'
84
+ #
85
+ #
86
+ # # When a child namespace asks for the :log artifact,
87
+ # # these artifacts will be searched starting from the :current namespace.
88
+ # ns.virtual :log, :logger, :commons_logging
89
+ # end
90
+ #
91
+ # artifact_ns('example2:one') do |ns| # namespace for the one subproject
92
+ # ns.logger = artifact('bea:wlcommons-logging:jar:8.1').from('path/to/wlcommons-logging.jar')
93
+ # end
94
+ # artifact_ns('example2:two') do |ns|
95
+ # ns.spring = '1.0' # for project two use an older spring version (just for an example)
96
+ # end
97
+ # artifact_ns('example2:three').commons_collections = 2.2'
98
+ # artifact_ns('example2:four') do |ns|
99
+ # ns.beanutils = 'commons-beanutils:commons-beanutils:jar:1.5' # just for this project
100
+ # ns.ns(:compilation).use :commons_logging, :beanutils, :spring # compile time dependencies
101
+ # ns.ns(:testing).use :log, :beanutils, 'cglib:cglib-nodep:jar:2.1.3' # run time dependencies
102
+ # end
103
+ #
104
+ # define 'example2' do
105
+ # define 'one' do
106
+ # compile.with :spring, :log, :commons # uses weblogic logging
107
+ # end
108
+ # define 'two' do
109
+ # compile.with :spring, :log, :commons # will take old spring
110
+ # end
111
+ # define 'three' do
112
+ # compile.with :commons_collections
113
+ # test.with artifact_ns('example2:two').spring # use spring from project two
114
+ # end
115
+ # define 'four' do
116
+ # compile.with artifact_ns.compilation
117
+ # test.with artifact_ns.testing
118
+ # end
119
+ # task(:down_them_all) do # again, just to fill this space with something ;)
120
+ # parent.projects.map(&method(:artifact_ns)).map(&:artifacts).map(&:invoke)
121
+ # end
122
+ # end
123
+ #
124
+ # = Loading from a yaml file (e. profiles.yaml)
125
+ #
126
+ # If your projects use lots of jars (after all we are using java ;) you may prefer
127
+ # to have constant artifact definitions on an external file.
128
+ # Doing so would allow an external tool (or future Buildr feature) to maintain
129
+ # an artifacts.yaml for you.
130
+ # An example usage is documented on the ArtifactNamespace.load method.
131
+ #
132
+ # = For addon/plugin writers & Customizing artifact versions
133
+ #
134
+ # Sometimes users would need to change the default artifact versions used by some
135
+ # module, for example, the XMLBeans compiler needs this, because of compatibility
136
+ # issues. Another example would be to select the groovy version to use on all our
137
+ # projects so that Buildr modules requiring groovy jars can use user prefered versions.
138
+ #
139
+ # To meet this goal, an ArtifactNamespace allows to specify ArgumentRequirement objects.
140
+ # In fact the only diference with the examples you have already seen is that requirements
141
+ # have an associated VersionRequirement, so that each time a user tries to select a version,
142
+ # buildr checks if it satisfies the requirements.
143
+ #
144
+ # Requirements are declared using the ArtifactNamespace#need method, but again,
145
+ # syntactic sugar is provided by ArtifactNamespace#method_missing.
146
+ #
147
+ # The following example is taken from the XMLBeans compiler module.
148
+ # And illustrates how addon authors should specify their requirements,
149
+ # provide default versions, and document the namespace for users to customize.
150
+ #
151
+ # module Buildr::XMLBeans
152
+ #
153
+ # # You need to document this constant, giving users some hints
154
+ # # about when are (maybe some of) these artifacts used. I mean,
155
+ # # some modules, add jars to the Buildr classpath when its file
156
+ # # is required, you would need to tell your users, so that they
157
+ # # can open the namespace and specify their defaults. Of course
158
+ # # when the requirements are defined, buildr checks if any compatible
159
+ # # version has been already defined, if so, uses it.
160
+ # #
161
+ # # Some things here have been changed to illustrate their meaning.
162
+ # REQUIRES = ArtifactNamespace.for(self).tap do |ns|
163
+ #
164
+ # # This jar requires a >2.0 version, default being 2.3.0
165
+ # ns.xmlbeans! 'org.apache.xmlbeans:xmlbeans:jar:2.3.0', '>2'
166
+ #
167
+ # # Users can customize with Buildr::XMLBeans::REQUIRES.stax_api = '1.2'
168
+ # # This is a non-flexible requirement, only satisfied by version 1.0.1
169
+ # ns.stax_api! 'stax:stax-api:jar:1.0.1'
170
+ #
171
+ # # This one is not part of XMLBeans, but is just another example
172
+ # # illustrating an `artifact requirement spec`.
173
+ #
174
+ # ns.need " some_name -> ar:ti:fact:3.2.5 -> ( >2 & <4)"
175
+ #
176
+ # # As you can see it's just an artifact spec, prefixed with
177
+ # # ' some_name -> ', this means users can use that name to
178
+ # # reference the requirement, also this string has a VersionRequirement
179
+ # # just after another ->.
180
+ # end
181
+ #
182
+ # # The REQUIRES constant is an ArtifactNamespace instance,
183
+ # # that means we can use it directly. Note that calling
184
+ # # Buildr.artifact_ns would lead to the currently executing context,
185
+ # # not the one for this module.
186
+ # def use
187
+ # # test if user specified his own version, if so, we could perform some
188
+ # # functionallity based on this.
189
+ # REQUIRES.some_name.selected? # => false
190
+ #
191
+ # REQUIRES.some_name.satisfied_by?('1.5') # => false
192
+ # puts REQUIRES.some_name.requirement # => ( >2 & <4 )
193
+ #
194
+ # REQUIRES.artifacts # get the Artifact tasks
195
+ # end
196
+ #
197
+ # end
198
+ #
199
+ # A more advanced example using ArtifactRequirement listeners is included
200
+ # in the artifact_namespace_spec.rb description for 'Extension using ArtifactNamespace'
201
+ # That's it for addon writers, now, users can select their prefered version with
202
+ # something like:
203
+ #
204
+ # require 'buildr/xmlbeans'
205
+ # Buildr::XMLBeans::REQUIRES.xmlbeans = '2.2.0'
206
+ #
207
+ # More advanced stuff, if users really need to select an xmlbeans version
208
+ # per project, they can do so letting :current (that is, the currently running
209
+ # namespace) be parent of the REQUIRES namespace:
210
+ #
211
+ # Buildr::XMLBeans::REQUIRES.parent = :current
212
+ #
213
+ # Now, provided that the compiler does not caches its artifacts, it will
214
+ # select the correct version. (See the first section for how to select per project
215
+ # artifacts).
216
+ #
217
+ #
218
+ class ArtifactNamespace
219
+ class << self
220
+ # Forget all namespaces, create a new ROOT
221
+ def clear
222
+ @instances = nil
223
+ remove_const(:ROOT) if const_defined?(:ROOT)
224
+ const_set(:ROOT, new('root'))
225
+ end
226
+
227
+ # Populate namespaces from a hash of hashes.
228
+ # The following example uses the profiles yaml to achieve this.
229
+ #
230
+ # -- profiles.yaml --
231
+ # development:
232
+ # artifacts:
233
+ # root: # root namespace
234
+ # spring: org.springframework:spring:jar:2.5
235
+ # groovy: org.codehaus.groovy:groovy:jar:1.5.4
236
+ # logging: # define a named group
237
+ # - log4j:log4j:jar:1.2.15
238
+ # - commons-logging:commons-logging:1.1.1
239
+ #
240
+ # # open Buildr::XMLBeans namespace
241
+ # Buildr::XMLBeans:
242
+ # xmlbeans: 2.2
243
+ #
244
+ # # for subproject one:oldie
245
+ # one:oldie:
246
+ # spring: org.springframework:spring:jar:1.0
247
+ #
248
+ # -- buildfile --
249
+ # ArtifactNamespace.load(Buildr.profile['artifacts'])
250
+ def load(namespaces = {})
251
+ namespaces.each_pair { |name, uses| instance(name).use(uses) }
252
+ end
253
+
254
+ # :call-seq:
255
+ # ArtifactNamespace.instance { |current_ns| ... } -> current_ns
256
+ # ArtifactNamespace.instance(name) { |ns| ... } -> ns
257
+ # ArtifactNamespace.instance(:current) { |current_ns| ... } -> current_ns
258
+ # ArtifactNamespace.instance(:root) { |root_ns| ... } -> root_ns
259
+ #
260
+ # Obtain an instance for the given name
261
+ def instance(name = nil)
262
+ case name
263
+ when :root, 'root' then return ROOT
264
+ when ArtifactNamespace then return name
265
+ when Array then name = name.join(':')
266
+ when Module, Project then name = name.name
267
+ when :current, 'current', nil then
268
+ task = Thread.current[:rake_chain]
269
+ task = task.instance_variable_get(:@value) if task
270
+ name = case task
271
+ when Project then task.name
272
+ when Rake::Task then task.scope.join(':')
273
+ when nil then Buildr.application.current_scope.join(':')
274
+ end
275
+ end
276
+ name = name.to_s
277
+ return ROOT if name.size == 0
278
+ name = name.to_s
279
+ @instances ||= Hash.new { |h, k| h[k] = new(k) }
280
+ instance = @instances[name]
281
+ yield(instance) if block_given?
282
+ instance
283
+ end
284
+
285
+ alias_method :[], :instance
286
+ alias_method :for, :instance
287
+
288
+ # :call-seq:
289
+ # ArtifactNamespace.root { |ns| ... } -> ns
290
+ #
291
+ # Obtain the root namespace, returns the ROOT constant
292
+ def root
293
+ yield ROOT if block_given?
294
+ ROOT
295
+ end
296
+ end
297
+
298
+ module DClone #:nodoc:
299
+ def dclone
300
+ clone = self.clone
301
+ clone.instance_variables.each do |i|
302
+ value = clone.instance_variable_get(i)
303
+ value = value.dclone rescue
304
+ clone.instance_variable_set(i, value)
305
+ end
306
+ clone
307
+ end
308
+ end
309
+
310
+ class Registry < Hash #:nodoc:
311
+ include DClone
312
+
313
+ attr_accessor :parent
314
+ def alias(new_name, old_name)
315
+ new_name = new_name.to_sym
316
+ old_name = old_name.to_sym
317
+ if obj = get(old_name, true)
318
+ self[new_name] = obj
319
+ @aliases ||= []
320
+ group = @aliases.find { |a| a.include?(new_name) }
321
+ group.delete(new_name) if group
322
+ group = @aliases.find { |a| a.include?(old_name) }
323
+ @aliases << (group = [old_name]) unless group
324
+ group << new_name unless group.include?(new_name)
325
+ end
326
+ obj
327
+ end
328
+
329
+ def aliases(name)
330
+ return [] unless name
331
+ name = name.to_sym
332
+ ((@aliases ||= []).find { |a| a.include?(name) } || [name]).dup
333
+ end
334
+
335
+ def []=(key, value)
336
+ return unless key
337
+ super(key.to_sym, value)
338
+ end
339
+
340
+ def get(key, include_parent = nil)
341
+ [].tap { |a| aliases(key).select { |n| a[0] = self[n] } }.first ||
342
+ (include_parent && parent && parent.get(key, include_parent))
343
+ end
344
+
345
+ def keys(include_parent = nil)
346
+ (super() | (include_parent && parent && parent.keys(include_parent) || [])).uniq
347
+ end
348
+
349
+ def values(include_parent = nil)
350
+ (super() | (include_parent && parent && parent.values(include_parent) || [])).uniq
351
+ end
352
+
353
+ def key?(key, include_parent = nil)
354
+ return false unless key
355
+ super(key.to_sym) || (include_parent && parent && parent.key?(key, include_parent))
356
+ end
357
+
358
+ def delete(key, include_parent = nil)
359
+ aliases(key).map {|n| super(n) } && include_parent && parent && parent.delete(key, include_parent)
360
+ end
361
+ end
362
+
363
+ # An artifact requirement is an object that ActsAsArtifact and has
364
+ # an associated VersionRequirement. It also knows the name (some times equal to the
365
+ # artifact id) that is used to store it in an ArtifactNamespace.
366
+ class ArtifactRequirement
367
+ attr_accessor :version
368
+ attr_reader :name, :requirement
369
+
370
+ include DClone
371
+
372
+ # Create a requirement from an `artifact requirement spec`.
373
+ # This spec has three parts, separated by ->
374
+ #
375
+ # some_name -> ar:ti:fact:3.2.5 -> ( >2 & <4)
376
+ #
377
+ # As you can see it's just an artifact spec, prefixed with
378
+ # some_name ->
379
+ # the :some_name symbol becomes this object's name and
380
+ # is used to store it on an ArtifactNamespace.
381
+ #
382
+ # ar:ti:fact:3.2.5
383
+ #
384
+ # The second part is an artifact spec by itself, and specifies
385
+ # all remaining attributes, the version of this spec becomes
386
+ # the default version of this requirement.
387
+ #
388
+ # The last part consist of a VersionRequirement.
389
+ # -> ( >2 & <4)
390
+ #
391
+ # VersionRequirement supports RubyGem's comparision operators
392
+ # in adition to parens, logical and, logical or and negation.
393
+ # See the docs for VersionRequirement for more info on operators.
394
+ def initialize(spec)
395
+ self.class.send :include, ActsAsArtifact unless ActsAsArtifact === self
396
+ if ArtifactRequirement === spec
397
+ copy_attrs(spec)
398
+ else
399
+ spec = requirement_hash(spec)
400
+ apply_spec(spec[:spec])
401
+ self.name = spec[:name]
402
+ @requirement = spec[:requirement]
403
+ @version = @requirement.default if VersionRequirement.requirement?(@version)
404
+ end
405
+ end
406
+
407
+ # Copy attributes from other to this object
408
+ def copy_attrs(other)
409
+ (ActsAsArtifact::ARTIFACT_ATTRIBUTES + [:name, :requirement]).each do |attr|
410
+ value = other.instance_variable_get("@#{attr}")
411
+ value = value.dup if value && !value.kind_of?(Numeric) && !value.kind_of?(Symbol)
412
+ instance_variable_set("@#{attr}", value)
413
+ end
414
+ end
415
+
416
+ def name=(name)
417
+ @name = name.to_s
418
+ end
419
+
420
+ # Set a the requirement, this must be an string formatted for
421
+ # VersionRequirement#create to parse.
422
+ def requirement=(version_requirement)
423
+ @requirement = VersionRequirement.create(version_requirement.to_s)
424
+ end
425
+
426
+ # Return a hash consisting of :name, :spec, :requirement
427
+ def requirement_hash(spec = self)
428
+ result = {}
429
+ if String === spec
430
+ parts = spec.split(/\s*->\s*/, 3).map(&:strip)
431
+ case parts.size
432
+ when 1
433
+ result[:spec] = Artifact.to_hash(parts.first)
434
+ when 2
435
+ if /^\w+$/ === parts.first
436
+ result[:name] = parts.first
437
+ result[:spec] = Artifact.to_hash(parts.last)
438
+ else
439
+ result[:spec] = Artifact.to_hash(parts.first)
440
+ result[:requirement] = VersionRequirement.create(parts.last)
441
+ end
442
+ when 3
443
+ result[:name] = parts.first
444
+ result[:spec] = Artifact.to_hash(parts[1])
445
+ result[:requirement] = VersionRequirement.create(parts.last)
446
+ end
447
+ else
448
+ result[:spec] = Artifact.to_hash(spec)
449
+ end
450
+ result[:name] ||= result[:spec][:id].to_s.to_sym
451
+ result[:requirement] ||= VersionRequirement.create(result[:spec][:version])
452
+ result
453
+ end
454
+
455
+ # Test if this requirement is satisfied by an artifact spec.
456
+ def satisfied_by?(spec)
457
+ return false unless requirement
458
+ spec = Artifact.to_hash(spec)
459
+ hash = to_spec_hash
460
+ hash.delete(:version)
461
+ version = spec.delete(:version)
462
+ hash == spec && requirement.satisfied_by?(version)
463
+ end
464
+
465
+ # Has user selected a version for this requirement?
466
+ def selected?
467
+ @selected
468
+ end
469
+
470
+ def selected! #:nodoc:
471
+ @selected = true
472
+ @listeners.each { |l| l.call(self) } if @listeners
473
+ self
474
+ end
475
+
476
+ def add_listener(&callback)
477
+ (@listeners ||= []) << callback
478
+ end
479
+
480
+ # Return the Artifact object for the currently selected version
481
+ def artifact
482
+ ::Buildr.artifact(self)
483
+ end
484
+
485
+ # Format this requirement as an `artifact requirement spec`
486
+ def to_requirement_spec
487
+ result = to_spec
488
+ result = "#{name} -> #{result}" if name
489
+ result = "#{result} -> #{requirement}" if requirement
490
+ result
491
+ end
492
+
493
+ def to_s #:nodoc:
494
+ id ? to_requirement_spec : version
495
+ end
496
+
497
+ # Return an artifact spec without the version part.
498
+ def unversioned_spec
499
+ str = to_spec
500
+ return nil if str =~ /^:+/
501
+ ary = str.split(':')
502
+ ary = ary[0...-1] if ary.size > 3
503
+ ary.join(':')
504
+ end
505
+
506
+ class << self
507
+ # Return an artifact spec without the version part.
508
+ def unversioned_spec(spec)
509
+ str = spec.to_s
510
+ return nil if str =~ /^:+/
511
+ ary = str.split(':')
512
+ ary = ary[0...-1] if ary.size > 3
513
+ if ary.size > 2
514
+ ary.join(':')
515
+ else
516
+ new(spec).unversioned_spec
517
+ end
518
+ end
519
+ end
520
+ end
521
+
522
+ include DClone
523
+ include Enumerable
524
+ attr_reader :name
525
+
526
+ def initialize(name = nil) #:nodoc:
527
+ @name = name.to_s if name
528
+ end
529
+ clear
530
+
531
+ def root
532
+ ROOT
533
+ end
534
+
535
+ # ROOT namespace has no parent
536
+ def parent
537
+ if root?
538
+ nil
539
+ elsif @parent.kind_of?(ArtifactNamespace)
540
+ @parent
541
+ elsif @parent
542
+ ArtifactNamespace.instance(@parent)
543
+ elsif name
544
+ parent_name = name.gsub(/::?[^:]+$/, '')
545
+ parent_name == name ? root : ArtifactNamespace.instance(parent_name)
546
+ else
547
+ root
548
+ end
549
+ end
550
+
551
+ # Set the parent for the current namespace, except if it is ROOT
552
+ def parent=(other)
553
+ raise 'Cannot set parent of root namespace' if root?
554
+ @parent = other
555
+ @registry = nil
556
+ end
557
+
558
+ # Is this the ROOT namespace?
559
+ def root?
560
+ ROOT == self
561
+ end
562
+
563
+ # Create a named sub-namespace, sub-namespaces are themselves
564
+ # ArtifactNamespace instances but cannot be referenced by
565
+ # the Buildr.artifact_ns, ArtifactNamespace.instance methods.
566
+ # Reference needs to be through this object using the given +name+
567
+ #
568
+ # artifact_ns('foo').ns(:bar).need :thing => 'some:thing:jar:1.0'
569
+ # artifact_ns('foo').bar # => the sub-namespace 'foo.bar'
570
+ # artifact_ns('foo').bar.thing # => the some thing artifact
571
+ #
572
+ # See the top level ArtifactNamespace documentation for examples
573
+ def ns(name, *uses, &block)
574
+ name = name.to_sym
575
+ sub = registry[name]
576
+ if sub
577
+ raise TypeError.new("#{name} is not a sub namespace of #{self}") unless sub.kind_of?(ArtifactNamespace)
578
+ else
579
+ sub = ArtifactNamespace.new("#{self.name}.#{name}")
580
+ sub.parent = self
581
+ registry[name] = sub
582
+ end
583
+ sub.use(*uses)
584
+ yield sub if block_given?
585
+ sub
586
+ end
587
+
588
+ # Test if a sub-namespace by the given name exists
589
+ def ns?(name)
590
+ sub = registry[name.to_sym]
591
+ ArtifactNamespace === sub
592
+ end
593
+
594
+ # :call-seq:
595
+ # artifact_ns.need 'name -> org:foo:bar:jar:~>1.2.3 -> 1.2.5'
596
+ # artifact_ns.need :name => 'org.foo:bar:jar:1.0'
597
+ #
598
+ # Create a new ArtifactRequirement on this namespace.
599
+ # ArtifactNamespace#method_missing provides syntactic sugar for this.
600
+ def need(*specs)
601
+ named = specs.flatten.inject({}) do |seen, spec|
602
+ if Hash === spec && (spec.keys & ActsAsArtifact::ARTIFACT_ATTRIBUTES).empty?
603
+ spec.each_pair do |name, spec|
604
+ if Array === spec # a group
605
+ seen[name] ||= spec.map { |s| ArtifactRequirement.new(s) }
606
+ else
607
+ artifact = ArtifactRequirement.new(spec)
608
+ artifact.name = name
609
+ seen[artifact.name] ||= artifact
610
+ end
611
+ end
612
+ else
613
+ artifact = ArtifactRequirement.new(spec)
614
+ seen[artifact.name] ||= artifact
615
+ end
616
+ seen
617
+ end
618
+ named.each_pair do |name, artifact|
619
+ if Array === artifact # a group
620
+ artifact.each do |a|
621
+ unvers = a.unversioned_spec
622
+ previous = registry[unvers]
623
+ if previous && previous.selected? && a.satisfied_by?(previous)
624
+ a.version = previous.version
625
+ end
626
+ registry[unvers] = a
627
+ end
628
+ group(name, *(artifact.map { |a| a.unversioned_spec } + [{:namespace => self}]))
629
+ else
630
+ unvers = artifact.unversioned_spec
631
+ previous = registry.get(unvers, true)
632
+ if previous && previous.selected? && artifact.satisfied_by?(previous)
633
+ artifact.version = previous.version
634
+ artifact.selected!
635
+ end
636
+ registry[unvers] = artifact
637
+ registry.alias name, unvers unless name.to_s[/^\s*$/]
638
+ end
639
+ end
640
+ self
641
+ end
642
+
643
+ # :call-seq:
644
+ # artifact_ns.use 'name -> org:foo:bar:jar:1.2.3'
645
+ # artifact_ns.use :name => 'org:foo:bar:jar:1.2.3'
646
+ # artifact_ns.use :name => '2.5.6'
647
+ #
648
+ # First and second form are equivalent, the third is used when an
649
+ # ArtifactRequirement has been previously defined with :name, so it
650
+ # just selects the version.
651
+ #
652
+ # ArtifactNamespace#method_missing provides syntactic sugar for this.
653
+ def use(*specs)
654
+ named = specs.flatten.inject({}) do |seen, spec|
655
+ if Hash === spec && (spec.keys & ActsAsArtifact::ARTIFACT_ATTRIBUTES).empty?
656
+ spec.each_pair do |name, spec|
657
+ if ArtifactNamespace === spec # create as subnamespace
658
+ raise ArgumentError.new("Circular reference") if self == spec
659
+ registry[name.to_sym] = spec
660
+ elsif Numeric === spec || (String === spec && VersionRequirement.version?(spec))
661
+ artifact = ArtifactRequirement.allocate
662
+ artifact.name = name
663
+ artifact.version = spec.to_s
664
+ seen[artifact.name] ||= artifact
665
+ elsif Symbol === spec
666
+ self.alias name, spec
667
+ elsif Array === spec # a group
668
+ seen[name] ||= spec.map { |s| ArtifactRequirement.new(s) }
669
+ else
670
+ artifact = ArtifactRequirement.new(spec)
671
+ artifact.name = name
672
+ seen[artifact.name] ||= artifact
673
+ end
674
+ end
675
+ else
676
+ if Symbol === spec
677
+ artifact = get(spec).dclone
678
+ else
679
+ artifact = ArtifactRequirement.new(spec)
680
+ end
681
+ seen[artifact.name] ||= artifact
682
+ end
683
+ seen
684
+ end
685
+ named.each_pair do |name, artifact|
686
+ is_group = Array === artifact
687
+ artifact = [artifact].flatten.map do |artifact|
688
+ unvers = artifact.unversioned_spec
689
+ previous = get(unvers, false) || get(name, false)
690
+ if previous # have previous on current namespace
691
+ if previous.requirement # we must satisfy the requirement
692
+ unless unvers # we only have the version
693
+ satisfied = previous.requirement.satisfied_by?(artifact.version)
694
+ else
695
+ satisfied = previous.satisfied_by?(artifact)
696
+ end
697
+ raise "Unsatisfied dependency #{previous} " +
698
+ "not satisfied by #{artifact}" unless satisfied
699
+ previous.version = artifact.version # OK, set new version
700
+ artifact = previous # use the same object for aliases
701
+ else # not a requirement, set the new values
702
+ unless artifact.id == previous.id && name != previous.name
703
+ previous.copy_attrs(artifact)
704
+ artifact = previous
705
+ end
706
+ end
707
+ else
708
+ if unvers.nil? && # we only have the version
709
+ (previous = get(unvers, true, false, false))
710
+ version = artifact.version
711
+ artifact.copy_attrs(previous)
712
+ artifact.version = version
713
+ end
714
+ artifact.requirement = nil
715
+ end
716
+ artifact.selected!
717
+ end
718
+ artifact = artifact.first unless is_group
719
+ if is_group
720
+ names = artifact.map do |art|
721
+ unv = art.unversioned_spec
722
+ registry[unv] = art
723
+ unv
724
+ end
725
+ group(name, *(names + [{:namespace => self}]))
726
+ elsif artifact.id
727
+ unvers = artifact.unversioned_spec
728
+ registry[name] = artifact
729
+ registry.alias unvers, name
730
+ else
731
+ registry[name] = artifact
732
+ end
733
+ end
734
+ self
735
+ end
736
+
737
+ # Like Hash#fetch
738
+ def fetch(name, default = nil, &block)
739
+ block ||= lambda { raise IndexError.new("No artifact found by name #{name.inspect} in namespace #{self}") }
740
+ real_name = name.to_s[/^\w+$/] ? name : ArtifactRequirement.unversioned_spec(name)
741
+ get(real_name.to_sym) || default || block.call(name)
742
+ end
743
+
744
+ # :call-seq:
745
+ # artifact_ns[:name] -> ArtifactRequirement
746
+ # artifact_ns[:many, :names] -> [ArtifactRequirement]
747
+ def [](*names)
748
+ ary = values_at(*names)
749
+ names.size == 1 ? ary.first : ary
750
+ end
751
+
752
+ # :call-seq:
753
+ # artifact_ns[:name] = 'some:cool:jar:1.0.2'
754
+ # artifact_ns[:name] = '1.0.2'
755
+ #
756
+ # Just like the use method
757
+ def []=(*names)
758
+ values = names.pop
759
+ values = [values] unless Array === values
760
+ names.each_with_index do |name, i|
761
+ use name => (values[i] || values.last)
762
+ end
763
+ end
764
+
765
+ # yield each ArtifactRequirement
766
+ def each(&block)
767
+ values.each(&block)
768
+ end
769
+
770
+ # return Artifact objects for each requirement
771
+ def artifacts(*names)
772
+ (names.empty? && values || values_at(*names)).map(&:artifact)
773
+ end
774
+
775
+ # Return all requirements for this namespace
776
+ def values(include_parents = false, include_groups = true)
777
+ seen, dict = {}, registry
778
+ while dict
779
+ dict.each do |k, v|
780
+ v = v.call if v.respond_to?(:call)
781
+ v = v.values if v.kind_of?(ArtifactNamespace)
782
+ if Array === v && include_groups
783
+ v.compact.each { |v| seen[v.name] = v unless seen.key?(v.name) }
784
+ else
785
+ seen[v.name] = v unless seen.key?(v.name)
786
+ end
787
+ end
788
+ dict = include_parents ? dict.parent : nil
789
+ end
790
+ seen.values
791
+ end
792
+
793
+ # Return only the named requirements
794
+ def values_at(*names)
795
+ names.map do |name|
796
+ catch :artifact do
797
+ unless name.to_s[/^\w+$/]
798
+ unvers = ArtifactRequirement.unversioned_spec(name)
799
+ unless unvers.to_s == name.to_s
800
+ req = ArtifactRequirement.new(name)
801
+ reg = self
802
+ while reg
803
+ candidate = reg.send(:get, unvers, false, false, true)
804
+ throw :artifact, candidate if req.satisfied_by?(candidate)
805
+ reg = reg.parent
806
+ end
807
+ end
808
+ end
809
+ get(name.to_sym)
810
+ end
811
+ end
812
+ end
813
+
814
+ def key?(name, include_parents = false)
815
+ name = ArtifactRequirement.unversioned_spec(name) unless name.to_s[/^\w+$/]
816
+ registry.key?(name, include_parents)
817
+ end
818
+
819
+ def delete(name, include_parents = false)
820
+ registry.delete(name, include_parents)
821
+ self
822
+ end
823
+
824
+ # :call-seq:
825
+ # group :who, :me, :you
826
+ # group :them, :me, :you, :namespace => ns
827
+ #
828
+ # Create a virtual group on this namespace. When the namespace
829
+ # is asked for the +who+ artifact, it's value is an array made from
830
+ # the remaining names. These names are searched by default from the current
831
+ # namespace.
832
+ # Second form specified the starting namespace to search from.
833
+ def group(group_name, *members)
834
+ namespace = (Hash === members.last && members.pop[:namespace]) || :current
835
+ registry[group_name] = lambda do
836
+ artifacts = self.class[namespace].values_at(*members)
837
+ artifacts = artifacts.first if members.size == 1
838
+ artifacts
839
+ end
840
+ self
841
+ end
842
+
843
+ alias_method :virtual, :group
844
+
845
+ # Create an alias for a named requirement.
846
+ def alias(new_name, old_name)
847
+ registry.alias(new_name, old_name) or
848
+ raise NameError.new("Undefined artifact name: #{old_name}")
849
+ end
850
+
851
+ def to_s #:nodoc:
852
+ name.to_s
853
+ end
854
+
855
+ # :call-seq:
856
+ # artifact_ns.cool_aid!('cool:aid:jar:2.3.4', '~>2.3') -> artifact_requirement
857
+ # artifact_ns.cool_aid = '2.3.5'
858
+ # artifact_ns.cool_aid -> artifact_requirement
859
+ # artifact_ns.cool_aid? -> true | false
860
+ #
861
+ # First form creates an ArtifactRequirement on the namespace.
862
+ # It is equivalent to providing a requirement_spec to the #need method:
863
+ # artifact_ns.need "cool_aid -> cool:aid:jar:2.3.4 -> ~>2.3"
864
+ # the second argument is optional.
865
+ #
866
+ # Second form can be used to select an artifact version
867
+ # and is equivalent to:
868
+ # artifact_ns.use :cool_aid => '1.0'
869
+ #
870
+ # Third form obtains the named ArtifactRequirement, can be
871
+ # used to test if a named requirement has been defined.
872
+ # It is equivalent to:
873
+ # artifact_ns.fetch(:cool_aid) { nil }
874
+ #
875
+ # Last form tests if the ArtifactRequirement has been defined
876
+ # and a version has been selected for use.
877
+ # It is equivalent to:
878
+ #
879
+ # artifact_ns.has_cool_aid?
880
+ # artifact_ns.values_at(:cool_aid).flatten.all? { |a| a && a.selected? }
881
+ #
882
+ def method_missing(name, *args, &block)
883
+ case name.to_s
884
+ when /!$/ then
885
+ name = $`.intern
886
+ if args.size < 1 && args.size > 2
887
+ raise ArgumentError.new("wrong number of arguments for #{name}!(spec, version_requirement?)")
888
+ end
889
+ need name => args.first
890
+ get(name).tap { |r| r.requirement = args.last if args.size == 2 }
891
+ when /=$/ then use $` => args.first
892
+ when /\?$/ then
893
+ name = $`.gsub(/^(has|have)_/, '').intern
894
+ [get(name)].flatten.all? { |a| a && a.selected? }
895
+ else
896
+ if block || args.size > 0
897
+ raise ArgumentError.new("wrong number of arguments #{args.size} for 0 or block given")
898
+ end
899
+ get(name)
900
+ end
901
+ end
902
+
903
+ # Return an anonymous module
904
+ # # first create a requirement
905
+ # artifact_ns.cool_aid! 'cool:aid:jar:>=1.0'
906
+ #
907
+ # # extend an object as a cool_aid delegator
908
+ # jars = Object.new.extend(artifact_ns.accessor(:cool_aid))
909
+ # jars.cool_aid = '2.0'
910
+ #
911
+ # artifact_ns.cool_aid.version # -> '2.0'
912
+ def accessor(*names)
913
+ ns = self
914
+ Module.new do
915
+ names.each do |name|
916
+ define_method("#{name}") { ns.send("#{name}") }
917
+ define_method("#{name}?") { ns.send("#{name}?") }
918
+ define_method("#{name}=") { |vers| ns.send("#{name}=", vers) }
919
+ end
920
+ end
921
+ end
922
+
923
+ private
924
+ def get(name, include_parents = true, include_subs = true, include_self = true) #:nodoc:
925
+ if include_subs && name.to_s[/_/] # try sub namespaces first
926
+ sub, parts = self, name.to_s.split('_')
927
+ sub_name = parts.shift.to_sym
928
+ until sub != self || parts.empty?
929
+ if registry[sub_name].kind_of?(ArtifactNamespace)
930
+ sub = registry[sub_name]
931
+ artifact = sub[parts.join('_')]
932
+ else
933
+ sub_name = [sub_name, parts.shift].join('_').to_sym
934
+ end
935
+ end
936
+ end
937
+ unless artifact
938
+ if include_self
939
+ artifact = registry.get(name, include_parents)
940
+ elsif include_parents && registry.parent
941
+ artifact = registry.parent.get(name, true)
942
+ end
943
+ end
944
+ artifact = artifact.call if artifact.respond_to?(:call)
945
+ artifact
946
+ end
947
+
948
+ def registry
949
+ @registry ||= Registry.new.tap do |m|
950
+ m.parent = parent.send(:registry) unless root?
951
+ end
952
+ end
953
+
954
+ end # ArtifactNamespace
955
+
956
+ # :call-seq:
957
+ # project.artifact_ns -> ArtifactNamespace
958
+ # Buildr.artifact_ns(name) -> ArtifactNamespace
959
+ # Buildr.artifact_ns -> ArtifactNamespace for the currently running Project
960
+ #
961
+ # Open an ArtifactNamespace.
962
+ # If a block is provided, the namespace is yielded to it.
963
+ #
964
+ # See also ArtifactNamespace.instance
965
+ def artifact_ns(name = nil, &block)
966
+ name = self if name.nil? && self.kind_of?(Project)
967
+ ArtifactNamespace.instance(name, &block)
968
+ end
969
+
970
+ end
971
+
972
+