Skip to content

Instantly share code, notes, and snippets.

@ugexe
Last active March 24, 2016 16:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ugexe/c5a74134164bcaabd756 to your computer and use it in GitHub Desktop.
Save ugexe/c5a74134164bcaabd756 to your computer and use it in GitHub Desktop.
method install(Distribution $dist, :$force) {
$!lock.protect( {
my @*MODULES;
my $path = self!writeable-path or die "No writeable path found, self.prefix not writeable";
my $lock //= self.prefix.child('repo.lock').open(:create, :w);
$lock.lock(2);
my $dist-id = $dist.id;
my $dist-dir = self!dist-dir;
if not $force and $dist-dir.child($dist-id) ~~ :e {
$lock.unlock;
fail "$dist already installed";
}
my $sources-dir = self!sources-dir;
my $resources-dir = self!resources-dir;
my $bin-dir = self!bin-dir;
my $is-win = Rakudo::Internals.IS-WIN;
self!add-short-name($dist.meta<name>, $dist); # so scripts can find their dist
# todo: emulate CUR `.files` for Distribution in a shared role
my %files;
my $implicit-files := $dist.meta<provides>.values;
my $explicit-files := $dist.meta<files>;
my $all-files := unique map { $_ ~~ Str ?? $_ !! $_.keys[0] },
grep *.defined, $implicit-files.Slip, $explicit-files.Slip;
for @$all-files -> $origpath {
# xxx: should really handle hash leaf nodes like Distribution does
state %pm6-path2name = $dist.meta<provides>.antipairs;
state @provides = $dist.meta<provides>.values; # only meant for use in a regex /^@provides/
given $origpath {
my $handle := $dist.content($origpath);
when /^@provides$/ {
my $name = %pm6-path2name{$origpath};
# $name is "Inline::Perl5" while $file is "lib/Inline/Perl5.pm6"
my $id = self!file-id($name, $dist-id);
my $destination = $sources-dir.child($id);
self!add-short-name($name, $dist);
note("Installing {$name} for {$dist.meta<name>}") if $verbose and $name ne $dist.meta<name>;
my $buf = $handle.open.slurp-rest(:bin);
$handle.close;
$destination.spurt($buf, :bin);
%files{$origpath} = $id;
}
when /^bin\// {
my $basename = $origpath.IO.basename;
my $id = self!file-id($origpath, $dist-id);
my $destination = $resources-dir.child($id);
my $withoutext = $basename.subst(/\.[exe|bat]$/, '');
for '', '-j', '-m' -> $be {
temp $perl_wrapper = $perl_wrapper.subst('#name#', $basename, :g).subst('#perl#', "perl6$be").subst('#dist-name#', $dist.meta<name>);
"$path/bin/$withoutext$be".IO.spurt: $perl_wrapper;
$is-win
?? "$path/bin/$withoutext$be.bat".IO.spurt: $windows_wrapper.subst('#perl#', "perl6$be", :g)
!! "$path/bin/$withoutext$be".IO.chmod(0o755);
}
self!add-short-name($basename, $dist);
my $buf = $handle.open.slurp-rest(:bin);
$handle.close;
$destination.spurt($buf, :bin);
%files{$origpath} = $id;
}
when /^resources\/$<subdir>=(.*)/ {
my $subdir = $<subdir>; # maybe do something with libraries
my $id = self!file-id($origpath, $dist-id) ~ '.' ~ $origpath.IO.extension;
my $destination = $resources-dir.child($id);
my $buf = $handle.open.slurp-rest(:bin);
$handle.close;
$destination.spurt($buf, :bin);
%files{$origpath} = $id;
}
}
}
# Create a Distribution with the updated `files` meta mapping for precomping
my $source-dist = Distribution::Local::Hash.new( %(|$dist.meta, :%files), :$.prefix );
$dist-dir.child($dist-id).spurt: to-json($source-dist.meta.hash);
my $precomped-dist = self!precompile-distribution($source-dist);
$dist-dir.child($dist-id).spurt: to-json($precomped-dist.meta.hash);
# reset cached id so it's generated again on next access.
# identity changes with every installation of a dist.
$!id = Any;
$lock.unlock;
} ) }
method !precompile-distribution(Distribution $dist is copy) {
my %provides = $dist.meta<provides>.hash;
my $precomp = $*REPO.precomp-repository;
my $*RESOURCES = Distribution::Resources.new(:repo(self), dist-id => $dist.id);
my %done;
for $dist.meta<provides>.kv -> $name, $origpath {
my $id = $dist.meta<files>{$origpath};
my $source = self!sources-dir.child($id);
if $precomp.may-precomp {
my $rev-deps-file = ($precomp.store.path($*PERL.compiler.id, $id) ~ '.rev-deps').IO;
my @rev-deps = $rev-deps-file.e ?? $rev-deps-file.lines !! ();
if %done{$name} { note "(Already did $name)" if $verbose; next }
note("Precompiling $name") if $verbose;
# xxx: can remove this. just using it to test arbitrary data structure extension validity
%provides{$name} = %($origpath => %(rev-deps => unique(@rev-deps)));
%done{$name} = $precomp.precompile($source.IO, $id, :force);
for @rev-deps -> $rev-dep-id {
if %done{$rev-dep-id} { note "(Already did $rev-dep-id)" if $verbose; next }
note("Precompiling reverse dependency $rev-dep-id") if $verbose;
my $rev-dep-source = self!sources-dir.child($rev-dep-id);
%done{$rev-dep-id} = $precomp.precompile($rev-dep-source, $rev-dep-id, :force) if $source.e;
}
}
}
# Create a Distribution with the updated `files` meta mapping for precomping
Distribution::Local::Hash.new( %(|$dist.meta, :%provides), :$.prefix );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment