Class: Buildr::ArtifactNamespace

Inherits:
Object
  • Object
show all
Includes:
DClone, Enumerable
Defined in:
lib/buildr/packaging/artifact_namespace.rb

Overview

An ArtifactNamespace is a hierarchical dictionary used to manage ArtifactRequirements. It can be used to have different artifact versions per project or to allow users to select a version for addons or modules.

Namespaces are opened using the Buildr.artifact_ns method, most important methods are:

need

Used to create a requirement on the namespace.

use

Set the artifact version to use for a requirement.

values_at

Reference requirements by name.

each

Return each ArtifactRequirement in the namespace.

The method_missing method for instances provides some syntactic sugar to these. See the following examples, and the methods for ArtifactRequirement.

Avoiding constant polution on buildfile

Each project has its own ArtifactNamespace inheriting the one from the parent project up to the root namespace.

Consider the following snippet, as project grows, each subproject may need diferent artifact combinations and/or versions. Asigning artifact specifications to constants can make it painful to maintain their references even if using structs/hashes.

-- buildfile --
SPRING = 'org.springframework:spring:jar:2.5'
SPRING_OLD = 'org.springframework:spring:jar:1.0'
LOGGING = ['comons-logging:commons-logging:jar:1.1.1',
           'log4j:log4j:jar:1.2.15']
WL_LOGGING = artifact('bea:wlcommons-logging:jar:8.1').from('path/to/wlcommons-logging.jar')
LOGGING_WEBLOGIC = ['comons-logging:commons-logging:jar:1.1.1',
                    WL_LOGGING]
COMMONS = struct :collections => 'commons-collection:commons-collection:jar:3.1',
                 :net => 'commons-net:commons-net:jar:1.4.0'

define 'example1' do
  define 'one' do
    compile.with SPRING, LOGGING_WEBLOGIC, COMMONS
  end
  define 'two' do
    compile.with SPRING_OLD, LOGGING, COMMONS
  end
  define 'three' do
    compile.with "commons-collections:commons-collections:jar:2.2"
  end
end

With ArtifactNamespace you can do some more advanced stuff, the following annotated snipped could still be reduced if default artifact definitions were loaded from yaml file (see section bellow and ArtifactNamespace.load).

-- buildfile --
artifact_ns do |ns| # the current namespace (root if called outside a project)
  # default artifacts
  ns.spring = 'org.springframework:spring:jar:2.5'
  # default logger is log4j
  ns.logger = 'log4j:log4j:jar:1.2.15'

  # create a sub namespace by calling the #ns method,
  # artifacts defined on the sub-namespace can be referenced by
  # name :commons_net or by calling commons.net
  ns.ns :commons, :net => 'commons-net:commons-net:jar:1.4.0',
                  :logging => 'comons-logging:commons-logging:jar:1.1.1'

  # When a child namespace asks for the :log artifact,
  # these artifacts will be searched starting from the :current namespace.
  ns.virtual :log, :logger, :commons_logging
end

artifact_ns('example2:one') do |ns| # namespace for the one subproject
  ns.logger = artifact('bea:wlcommons-logging:jar:8.1').from('path/to/wlcommons-logging.jar')
end
artifact_ns('example2:two') do |ns|
  ns.spring = '1.0' # for project two use an older spring version (just for an example)
end
artifact_ns('example2:three').commons_collections = 2.2'
artifact_ns('example2:four') do |ns|
  ns.beanutils = 'commons-beanutils:commons-beanutils:jar:1.5'        # just for this project
  ns.ns(:compilation).use :commons_logging, :beanutils, :spring       # compile time dependencies
  ns.ns(:testing).use :log, :beanutils, 'cglib:cglib-nodep:jar:2.1.3' # run time dependencies
end

define 'example2' do
  define 'one' do
    compile.with :spring, :log, :commons # uses weblogic logging
  end
  define 'two' do
    compile.with :spring, :log, :commons # will take old spring
  end
  define 'three' do
    compile.with :commons_collections
    test.with artifact_ns('example2:two').spring # use spring from project two
  end
  define 'four' do
    compile.with artifact_ns.compilation
    test.with artifact_ns.testing
  end
  task(:down_them_all) do # again, just to fill this space with something ;)
    parent.projects.map(&method(:artifact_ns)).map(&:artifacts).map(&:invoke)
  end
end

Loading from a yaml file (e. profiles.yaml)

If your projects use lots of jars (after all we are using java ;) you may prefer to have constant artifact definitions on an external file. Doing so would allow an external tool (or future Buildr feature) to maintain an artifacts.yaml for you. An example usage is documented on the ArtifactNamespace.load method.

For addon/plugin writers & Customizing artifact versions

Sometimes users would need to change the default artifact versions used by some module, for example, the XMLBeans compiler needs this, because of compatibility issues. Another example would be to select the groovy version to use on all our projects so that Buildr modules requiring groovy jars can use user prefered versions.

To meet this goal, an ArtifactNamespace allows to specify ArgumentRequirement objects. In fact the only diference with the examples you have already seen is that requirements have an associated VersionRequirement, so that each time a user tries to select a version, buildr checks if it satisfies the requirements.

Requirements are declared using the ArtifactNamespace#need method, but again, syntactic sugar is provided by ArtifactNamespace#method_missing.

The following example is taken from the XMLBeans compiler module. And illustrates how addon authors should specify their requirements, provide default versions, and document the namespace for users to customize.

module Buildr::XMLBeans

   # You need to document this constant, giving users some hints
   # about when are (maybe some of) these artifacts used. I mean,
   # some modules, add jars to the Buildr classpath when its file
   # is required, you would need to tell your users, so that they
   # can open the namespace and specify their defaults. Of course
   # when the requirements are defined, buildr checks if any compatible
   # version has been already defined, if so, uses it.
   #
   # Some things here have been changed to illustrate their meaning.
   REQUIRES = ArtifactNamespace.for(self).tap do |ns|

     # This jar requires a >2.0 version, default being 2.3.0
     ns.xmlbeans! 'org.apache.xmlbeans:xmlbeans:jar:2.3.0', '>2'

     # Users can customize with Buildr::XMLBeans::REQUIRES.stax_api = '1.2'
     # This is a non-flexible requirement, only satisfied by version 1.0.1
     ns.stax_api! 'stax:stax-api:jar:1.0.1'

     # This one is not part of XMLBeans, but is just another example
     # illustrating an `artifact requirement spec`.

     ns.need " some_name ->  ar:ti:fact:3.2.5 ->  ( >2 & <4)"

     # As you can see it's just an artifact spec, prefixed with
     # ' some_name -> ', this means users can use that name to
     # reference the requirement, also this string has a VersionRequirement
     # just after another ->.
   end

   # The REQUIRES constant is an ArtifactNamespace instance,
   # that means we can use it directly. Note that calling
   # Buildr.artifact_ns would lead to the currently executing context,
   # not the one for this module.
   def use
     # test if user specified his own version, if so, we could perform some
     # functionallity based on this.
     REQUIRES.some_name.selected? # => false

     REQUIRES.some_name.satisfied_by?('1.5') # => false
     puts REQUIRES.some_name.requirement     # => ( >2 & <4 )

     REQUIRES.artifacts # get the Artifact tasks
   end

end

A more advanced example using ArtifactRequirement listeners is included in the artifact_namespace_spec.rb description for ‘Extension using ArtifactNamespace’ That’s it for addon writers, now, users can select their prefered version with something like:

require 'buildr/xmlbeans'
Buildr::XMLBeans::REQUIRES.xmlbeans = '2.2.0'

More advanced stuff, if users really need to select an xmlbeans version per project, they can do so letting :current (that is, the currently running namespace) be parent of the REQUIRES namespace:

Buildr::XMLBeans::REQUIRES.parent = :current

Now, provided that the compiler does not caches its artifacts, it will select the correct version. (See the first section for how to select per project artifacts).

Defined Under Namespace

Modules: DClone Classes: ArtifactRequirement, Registry

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DClone

#dclone

Constructor Details

#initialize(name = nil) ⇒ ArtifactNamespace

:nodoc:



526
527
528
# File 'lib/buildr/packaging/artifact_namespace.rb', line 526

def initialize(name = nil) #:nodoc:
  @name = name.to_s if name
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

:call-seq:

artifact_ns.cool_aid!('cool:aid:jar:2.3.4', '~>2.3') -> artifact_requirement
artifact_ns.cool_aid = '2.3.5'
artifact_ns.cool_aid  -> artifact_requirement
artifact_ns.cool_aid? -> true | false

First form creates an ArtifactRequirement on the namespace. It is equivalent to providing a requirement_spec to the #need method:

artifact_ns.need "cool_aid -> cool:aid:jar:2.3.4 -> ~>2.3"

the second argument is optional.

Second form can be used to select an artifact version and is equivalent to:

artifact_ns.use :cool_aid => '1.0'

Third form obtains the named ArtifactRequirement, can be used to test if a named requirement has been defined. It is equivalent to:

artifact_ns.fetch(:cool_aid) { nil }

Last form tests if the ArtifactRequirement has been defined and a version has been selected for use. It is equivalent to:

artifact_ns.has_cool_aid?
artifact_ns.values_at(:cool_aid).flatten.all? { |a| a && a.selected? }


890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
# File 'lib/buildr/packaging/artifact_namespace.rb', line 890

def method_missing(name, *args, &block)
  case name.to_s
  when /!$/ then
    name = $`.intern
    if args.size < 1 || args.size > 2
      raise ArgumentError.new("wrong number of arguments for #{name}!(spec, version_requirement?)")
    end
    need name => args.first
    get(name).tap { |r| r.requirement = args.last if args.size == 2 }
  when /=$/ then use $` => args.first
  when /\?$/ then
    name = $`.gsub(/^(has|have)_/, '').intern
    [get(name)].flatten.all? { |a| a && a.selected? }
  else
    if block || args.size > 0
      raise ArgumentError.new("wrong number of arguments #{args.size} for 0 or block given")
    end
    get(name)
  end
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



524
525
526
# File 'lib/buildr/packaging/artifact_namespace.rb', line 524

def name
  @name
end

Class Method Details

.clearObject

Forget all namespaces, create a new ROOT



221
222
223
224
225
# File 'lib/buildr/packaging/artifact_namespace.rb', line 221

def clear
  @instances = nil
  remove_const(:ROOT) rescue nil
  const_set(:ROOT, new('root'))
end

.instance(name = nil) {|instance| ... } ⇒ Object Also known as: [], for

:call-seq:

ArtifactNamespace.instance { |current_ns| ... } -> current_ns
ArtifactNamespace.instance(name) { |ns| ... } -> ns
ArtifactNamespace.instance(:current) { |current_ns| ... } -> current_ns
ArtifactNamespace.instance(:root) { |root_ns| ... } -> root_ns

Obtain an instance for the given name

Yields:



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/buildr/packaging/artifact_namespace.rb', line 261

def instance(name = nil)
  case name
  when :root, 'root' then return ROOT
  when ArtifactNamespace then return name
  when Array then name = name.join(':')
  when Module, Project then name = name.name
  when :current, 'current', nil then
    task = Thread.current[:rake_chain]
    task = task.instance_variable_get(:@value) if task
    name = case task
           when Project then task.name
           when Rake::Task then task.scope.join(':')
           when nil then Buildr.application.current_scope.join(':')
           end
  end
  name = name.to_s
  return ROOT if name.size == 0
  name = name.to_s
  @instances ||= Hash.new { |h, k| h[k] = new(k) }
  instance = @instances[name]
  yield(instance) if block_given?
  instance
end

.load(namespaces = {}) ⇒ Object

Populate namespaces from a hash of hashes. The following example uses the profiles yaml to achieve this.

-- profiles.yaml --
development:
  artifacts:
    root:        # root namespace
      spring:     org.springframework:spring:jar:2.5
      groovy:     org.codehaus.groovy:groovy:jar:1.5.4
      logging:    # define a named group
        - log4j:log4j:jar:1.2.15
        - commons-logging:commons-logging:jar:1.1.1

    # open Buildr::XMLBeans namespace
    Buildr::XMLBeans:
      xmlbeans: 2.2

    # for subproject one:oldie
    one:oldie:
      spring:  org.springframework:spring:jar:1.0

-- buildfile --
ArtifactNamespace.load(Buildr.settings.profile['artifacts'])


250
251
252
# File 'lib/buildr/packaging/artifact_namespace.rb', line 250

def load(namespaces = {})
  namespaces.each_pair { |name, uses| instance(name).use(uses) }
end

.root {|ROOT| ... } ⇒ Object

:call-seq:

ArtifactNamespace.root { |ns| ... } -> ns

Obtain the root namespace, returns the ROOT constant

Yields:

  • (ROOT)


292
293
294
295
# File 'lib/buildr/packaging/artifact_namespace.rb', line 292

def root
  yield ROOT if block_given?
  ROOT
end

Instance Method Details

#[](*names) ⇒ Object

:call-seq:

artifact_ns[:name] -> ArtifactRequirement
artifact_ns[:many, :names] -> [ArtifactRequirement]


747
748
749
750
# File 'lib/buildr/packaging/artifact_namespace.rb', line 747

def [](*names)
  ary = values_at(*names)
  names.size == 1 ? ary.first : ary
end

#[]=(*names) ⇒ Object

:call-seq:

artifact_ns[:name] = 'some:cool:jar:1.0.2'
artifact_ns[:name] = '1.0.2'

Just like the use method



757
758
759
760
761
762
763
# File 'lib/buildr/packaging/artifact_namespace.rb', line 757

def []=(*names)
  values = names.pop
  values = [values] unless Array === values
  names.each_with_index do |name, i|
    use name => (values[i] || values.last)
  end
end

#accessor(*names) ⇒ Object

Return an anonymous module

# first create a requirement
artifact_ns.cool_aid! 'cool:aid:jar:>=1.0'

# extend an object as a cool_aid delegator
jars = Object.new.extend(artifact_ns.accessor(:cool_aid))
jars.cool_aid = '2.0'

artifact_ns.cool_aid.version # -> '2.0'


920
921
922
923
924
925
926
927
928
929
# File 'lib/buildr/packaging/artifact_namespace.rb', line 920

def accessor(*names)
  ns = self
  Module.new do
    names.each do |name|
      define_method("#{name}") { ns.send("#{name}") }
      define_method("#{name}?") { ns.send("#{name}?") }
      define_method("#{name}=") { |vers| ns.send("#{name}=", vers) }
    end
  end
end

#alias(new_name, old_name) ⇒ Object

Create an alias for a named requirement.



854
855
856
857
# File 'lib/buildr/packaging/artifact_namespace.rb', line 854

def alias(new_name, old_name)
  registry.alias(new_name, old_name) or
    raise NameError.new("Undefined artifact name: #{old_name}")
end

#artifacts(*names) ⇒ Object

return Artifact objects for each requirement



771
772
773
# File 'lib/buildr/packaging/artifact_namespace.rb', line 771

def artifacts(*names)
  (names.empty? && values || values_at(*names)).map(&:artifact)
end

#clearObject



828
829
830
# File 'lib/buildr/packaging/artifact_namespace.rb', line 828

def clear
  keys.each { |k| delete(k) }
end

#delete(name, include_parents = false) ⇒ Object



823
824
825
826
# File 'lib/buildr/packaging/artifact_namespace.rb', line 823

def delete(name, include_parents = false)
  registry.delete(name, include_parents)
  self
end

#each(&block) ⇒ Object

yield each ArtifactRequirement



766
767
768
# File 'lib/buildr/packaging/artifact_namespace.rb', line 766

def each(&block)
  values.each(&block)
end

#fetch(name, default = nil, &block) ⇒ Object

Like Hash#fetch



738
739
740
741
742
# File 'lib/buildr/packaging/artifact_namespace.rb', line 738

def fetch(name, default = nil, &block)
  block ||= proc { raise IndexError.new("No artifact found by name #{name.inspect} in namespace #{self}") }
  real_name = name.to_s[/^[\w\-\.]+$/] ? name : ArtifactRequirement.unversioned_spec(name)
  get(real_name.to_sym) || default || block.call(name)
end

#group(group_name, *members) ⇒ Object Also known as: virtual

:call-seq:

group :who, :me, :you
group :them, :me, :you, :namespace => ns

Create a virtual group on this namespace. When the namespace is asked for the who artifact, it’s value is an array made from the remaining names. These names are searched by default from the current namespace. Second form specified the starting namespace to search from.



841
842
843
844
845
846
847
848
849
# File 'lib/buildr/packaging/artifact_namespace.rb', line 841

def group(group_name, *members)
  namespace = (Hash === members.last && members.pop[:namespace]) || :current
  registry[group_name] = lambda do
    artifacts = self.class[namespace].values_at(*members)
    artifacts = artifacts.first if members.size == 1
    artifacts
  end
  self
end

#key?(name, include_parents = false) ⇒ Boolean

Returns:

  • (Boolean)


814
815
816
817
# File 'lib/buildr/packaging/artifact_namespace.rb', line 814

def key?(name, include_parents = false)
  name = ArtifactRequirement.unversioned_spec(name) unless name.to_s[/^[\w\-\.]+$/]
  registry.key?(name, include_parents)
end

#keysObject



819
820
821
# File 'lib/buildr/packaging/artifact_namespace.rb', line 819

def keys
  values.map(&:name)
end

#need(*specs) ⇒ Object

:call-seq:

artifact_ns.need 'name -> org:foo:bar:jar:~>1.2.3 -> 1.2.5'
artifact_ns.need :name => 'org.foo:bar:jar:1.0'

Create a new ArtifactRequirement on this namespace. ArtifactNamespace#method_missing provides syntactic sugar for this.



600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
# File 'lib/buildr/packaging/artifact_namespace.rb', line 600

def need(*specs)
  named = specs.flatten.inject({}) do |seen, spec|
    if Hash === spec && (spec.keys & ActsAsArtifact::ARTIFACT_ATTRIBUTES).empty?
      spec.each_pair do |name, spec|
        if Array === spec # a group
          seen[name] ||= spec.map { |s| ArtifactRequirement.new(s) }
        else
          artifact = ArtifactRequirement.new(spec)
          artifact.name = name
          seen[artifact.name] ||= artifact
        end
      end
    else
      artifact = ArtifactRequirement.new(spec)
      seen[artifact.name] ||= artifact
    end
    seen
  end
  named.each_pair do |name, artifact|
    if Array === artifact # a group
      artifact.each do |a|
        unvers = a.unversioned_spec
        previous = registry[unvers]
        if previous && previous.selected? && a.satisfied_by?(previous)
          a.version = previous.version
        end
        registry[unvers] = a
      end
      group(name, *(artifact.map { |a| a.unversioned_spec } + [{:namespace => self}]))
    else
      unvers = artifact.unversioned_spec
      previous = registry.get(unvers, true)
      if previous && previous.selected? && artifact.satisfied_by?(previous)
        artifact.version = previous.version
        artifact.selected!
      end
      registry[unvers] = artifact
      registry.alias name, unvers unless name.to_s[/^\s*$/]
    end
  end
  self
end

#ns(name, *uses) {|sub| ... } ⇒ Object

Create a named sub-namespace, sub-namespaces are themselves ArtifactNamespace instances but cannot be referenced by the Buildr.artifact_ns, ArtifactNamespace.instance methods. Reference needs to be through this object using the given name

artifact_ns('foo').ns(:bar).need :thing => 'some:thing:jar:1.0'
artifact_ns('foo').bar # => the sub-namespace 'foo.bar'
artifact_ns('foo').bar.thing # => the some thing artifact

See the top level ArtifactNamespace documentation for examples

Yields:

  • (sub)


573
574
575
576
577
578
579
580
581
582
583
584
585
586
# File 'lib/buildr/packaging/artifact_namespace.rb', line 573

def ns(name, *uses, &block)
  name = name.to_sym
  sub = registry[name]
  if sub
    raise TypeError.new("#{name} is not a sub namespace of #{self}") unless sub.kind_of?(ArtifactNamespace)
  else
    sub = ArtifactNamespace.new("#{self.name}.#{name}")
    sub.parent = self
    registry[name] = sub
  end
  sub.use(*uses)
  yield sub if block_given?
  sub
end

#ns?(name) ⇒ Boolean

Test if a sub-namespace by the given name exists

Returns:

  • (Boolean)


589
590
591
592
# File 'lib/buildr/packaging/artifact_namespace.rb', line 589

def ns?(name)
  sub = registry[name.to_sym]
  ArtifactNamespace === sub
end

#parentObject

ROOT namespace has no parent



536
537
538
539
540
541
542
543
544
545
546
547
548
549
# File 'lib/buildr/packaging/artifact_namespace.rb', line 536

def parent
  if root?
    nil
  elsif @parent.kind_of?(ArtifactNamespace)
    @parent
  elsif @parent
    ArtifactNamespace.instance(@parent)
  elsif name
    parent_name = name.gsub(/::?[^:]+$/, '')
    parent_name == name ? root : ArtifactNamespace.instance(parent_name)
  else
    root
  end
end

#parent=(other) ⇒ Object

Set the parent for the current namespace, except if it is ROOT



552
553
554
555
556
# File 'lib/buildr/packaging/artifact_namespace.rb', line 552

def parent=(other)
  raise 'Cannot set parent of root namespace' if root?
  @parent = other
  @registry = nil
end

#rootObject



531
532
533
# File 'lib/buildr/packaging/artifact_namespace.rb', line 531

def root
  ROOT
end

#root?Boolean

Is this the ROOT namespace?

Returns:

  • (Boolean)


559
560
561
# File 'lib/buildr/packaging/artifact_namespace.rb', line 559

def root?
  ROOT == self
end

#to_sObject

:nodoc:



859
860
861
# File 'lib/buildr/packaging/artifact_namespace.rb', line 859

def to_s #:nodoc:
  name.to_s
end

#use(*specs) ⇒ Object

:call-seq:

artifact_ns.use 'name -> org:foo:bar:jar:1.2.3'
artifact_ns.use :name => 'org:foo:bar:jar:1.2.3'
artifact_ns.use :name => '2.5.6'

First and second form are equivalent, the third is used when an ArtifactRequirement has been previously defined with :name, so it just selects the version.

ArtifactNamespace#method_missing provides syntactic sugar for this.



653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
# File 'lib/buildr/packaging/artifact_namespace.rb', line 653

def use(*specs)
  named = specs.flatten.inject({}) do |seen, spec|
    if Hash === spec && (spec.keys & ActsAsArtifact::ARTIFACT_ATTRIBUTES).empty?
      spec.each_pair do |name, spec|
        if ArtifactNamespace === spec # create as subnamespace
          raise ArgumentError.new("Circular reference") if self == spec
          registry[name.to_sym] = spec
        elsif Numeric === spec || (String === spec && VersionRequirement.version?(spec))
          artifact = ArtifactRequirement.allocate
          artifact.name = name
          artifact.version = spec.to_s
          seen[artifact.name] ||= artifact
        elsif Symbol === spec
          self.alias name, spec
        elsif Array === spec # a group
          seen[name] ||= spec.map { |s| ArtifactRequirement.new(s) }
        else
          artifact = ArtifactRequirement.new(spec)
          artifact.name = name
          seen[artifact.name] ||= artifact
        end
      end
    else
      if Symbol === spec
        artifact = get(spec).dclone
      else
        artifact = ArtifactRequirement.new(spec)
      end
      seen[artifact.name] ||= artifact
    end
    seen
  end
  named.each_pair do |name, artifact|
    is_group = Array === artifact
    artifact = [artifact].flatten.map do |artifact|
      unvers = artifact.unversioned_spec
      previous = get(unvers, false) || get(name, false)
      if previous # have previous on current namespace
        if previous.requirement # we must satisfy the requirement
          unless unvers # we only have the version
            satisfied = previous.requirement.satisfied_by?(artifact.version)
          else
            satisfied = previous.satisfied_by?(artifact)
          end
          raise "Unsatisfied dependency #{previous} " +
            "not satisfied by #{artifact}" unless satisfied
          previous.version = artifact.version # OK, set new version
          artifact = previous # use the same object for aliases
        else # not a requirement, set the new values
          unless artifact.id == previous.id && name != previous.name
            previous.copy_attrs(artifact)
            artifact = previous
          end
        end
      else
        if unvers.nil? && # we only have the version
            (previous = get(unvers, true, false, false))
          version = artifact.version
          artifact.copy_attrs(previous)
          artifact.version = version
        end
        artifact.requirement = nil
      end
      artifact.selected!
    end
    artifact = artifact.first unless is_group
    if is_group
      names = artifact.map do |art|
        unv = art.unversioned_spec
        registry[unv] = art
        unv
      end
      group(name, *(names + [{:namespace => self}]))
    elsif artifact.id
      unvers = artifact.unversioned_spec
      registry[name] = artifact
      registry.alias unvers, name
    else
      registry[name] = artifact
    end
  end
  self
end

#values(include_parents = false, include_groups = true) ⇒ Object

Return all requirements for this namespace



776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
# File 'lib/buildr/packaging/artifact_namespace.rb', line 776

def values(include_parents = false, include_groups = true)
  seen, dict = {}, registry
  while dict
    dict.each do |k, v|
      v = v.call if v.respond_to?(:call)
      v = v.values if v.kind_of?(ArtifactNamespace)
      if Array === v && include_groups
        v.compact.each { |v| seen[v.name] = v unless seen.key?(v.name) }
      else
        seen[v.name] = v unless seen.key?(v.name)
      end
    end
    dict = include_parents ? dict.parent : nil
  end
  seen.values
end

#values_at(*names) ⇒ Object

Return only the named requirements



794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
# File 'lib/buildr/packaging/artifact_namespace.rb', line 794

def values_at(*names)
  names.map do |name|
    catch :artifact do
      unless name.to_s[/^[\w\-\.]+$/]
        unvers = ArtifactRequirement.unversioned_spec(name)
        unless unvers.to_s == name.to_s
          req = ArtifactRequirement.new(name)
          reg = self
          while reg
            candidate = reg.send(:get, unvers, false, false, true)
            throw :artifact, candidate if req.satisfied_by?(candidate)
            reg = reg.parent
          end
        end
      end
      get(name.to_sym)
    end
  end
end