buildr 1.3.0-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 (138) hide show
  1. data/CHANGELOG +780 -0
  2. data/DISCLAIMER +7 -0
  3. data/KEYS +151 -0
  4. data/LICENSE +176 -0
  5. data/NOTICE +31 -0
  6. data/README +173 -0
  7. data/Rakefile +63 -0
  8. data/addon/buildr/antlr.rb +65 -0
  9. data/addon/buildr/cobertura.rb +232 -0
  10. data/addon/buildr/hibernate.rb +142 -0
  11. data/addon/buildr/javacc.rb +85 -0
  12. data/addon/buildr/jdepend.rb +60 -0
  13. data/addon/buildr/jetty.rb +248 -0
  14. data/addon/buildr/nailgun.rb +892 -0
  15. data/addon/buildr/openjpa.rb +90 -0
  16. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  17. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  18. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  19. data/addon/buildr/org/apache/buildr/JettyWrapper.java +144 -0
  20. data/addon/buildr/xmlbeans.rb +93 -0
  21. data/bin/buildr +21 -0
  22. data/buildr.gemspec +50 -0
  23. data/doc/css/default.css +225 -0
  24. data/doc/css/print.css +95 -0
  25. data/doc/css/syntax.css +43 -0
  26. data/doc/images/apache-incubator-logo.png +0 -0
  27. data/doc/images/buildr-hires.png +0 -0
  28. data/doc/images/buildr.png +0 -0
  29. data/doc/images/note.png +0 -0
  30. data/doc/images/tip.png +0 -0
  31. data/doc/images/zbuildr.tif +0 -0
  32. data/doc/pages/artifacts.textile +317 -0
  33. data/doc/pages/building.textile +501 -0
  34. data/doc/pages/contributing.textile +178 -0
  35. data/doc/pages/download.textile +25 -0
  36. data/doc/pages/extending.textile +229 -0
  37. data/doc/pages/getting_started.textile +337 -0
  38. data/doc/pages/index.textile +63 -0
  39. data/doc/pages/mailing_lists.textile +17 -0
  40. data/doc/pages/more_stuff.textile +367 -0
  41. data/doc/pages/packaging.textile +592 -0
  42. data/doc/pages/projects.textile +449 -0
  43. data/doc/pages/recipes.textile +127 -0
  44. data/doc/pages/settings_profiles.textile +339 -0
  45. data/doc/pages/testing.textile +475 -0
  46. data/doc/pages/troubleshooting.textile +121 -0
  47. data/doc/pages/whats_new.textile +389 -0
  48. data/doc/print.haml +52 -0
  49. data/doc/print.toc.yaml +28 -0
  50. data/doc/scripts/buildr-git.rb +411 -0
  51. data/doc/scripts/install-jruby.sh +44 -0
  52. data/doc/scripts/install-linux.sh +64 -0
  53. data/doc/scripts/install-osx.sh +52 -0
  54. data/doc/site.haml +55 -0
  55. data/doc/site.toc.yaml +44 -0
  56. data/lib/buildr.rb +47 -0
  57. data/lib/buildr/core.rb +27 -0
  58. data/lib/buildr/core/application.rb +373 -0
  59. data/lib/buildr/core/application_cli.rb +134 -0
  60. data/lib/buildr/core/build.rb +262 -0
  61. data/lib/buildr/core/checks.rb +382 -0
  62. data/lib/buildr/core/common.rb +155 -0
  63. data/lib/buildr/core/compile.rb +594 -0
  64. data/lib/buildr/core/environment.rb +120 -0
  65. data/lib/buildr/core/filter.rb +258 -0
  66. data/lib/buildr/core/generate.rb +195 -0
  67. data/lib/buildr/core/help.rb +118 -0
  68. data/lib/buildr/core/progressbar.rb +156 -0
  69. data/lib/buildr/core/project.rb +890 -0
  70. data/lib/buildr/core/test.rb +690 -0
  71. data/lib/buildr/core/transports.rb +486 -0
  72. data/lib/buildr/core/util.rb +235 -0
  73. data/lib/buildr/ide.rb +19 -0
  74. data/lib/buildr/ide/eclipse.rb +181 -0
  75. data/lib/buildr/ide/idea.ipr.template +300 -0
  76. data/lib/buildr/ide/idea.rb +194 -0
  77. data/lib/buildr/ide/idea7x.ipr.template +290 -0
  78. data/lib/buildr/ide/idea7x.rb +210 -0
  79. data/lib/buildr/java.rb +26 -0
  80. data/lib/buildr/java/ant.rb +71 -0
  81. data/lib/buildr/java/bdd_frameworks.rb +267 -0
  82. data/lib/buildr/java/commands.rb +210 -0
  83. data/lib/buildr/java/compilers.rb +432 -0
  84. data/lib/buildr/java/deprecated.rb +141 -0
  85. data/lib/buildr/java/groovyc.rb +137 -0
  86. data/lib/buildr/java/jruby.rb +99 -0
  87. data/lib/buildr/java/org/apache/buildr/BuildrNail$Main.class +0 -0
  88. data/lib/buildr/java/org/apache/buildr/BuildrNail.class +0 -0
  89. data/lib/buildr/java/org/apache/buildr/BuildrNail.java +41 -0
  90. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  91. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +116 -0
  92. data/lib/buildr/java/packaging.rb +706 -0
  93. data/lib/buildr/java/pom.rb +178 -0
  94. data/lib/buildr/java/rjb.rb +142 -0
  95. data/lib/buildr/java/test_frameworks.rb +290 -0
  96. data/lib/buildr/java/version_requirement.rb +172 -0
  97. data/lib/buildr/packaging.rb +21 -0
  98. data/lib/buildr/packaging/artifact.rb +729 -0
  99. data/lib/buildr/packaging/artifact_namespace.rb +957 -0
  100. data/lib/buildr/packaging/artifact_search.rb +140 -0
  101. data/lib/buildr/packaging/gems.rb +102 -0
  102. data/lib/buildr/packaging/package.rb +233 -0
  103. data/lib/buildr/packaging/tar.rb +104 -0
  104. data/lib/buildr/packaging/zip.rb +719 -0
  105. data/rakelib/apache.rake +126 -0
  106. data/rakelib/changelog.rake +56 -0
  107. data/rakelib/doc.rake +103 -0
  108. data/rakelib/package.rake +44 -0
  109. data/rakelib/release.rake +53 -0
  110. data/rakelib/rspec.rake +81 -0
  111. data/rakelib/rubyforge.rake +45 -0
  112. data/rakelib/scm.rake +49 -0
  113. data/rakelib/setup.rake +59 -0
  114. data/rakelib/stage.rake +45 -0
  115. data/spec/application_spec.rb +316 -0
  116. data/spec/archive_spec.rb +494 -0
  117. data/spec/artifact_namespace_spec.rb +635 -0
  118. data/spec/artifact_spec.rb +738 -0
  119. data/spec/build_spec.rb +193 -0
  120. data/spec/checks_spec.rb +537 -0
  121. data/spec/common_spec.rb +579 -0
  122. data/spec/compile_spec.rb +561 -0
  123. data/spec/groovy_compilers_spec.rb +239 -0
  124. data/spec/java_bdd_frameworks_spec.rb +238 -0
  125. data/spec/java_compilers_spec.rb +446 -0
  126. data/spec/java_packaging_spec.rb +1042 -0
  127. data/spec/java_test_frameworks_spec.rb +414 -0
  128. data/spec/packaging_helper.rb +63 -0
  129. data/spec/packaging_spec.rb +589 -0
  130. data/spec/project_spec.rb +739 -0
  131. data/spec/sandbox.rb +116 -0
  132. data/spec/scala_compilers_spec.rb +239 -0
  133. data/spec/spec.opts +6 -0
  134. data/spec/spec_helpers.rb +283 -0
  135. data/spec/test_spec.rb +871 -0
  136. data/spec/transport_spec.rb +300 -0
  137. data/spec/version_requirement_spec.rb +115 -0
  138. metadata +324 -0
@@ -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
+