/
Tar.pm6
147 lines (120 loc) · 5.51 KB
/
Tar.pm6
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use Distribution::Common::Tar;
use nqp;
class CompUnit::Repository::Tar does CompUnit::Repository {
has %!resources;# %?RESOURCES has to return IO::Paths, so cache what we write to temp files
has %!loaded;
has $.prefix;
my %seen;
method !dist { state $dist = Distribution::Common::Tar.new($.prefix.IO) }
method !path2name { state %path2name = self!dist.meta<provides>.map({ parse-value(.value) => .key }) }
method !name2path { state %name2path = self!dist.meta<provides>.map({ .key => parse-value(.value) }) }
method !cur-id($name) { nqp::sha1(join '/', $!prefix, $name, $*REPO.id) }
method !spec-matcher(:$name!, :$auth, :version(:$ver)) {
return unless any($name eq self!dist.meta<name>, |(self!dist.meta<provides><<$name>>:exists));
return if ?$auth and self!dist.meta<auth> !~~ $auth;
return if ?$ver and self!dist.meta<ver version>.first(*.defined) !~~ $ver;
True
}
method id { 'tar' }
method short-id { 'tar' }
method path-spec { 'tar#' }
method loaded returns Iterable {
return %!loaded.values;
}
method need(CompUnit::DependencySpecification $spec,
CompUnit::PrecompilationRepository $precomp = self.precomp-repository())
returns CompUnit:D
{
my $name = $spec.short-name;
my $name-path = self!name2path{$name};
if $name-path {
my $base = $!prefix.IO.child($name-path);
return %!loaded{$name} if %!loaded{$name}:exists;
return %seen{$base} if %seen{$base}:exists;
my $*RESOURCES = Distribution::Resources.new(:repo(self), :dist-id(''));
my $bytes = Blob.new( self!dist.content($name-path).slurp-rest(:bin) );
my $handle = CompUnit::Loader.load-source( $bytes );
return %!loaded{$name} //= %seen{$base} = CompUnit.new(
:$handle,
:short-name($name),
:version(Version.new: self!dist.meta<ver version>.first(*.defined) // 0),
:auth(self!dist.meta<auth> // Str),
:repo(self),
:repo-id(self!cur-id($name)),
:distribution(self!dist),
:!precompiled,
);
}
return self.next-repo.need($spec, $precomp) if self.next-repo;
X::CompUnit::UnsatisfiedDependency.new(:specification($spec)).throw;
}
method load(Str(Cool) $name-path) returns CompUnit:D {
my $name = self!path2name{$name-path} // (self!name2path{$name-path} ?? $name-path !! Nil);
my $path = self!name2path{$name-path} // (self!path2name{$name-path} ?? $name-path !! Nil);
if $path {
# XXX: Distribution::Common's .slurp-rest(:bin) doesn't work right yet, hence the `.encode`
my $bytes = Blob.new( self!dist.content($path).slurp-rest(:bin) );
my $handle = CompUnit::Loader.load-source( $bytes );
my $base = ~$!prefix.IO.child($path);
return %!loaded{$path} //= %seen{$base} = CompUnit.new(
:$handle,
:short-name($name),
:version(Version.new: self!dist.meta<ver version>.first(*.defined) // 0),
:auth(self!dist.meta<auth> // Str),
:repo(self),
:repo-id(self!cur-id($name)),
:distribution(self!dist),
:!precompiled,
);
}
return self.next-repo.load($path) if self.next-repo;
die("Could not find $path in:\n" ~ $*REPO.repo-chain.map(*.Str).join("\n").indent(4));
}
method resolve(
CompUnit::DependencySpecification $spec,
)
returns CompUnit
{
if self!spec-matcher(:name($spec.short-name), :auth($spec.auth-matcher), :ver($spec.version-matcher)) {
return CompUnit.new(
:handle(CompUnit::Handle),
:short-name($spec.short-name),
:version(Version.new: self!dist.meta<ver version>.first(*.defined) // 0),
:auth(self!dist.meta<auth> // Str),
:repo(self),
:repo-id(self!cur-id($spec.short-name)),
:distribution(self!dist),
:!precompiled,
);
}
return self.next-repo.resolve($spec) if self.next-repo;
Nil
}
method resource($dist-id, $key) {
%!resources{$key} //= do {
my $temp-repo-dir = $*TMPDIR.child($*REPO.id);
my $temp-dist-dir = $temp-repo-dir.child(nqp::sha1(self!dist.Str));
my $temp-file = $temp-dist-dir.child($key);
mkdir $temp-repo-dir unless $temp-repo-dir.e;
mkdir $temp-dist-dir unless $temp-dist-dir.e;
mkdir $temp-file.parent unless $temp-file.parent.e;
my $resource-handle = self!dist.content($key);
my $resource-bytes = Blob.new($resource-handle.open(:bin).slurp-rest(:bin));
spurt $temp-file, $resource-bytes;
IO::Path.new($temp-file);
}
}
# XXX: this method feels like it doesn't belong in a CUR that represent a single distribution
method files($file, :$name = self!dist.meta<name>, :$auth, :$ver) {
my @name-paths = self!dist.meta<files>.map(*.&parse-value);
return () if $file ~~ none(@name-paths) || !self!spec-matcher(:$name, :$auth, :$ver);
self!dist.meta;
}
my sub parse-value($str-or-kv) {
do given $str-or-kv {
when Str { $_ }
when Hash { $_.keys[0] }
when Pair { $_.key }
}
}
}