1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
use Zef;
use Zef::Identity;
role DependencySpecification {
method name(--> Str) { ... }
method identity(--> Str) { ... }
method spec-matcher($spec --> Bool:D) { ... }
}
class Zef::Distribution::DependencySpecification::Any does DependencySpecification {
has @.specs;
method name { "any({@.specs.map(*.name).join(', ')})" }
method identity { "any({@.specs.map(*.identity).join(',')})" }
method spec-matcher($spec --> Bool:D) {
return so @!specs.first(*.spec-matcher($spec));
}
}
class Zef::Distribution::DependencySpecification does DependencySpecification {
has $!ident;
has $.spec;
submethod TWEAK(:$!spec, :$!ident) { }
multi submethod new(Zef::Identity $ident) { self.bless(:$ident) }
multi submethod new(Str $spec) { self.bless(:$spec) }
multi submethod new(Hash $spec) { self.bless(:$spec) }
multi submethod new(Hash $spec where {$_.keys == 1 and $_.keys[0] eq 'any'}) {
Zef::Distribution::DependencySpecification::Any.new: :specs(
$spec.values[0].map: {self.new($_)}
)
}
multi submethod new($spec) {
die "Invalid dependency specification: $spec.gist()";
}
method identity {
my $hash = %(:name($.name), :ver($.version-matcher), :auth($.auth-matcher), :api($.api-matcher), :from($.from-matcher));
my $identity = hash2identity( $hash );
$identity;
}
method clone(|) { $!ident = Nil; nextsame(); }
method spec-parts(Zef::Distribution::DependencySpecification:_: $spec = self!spec) {
# Need to find a way to break this cache when a distribution gets cloned with a different version
$!ident //= Zef::Identity.new(|$spec);
$!ident.?hash;
}
method name { self.spec-parts<name> }
method ver { self.spec-parts<ver> }
method version-matcher { self.spec-parts<ver> // '*' }
method auth-matcher { self.spec-parts<auth> // '' }
method api-matcher { self.spec-parts<api> // '*' }
method from-matcher { self.spec-parts<from> // '' }
method !spec { $.spec || self.Str }
multi method spec-matcher(Zef::Distribution::DependencySpecification::Any $spec, Bool :$strict = True) {
self.spec-matcher(any($spec.specs), :$strict)
}
multi method spec-matcher($spec, Bool :$strict = True) {
return False unless $spec.name.?chars && self.name.?chars;
if $strict {
return False unless $spec.name eq self.name;
}
else {
my $name = $spec.name;
return False unless self.name ~~ /[:i $name]/;
}
if $spec.auth-matcher.chars {
return False unless $.auth-matcher.chars && $spec.auth-matcher eq $.auth-matcher;
}
if $spec.version-matcher.chars && $spec.version-matcher ne '*' && $.version-matcher ne '*' {
my $spec-version = Version.new($spec.version-matcher);
my $self-version = Version.new($.version-matcher);
return False unless self!version-matcher(:$spec-version, :$self-version);
}
if $spec.api-matcher.chars && $spec.api-matcher ne '*' && $.api-matcher ne '*' {
my $spec-version = Version.new($spec.api-matcher);
my $self-version = Version.new($.api-matcher);
return False unless self!version-matcher(:$spec-version, :$self-version);
}
return True;
}
method !version-matcher(Version :$self-version is copy, Version :$spec-version is copy) {
# Normalize the parts between version so that Version ~~ Version works in the way we need
# Example: for `0.1 ~~ 0.1.1` we want `0.1.0` ~~ `0.1.1`
my $self-add-parts = $spec-version.parts.elems - $self-version.parts.elems;
$self-version = Version.new( (|$self-version.parts, |(0 xx $self-add-parts), ("+" if $self-version.plus)).join('.') )
if $self-add-parts > 0;
my $spec-add-parts = $self-version.parts.elems - $spec-version.parts.elems;
$spec-version = Version.new( (|$spec-version.parts, |(0 xx $spec-add-parts), ("+" if $spec-version.plus)).join('.') )
if $spec-add-parts;
return $self-version ~~ $spec-version;
}
}
|