buildr 1.2.10 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/CHANGELOG +566 -268
  2. data/DISCLAIMER +7 -1
  3. data/KEYS +151 -0
  4. data/NOTICE +23 -8
  5. data/README +122 -22
  6. data/Rakefile +49 -229
  7. data/{lib → addon}/buildr/antlr.rb +23 -10
  8. data/addon/buildr/cobertura.rb +232 -0
  9. data/{lib → addon}/buildr/hibernate.rb +20 -4
  10. data/{lib → addon}/buildr/javacc.rb +27 -12
  11. data/addon/buildr/jdepend.rb +60 -0
  12. data/{lib → addon}/buildr/jetty.rb +34 -18
  13. data/addon/buildr/nailgun.rb +892 -0
  14. data/{lib → addon}/buildr/openjpa.rb +23 -6
  15. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  16. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  17. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  18. data/{lib/buildr/jetty → addon/buildr/org/apache/buildr}/JettyWrapper.java +19 -0
  19. data/{lib → addon}/buildr/xmlbeans.rb +39 -14
  20. data/bin/buildr +21 -7
  21. data/buildr.gemspec +50 -0
  22. data/doc/css/default.css +225 -0
  23. data/doc/css/print.css +95 -0
  24. data/doc/css/syntax.css +43 -0
  25. data/doc/images/apache-incubator-logo.png +0 -0
  26. data/doc/images/buildr-hires.png +0 -0
  27. data/doc/images/buildr.png +0 -0
  28. data/doc/images/note.png +0 -0
  29. data/doc/images/tip.png +0 -0
  30. data/doc/images/zbuildr.tif +0 -0
  31. data/doc/pages/artifacts.textile +317 -0
  32. data/doc/pages/building.textile +501 -0
  33. data/doc/pages/contributing.textile +178 -0
  34. data/doc/pages/download.textile +25 -0
  35. data/doc/pages/extending.textile +229 -0
  36. data/doc/pages/getting_started.textile +337 -0
  37. data/doc/pages/index.textile +63 -0
  38. data/doc/pages/mailing_lists.textile +17 -0
  39. data/doc/pages/more_stuff.textile +367 -0
  40. data/doc/pages/packaging.textile +592 -0
  41. data/doc/pages/projects.textile +449 -0
  42. data/doc/pages/recipes.textile +127 -0
  43. data/doc/pages/settings_profiles.textile +339 -0
  44. data/doc/pages/testing.textile +475 -0
  45. data/doc/pages/troubleshooting.textile +121 -0
  46. data/doc/pages/whats_new.textile +389 -0
  47. data/doc/print.haml +52 -0
  48. data/doc/print.toc.yaml +28 -0
  49. data/doc/scripts/buildr-git.rb +411 -0
  50. data/doc/scripts/install-jruby.sh +44 -0
  51. data/doc/scripts/install-linux.sh +64 -0
  52. data/doc/scripts/install-osx.sh +52 -0
  53. data/doc/site.haml +55 -0
  54. data/doc/site.toc.yaml +44 -0
  55. data/lib/buildr.rb +28 -45
  56. data/lib/buildr/core.rb +27 -0
  57. data/lib/buildr/core/application.rb +373 -0
  58. data/lib/buildr/core/application_cli.rb +134 -0
  59. data/lib/{core → buildr/core}/build.rb +91 -77
  60. data/lib/{core → buildr/core}/checks.rb +116 -95
  61. data/lib/buildr/core/common.rb +155 -0
  62. data/lib/buildr/core/compile.rb +594 -0
  63. data/lib/buildr/core/environment.rb +120 -0
  64. data/lib/buildr/core/filter.rb +258 -0
  65. data/lib/{core → buildr/core}/generate.rb +22 -5
  66. data/lib/buildr/core/help.rb +118 -0
  67. data/lib/buildr/core/progressbar.rb +156 -0
  68. data/lib/{core → buildr/core}/project.rb +468 -213
  69. data/lib/buildr/core/test.rb +690 -0
  70. data/lib/{core → buildr/core}/transports.rb +107 -127
  71. data/lib/buildr/core/util.rb +235 -0
  72. data/lib/buildr/ide.rb +19 -0
  73. data/lib/{java → buildr/ide}/eclipse.rb +86 -60
  74. data/lib/{java → buildr/ide}/idea.ipr.template +16 -0
  75. data/lib/buildr/ide/idea.rb +194 -0
  76. data/lib/buildr/ide/idea7x.ipr.template +290 -0
  77. data/lib/buildr/ide/idea7x.rb +210 -0
  78. data/lib/buildr/java.rb +26 -0
  79. data/lib/buildr/java/ant.rb +71 -0
  80. data/lib/buildr/java/bdd_frameworks.rb +267 -0
  81. data/lib/buildr/java/commands.rb +210 -0
  82. data/lib/buildr/java/compilers.rb +432 -0
  83. data/lib/buildr/java/deprecated.rb +141 -0
  84. data/lib/buildr/java/groovyc.rb +137 -0
  85. data/lib/buildr/java/jruby.rb +99 -0
  86. data/lib/buildr/java/org/apache/buildr/BuildrNail$Main.class +0 -0
  87. data/lib/buildr/java/org/apache/buildr/BuildrNail.class +0 -0
  88. data/lib/buildr/java/org/apache/buildr/BuildrNail.java +41 -0
  89. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  90. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +116 -0
  91. data/lib/buildr/java/packaging.rb +706 -0
  92. data/lib/{java → buildr/java}/pom.rb +20 -4
  93. data/lib/buildr/java/rjb.rb +142 -0
  94. data/lib/buildr/java/test_frameworks.rb +290 -0
  95. data/lib/buildr/java/version_requirement.rb +172 -0
  96. data/lib/buildr/packaging.rb +21 -0
  97. data/lib/{java → buildr/packaging}/artifact.rb +170 -179
  98. data/lib/buildr/packaging/artifact_namespace.rb +957 -0
  99. data/lib/buildr/packaging/artifact_search.rb +140 -0
  100. data/lib/buildr/packaging/gems.rb +102 -0
  101. data/lib/buildr/packaging/package.rb +233 -0
  102. data/lib/{tasks → buildr/packaging}/tar.rb +18 -1
  103. data/lib/{tasks → buildr/packaging}/zip.rb +153 -105
  104. data/rakelib/apache.rake +126 -0
  105. data/rakelib/changelog.rake +56 -0
  106. data/rakelib/doc.rake +103 -0
  107. data/rakelib/package.rake +44 -0
  108. data/rakelib/release.rake +53 -0
  109. data/rakelib/rspec.rake +81 -0
  110. data/rakelib/rubyforge.rake +45 -0
  111. data/rakelib/scm.rake +49 -0
  112. data/rakelib/setup.rake +59 -0
  113. data/rakelib/stage.rake +45 -0
  114. data/spec/application_spec.rb +316 -0
  115. data/spec/archive_spec.rb +494 -0
  116. data/spec/artifact_namespace_spec.rb +635 -0
  117. data/spec/artifact_spec.rb +738 -0
  118. data/spec/build_spec.rb +193 -0
  119. data/spec/checks_spec.rb +537 -0
  120. data/spec/common_spec.rb +579 -0
  121. data/spec/compile_spec.rb +561 -0
  122. data/spec/groovy_compilers_spec.rb +239 -0
  123. data/spec/java_bdd_frameworks_spec.rb +238 -0
  124. data/spec/java_compilers_spec.rb +446 -0
  125. data/spec/java_packaging_spec.rb +1042 -0
  126. data/spec/java_test_frameworks_spec.rb +414 -0
  127. data/spec/packaging_helper.rb +63 -0
  128. data/spec/packaging_spec.rb +589 -0
  129. data/spec/project_spec.rb +739 -0
  130. data/spec/sandbox.rb +116 -0
  131. data/spec/scala_compilers_spec.rb +239 -0
  132. data/spec/spec.opts +6 -0
  133. data/spec/spec_helpers.rb +283 -0
  134. data/spec/test_spec.rb +871 -0
  135. data/spec/transport_spec.rb +300 -0
  136. data/spec/version_requirement_spec.rb +115 -0
  137. metadata +188 -77
  138. data/lib/buildr/cobertura.rb +0 -89
  139. data/lib/buildr/jdepend.rb +0 -40
  140. data/lib/buildr/jetty/JettyWrapper$1.class +0 -0
  141. data/lib/buildr/jetty/JettyWrapper$BuildrHandler.class +0 -0
  142. data/lib/buildr/jetty/JettyWrapper.class +0 -0
  143. data/lib/buildr/scala.rb +0 -368
  144. data/lib/core/application.rb +0 -188
  145. data/lib/core/common.rb +0 -562
  146. data/lib/core/help.rb +0 -72
  147. data/lib/core/rake_ext.rb +0 -81
  148. data/lib/java/ant.rb +0 -71
  149. data/lib/java/compile.rb +0 -589
  150. data/lib/java/idea.rb +0 -159
  151. data/lib/java/java.rb +0 -432
  152. data/lib/java/packaging.rb +0 -581
  153. data/lib/java/test.rb +0 -795
  154. data/lib/tasks/concat.rb +0 -35
@@ -0,0 +1,957 @@
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
+ to_spec[/^([a-zA-Z._-]+(:[a-zA-Z._-]+){2,3})/]
500
+ end
501
+
502
+ class << self
503
+ # Return an artifact spec without the version part.
504
+ def unversioned_spec(spec)
505
+ spec.to_s[/^([a-zA-Z._-]+(:[a-zA-Z._-]+){2,3})/] || new(spec).unversioned_spec
506
+ end
507
+ end
508
+ end
509
+
510
+ include DClone
511
+ include Enumerable
512
+ attr_reader :name
513
+
514
+ def initialize(name = nil) #:nodoc:
515
+ @name = name.to_s if name
516
+ end
517
+ clear
518
+
519
+ def root
520
+ ROOT
521
+ end
522
+
523
+ # ROOT namespace has no parent
524
+ def parent
525
+ if root?
526
+ nil
527
+ elsif @parent.kind_of?(ArtifactNamespace)
528
+ @parent
529
+ elsif @parent
530
+ ArtifactNamespace.instance(@parent)
531
+ elsif name
532
+ parent_name = name.gsub(/::?[^:]+$/, '')
533
+ parent_name == name ? root : ArtifactNamespace.instance(parent_name)
534
+ else
535
+ root
536
+ end
537
+ end
538
+
539
+ # Set the parent for the current namespace, except if it is ROOT
540
+ def parent=(other)
541
+ raise 'Cannot set parent of root namespace' if root?
542
+ @parent = other
543
+ @registry = nil
544
+ end
545
+
546
+ # Is this the ROOT namespace?
547
+ def root?
548
+ ROOT == self
549
+ end
550
+
551
+ # Create a named sub-namespace, sub-namespaces are themselves
552
+ # ArtifactNamespace instances but cannot be referenced by
553
+ # the Buildr.artifact_ns, ArtifactNamespace.instance methods.
554
+ # Reference needs to be through this object using the given +name+
555
+ #
556
+ # artifact_ns('foo').ns(:bar).need :thing => 'some:thing:jar:1.0'
557
+ # artifact_ns('foo').bar # => the sub-namespace 'foo.bar'
558
+ # artifact_ns('foo').bar.thing # => the some thing artifact
559
+ #
560
+ # See the top level ArtifactNamespace documentation for examples
561
+ def ns(name, *uses, &block)
562
+ name = name.to_sym
563
+ sub = registry[name]
564
+ if sub
565
+ raise TypeError.new("#{name} is not a sub namespace of #{self}") unless sub.kind_of?(ArtifactNamespace)
566
+ else
567
+ sub = ArtifactNamespace.new("#{self.name}.#{name}")
568
+ sub.parent = self
569
+ registry[name] = sub
570
+ end
571
+ sub.use(*uses)
572
+ yield sub if block_given?
573
+ sub
574
+ end
575
+
576
+ # Test if a sub-namespace by the given name exists
577
+ def ns?(name)
578
+ sub = registry[name.to_sym]
579
+ ArtifactNamespace === sub
580
+ end
581
+
582
+ # :call-seq:
583
+ # artifact_ns.need 'name -> org:foo:bar:jar:~>1.2.3 -> 1.2.5'
584
+ # artifact_ns.need :name => 'org.foo:bar:jar:1.0'
585
+ #
586
+ # Create a new ArtifactRequirement on this namespace.
587
+ # ArtifactNamespace#method_missing provides syntactic sugar for this.
588
+ def need(*specs)
589
+ named = specs.flatten.inject({}) do |seen, spec|
590
+ if Hash === spec && (spec.keys & ActsAsArtifact::ARTIFACT_ATTRIBUTES).empty?
591
+ spec.each_pair do |name, spec|
592
+ if Array === spec # a group
593
+ seen[name] ||= spec.map { |s| ArtifactRequirement.new(s) }
594
+ else
595
+ artifact = ArtifactRequirement.new(spec)
596
+ artifact.name = name
597
+ seen[artifact.name] ||= artifact
598
+ end
599
+ end
600
+ else
601
+ artifact = ArtifactRequirement.new(spec)
602
+ seen[artifact.name] ||= artifact
603
+ end
604
+ seen
605
+ end
606
+ named.each_pair do |name, artifact|
607
+ if Array === artifact # a group
608
+ artifact.each do |a|
609
+ unvers = a.unversioned_spec
610
+ previous = registry[unvers]
611
+ if previous && previous.selected? && a.satisfied_by?(previous)
612
+ a.version = previous.version
613
+ end
614
+ registry[unvers] = a
615
+ end
616
+ group(name, *(artifact.map { |a| a.unversioned_spec } + [{:namespace => self}]))
617
+ else
618
+ unvers = artifact.unversioned_spec
619
+ previous = registry.get(unvers, true)
620
+ if previous && previous.selected? && artifact.satisfied_by?(previous)
621
+ artifact.version = previous.version
622
+ artifact.selected!
623
+ end
624
+ registry[unvers] = artifact
625
+ registry.alias name, unvers unless name.to_s[/^\s*$/]
626
+ end
627
+ end
628
+ self
629
+ end
630
+
631
+ # :call-seq:
632
+ # artifact_ns.use 'name -> org:foo:bar:jar:1.2.3'
633
+ # artifact_ns.use :name => 'org:foo:bar:jar:1.2.3'
634
+ # artifact_ns.use :name => '2.5.6'
635
+ #
636
+ # First and second form are equivalent, the third is used when an
637
+ # ArtifactRequirement has been previously defined with :name, so it
638
+ # just selects the version.
639
+ #
640
+ # ArtifactNamespace#method_missing provides syntactic sugar for this.
641
+ def use(*specs)
642
+ named = specs.flatten.inject({}) do |seen, spec|
643
+ if Hash === spec && (spec.keys & ActsAsArtifact::ARTIFACT_ATTRIBUTES).empty?
644
+ spec.each_pair do |name, spec|
645
+ if ArtifactNamespace === spec # create as subnamespace
646
+ raise ArgumentError.new("Circular reference") if self == spec
647
+ registry[name.to_sym] = spec
648
+ elsif Numeric === spec || (String === spec && VersionRequirement.version?(spec))
649
+ artifact = ArtifactRequirement.allocate
650
+ artifact.name = name
651
+ artifact.version = spec.to_s
652
+ seen[artifact.name] ||= artifact
653
+ elsif Symbol === spec
654
+ self.alias name, spec
655
+ elsif Array === spec # a group
656
+ seen[name] ||= spec.map { |s| ArtifactRequirement.new(s) }
657
+ else
658
+ artifact = ArtifactRequirement.new(spec)
659
+ artifact.name = name
660
+ seen[artifact.name] ||= artifact
661
+ end
662
+ end
663
+ else
664
+ if Symbol === spec
665
+ artifact = get(spec).dclone
666
+ else
667
+ artifact = ArtifactRequirement.new(spec)
668
+ end
669
+ seen[artifact.name] ||= artifact
670
+ end
671
+ seen
672
+ end
673
+ named.each_pair do |name, artifact|
674
+ is_group = Array === artifact
675
+ artifact = [artifact].flatten.map do |artifact|
676
+ unvers = artifact.unversioned_spec
677
+ previous = get(unvers, false) || get(name, false)
678
+ if previous # have previous on current namespace
679
+ if previous.requirement # we must satisfy the requirement
680
+ unless unvers # we only have the version
681
+ satisfied = previous.requirement.satisfied_by?(artifact.version)
682
+ else
683
+ satisfied = previous.satisfied_by?(artifact)
684
+ end
685
+ raise "Unsatisfied dependency #{previous} " +
686
+ "not satisfied by #{artifact}" unless satisfied
687
+ previous.version = artifact.version # OK, set new version
688
+ else # not a requirement, set the new values
689
+ previous.copy_attrs(artifact)
690
+ end
691
+ artifact = previous # use the same object for aliases
692
+ else
693
+ if unvers.nil? && # we only have the version
694
+ (previous = get(unvers, true, false, false))
695
+ version = artifact.version
696
+ artifact.copy_attrs(previous)
697
+ artifact.version = version
698
+ end
699
+ artifact.requirement = nil
700
+ end
701
+ artifact.selected!
702
+ end
703
+ artifact = artifact.first unless is_group
704
+ if is_group
705
+ names = artifact.map do |art|
706
+ unv = art.unversioned_spec
707
+ registry[unv] = art
708
+ unv
709
+ end
710
+ group(name, *(names + [{:namespace => self}]))
711
+ elsif artifact.id
712
+ unvers = artifact.unversioned_spec
713
+ registry[unvers] = artifact
714
+ registry.alias name, unvers unless name.to_s[/^\s*$/]
715
+ else
716
+ registry[name] = artifact
717
+ end
718
+ end
719
+ self
720
+ end
721
+
722
+ # Like Hash#fetch
723
+ def fetch(name, default = nil, &block)
724
+ block ||= lambda { raise IndexError.new("No artifact found by name #{name.inspect} in namespace #{self}") }
725
+ real_name = name.to_s[/^\w+$/] ? name : ArtifactRequirement.unversioned_spec(name)
726
+ get(real_name.to_sym) || default || block.call(name)
727
+ end
728
+
729
+ # :call-seq:
730
+ # artifact_ns[:name] -> ArtifactRequirement
731
+ # artifact_ns[:many, :names] -> [ArtifactRequirement]
732
+ def [](*names)
733
+ ary = values_at(*names)
734
+ names.size == 1 ? ary.first : ary
735
+ end
736
+
737
+ # :call-seq:
738
+ # artifact_ns[:name] = 'some:cool:jar:1.0.2'
739
+ # artifact_ns[:name] = '1.0.2'
740
+ #
741
+ # Just like the use method
742
+ def []=(*names)
743
+ values = names.pop
744
+ values = [values] unless Array === values
745
+ names.each_with_index do |name, i|
746
+ use name => (values[i] || values.last)
747
+ end
748
+ end
749
+
750
+ # yield each ArtifactRequirement
751
+ def each(&block)
752
+ values.each(&block)
753
+ end
754
+
755
+ # return Artifact objects for each requirement
756
+ def artifacts(*names)
757
+ (names.empty? && values || values_at(*names)).map(&:artifact)
758
+ end
759
+
760
+ # Return all requirements for this namespace
761
+ def values(include_parents = false, include_groups = true)
762
+ seen, dict = {}, registry
763
+ while dict
764
+ dict.each do |k, v|
765
+ v = v.call if v.respond_to?(:call)
766
+ v = v.values if v.kind_of?(ArtifactNamespace)
767
+ if Array === v && include_groups
768
+ v.compact.each { |v| seen[v.name] = v unless seen.key?(v.name) }
769
+ else
770
+ seen[v.name] = v unless seen.key?(v.name)
771
+ end
772
+ end
773
+ dict = include_parents ? dict.parent : nil
774
+ end
775
+ seen.values
776
+ end
777
+
778
+ # Return only the named requirements
779
+ def values_at(*names)
780
+ names.map do |name|
781
+ catch :artifact do
782
+ unless name.to_s[/^\w+$/]
783
+ unvers = ArtifactRequirement.unversioned_spec(name)
784
+ unless unvers.to_s == name.to_s
785
+ req = ArtifactRequirement.new(name)
786
+ reg = self
787
+ while reg
788
+ candidate = reg.send(:get, unvers, false, false, true)
789
+ throw :artifact, candidate if req.satisfied_by?(candidate)
790
+ reg = reg.parent
791
+ end
792
+ end
793
+ end
794
+ get(name.to_sym)
795
+ end
796
+ end
797
+ end
798
+
799
+ def key?(name, include_parents = false)
800
+ name = ArtifactRequirement.unversioned_spec(name) unless name.to_s[/^\w+$/]
801
+ registry.key?(name, include_parents)
802
+ end
803
+
804
+ def delete(name, include_parents = false)
805
+ registry.delete(name, include_parents)
806
+ self
807
+ end
808
+
809
+ # :call-seq:
810
+ # group :who, :me, :you
811
+ # group :them, :me, :you, :namespace => ns
812
+ #
813
+ # Create a virtual group on this namespace. When the namespace
814
+ # is asked for the +who+ artifact, it's value is an array made from
815
+ # the remaining names. These names are searched by default from the current
816
+ # namespace.
817
+ # Second form specified the starting namespace to search from.
818
+ def group(group_name, *members)
819
+ namespace = (Hash === members.last && members.pop[:namespace]) || :current
820
+ registry[group_name] = lambda do
821
+ artifacts = self.class[namespace].values_at(*members)
822
+ artifacts = artifacts.first if members.size == 1
823
+ artifacts
824
+ end
825
+ self
826
+ end
827
+
828
+ alias_method :virtual, :group
829
+
830
+ # Create an alias for a named requirement.
831
+ def alias(new_name, old_name)
832
+ registry.alias(new_name, old_name) or
833
+ raise NameError.new("Undefined artifact name: #{old_name}")
834
+ end
835
+
836
+ def to_s #:nodoc:
837
+ name.to_s
838
+ end
839
+
840
+ # :call-seq:
841
+ # artifact_ns.cool_aid!('cool:aid:jar:2.3.4', '~>2.3') -> artifact_requirement
842
+ # artifact_ns.cool_aid = '2.3.5'
843
+ # artifact_ns.cool_aid -> artifact_requirement
844
+ # artifact_ns.cool_aid? -> true | false
845
+ #
846
+ # First form creates an ArtifactRequirement on the namespace.
847
+ # It is equivalent to providing a requirement_spec to the #need method:
848
+ # artifact_ns.need "cool_aid -> cool:aid:jar:2.3.4 -> ~>2.3"
849
+ # the second argument is optional.
850
+ #
851
+ # Second form can be used to select an artifact version
852
+ # and is equivalent to:
853
+ # artifact_ns.use :cool_aid => '1.0'
854
+ #
855
+ # Third form obtains the named ArtifactRequirement, can be
856
+ # used to test if a named requirement has been defined.
857
+ # It is equivalent to:
858
+ # artifact_ns.fetch(:cool_aid) { nil }
859
+ #
860
+ # Last form tests if the ArtifactRequirement has been defined
861
+ # and a version has been selected for use.
862
+ # It is equivalent to:
863
+ #
864
+ # artifact_ns.has_cool_aid?
865
+ # artifact_ns.values_at(:cool_aid).flatten.all? { |a| a && a.selected? }
866
+ #
867
+ def method_missing(name, *args, &block)
868
+ case name.to_s
869
+ when /!$/ then
870
+ name = $`.intern
871
+ if args.size < 1 && args.size > 2
872
+ raise ArgumentError.new("wrong number of arguments for #{name}!(spec, version_requirement?)")
873
+ end
874
+ need name => args.first
875
+ get(name).tap { |r| r.requirement = args.last if args.size == 2 }
876
+ when /=$/ then use $` => args.first
877
+ when /\?$/ then
878
+ name = $`.gsub(/^(has|have)_/, '').intern
879
+ [get(name)].flatten.all? { |a| a && a.selected? }
880
+ else
881
+ if block || args.size > 0
882
+ raise ArgumentError.new("wrong number of arguments #{args.size} for 0 or block given")
883
+ end
884
+ get(name)
885
+ end
886
+ end
887
+
888
+ # Return an anonymous module
889
+ # # first create a requirement
890
+ # artifact_ns.cool_aid! 'cool:aid:jar:>=1.0'
891
+ #
892
+ # # extend an object as a cool_aid delegator
893
+ # jars = Object.new.extend(artifact_ns.accessor(:cool_aid))
894
+ # jars.cool_aid = '2.0'
895
+ #
896
+ # artifact_ns.cool_aid.version # -> '2.0'
897
+ def accessor(*names)
898
+ ns = self
899
+ Module.new do
900
+ names.each do |name|
901
+ define_method("#{name}") { ns.send("#{name}") }
902
+ define_method("#{name}?") { ns.send("#{name}?") }
903
+ define_method("#{name}=") { |vers| ns.send("#{name}=", vers) }
904
+ end
905
+ end
906
+ end
907
+
908
+ private
909
+ def get(name, include_parents = true, include_subs = true, include_self = true) #:nodoc:
910
+ if include_subs && name.to_s[/_/] # try sub namespaces first
911
+ sub, parts = self, name.to_s.split('_')
912
+ sub_name = parts.shift.to_sym
913
+ until sub != self || parts.empty?
914
+ if registry[sub_name].kind_of?(ArtifactNamespace)
915
+ sub = registry[sub_name]
916
+ artifact = sub[parts.join('_')]
917
+ else
918
+ sub_name = [sub_name, parts.shift].join('_').to_sym
919
+ end
920
+ end
921
+ end
922
+ unless artifact
923
+ if include_self
924
+ artifact = registry.get(name, include_parents)
925
+ elsif include_parents && registry.parent
926
+ artifact = registry.parent.get(name, true)
927
+ end
928
+ end
929
+ artifact = artifact.call if artifact.respond_to?(:call)
930
+ artifact
931
+ end
932
+
933
+ def registry
934
+ @registry ||= Registry.new.tap do |m|
935
+ m.parent = parent.send(:registry) unless root?
936
+ end
937
+ end
938
+
939
+ end # ArtifactNamespace
940
+
941
+ # :call-seq:
942
+ # project.artifact_ns -> ArtifactNamespace
943
+ # Buildr.artifact_ns(name) -> ArtifactNamespace
944
+ # Buildr.artifact_ns -> ArtifactNamespace for the currently running Project
945
+ #
946
+ # Open an ArtifactNamespace.
947
+ # If a block is provided, the namespace is yielded to it.
948
+ #
949
+ # See also ArtifactNamespace.instance
950
+ def artifact_ns(name = nil, &block)
951
+ name = self if name.nil? && self.kind_of?(Project)
952
+ ArtifactNamespace.instance(name, &block)
953
+ end
954
+
955
+ end
956
+
957
+