From dce0a498b083f293ddf26258c43bfc461f06326f Mon Sep 17 00:00:00 2001 From: Kang-min Liu Date: Wed, 18 Sep 2024 20:10:24 +0900 Subject: [PATCH 1/4] add a subroutine for checking a given string looks like a release tarball url of skaji/relocatable-perl The URLs can be found from their "Releases" page: https://github.com/skaji/relocatable-perl/releases --- lib/App/Perlbrew/Util.pm | 11 ++++++++++- t/util-looks-like.t | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 t/util-looks-like.t diff --git a/lib/App/Perlbrew/Util.pm b/lib/App/Perlbrew/Util.pm index f3544f7c..d5312439 100644 --- a/lib/App/Perlbrew/Util.pm +++ b/lib/App/Perlbrew/Util.pm @@ -5,7 +5,7 @@ use 5.008; use Exporter 'import'; our @EXPORT = qw( uniq min editdist files_are_the_same perl_version_to_integer ); -our @EXPORT_OK = qw( find_similar_tokens ); +our @EXPORT_OK = qw( find_similar_tokens looks_like_url_of_skaji_relocatable_perl ); sub uniq { my %seen; @@ -98,4 +98,13 @@ sub find_similar_tokens { return \@similar_tokens; } +sub looks_like_url_of_skaji_relocatable_perl { + my ($str) = @_; + # https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-linux-amd64.tar.gz + my $prefix = "https://github.com/skaji/relocatable-perl/releases/download"; + my $version_re = qr/(5\.[0-9][0-9]\.[0-9][0-9]?.[0-9])/; + my $name_re = qr/perl-(linux|darwin)-(amd64|arm64)\.tar\.gz/; + $str =~ m{ \Q$prefix\E / $version_re / $name_re }x; +} + 1; diff --git a/t/util-looks-like.t b/t/util-looks-like.t new file mode 100644 index 00000000..0e79e7d0 --- /dev/null +++ b/t/util-looks-like.t @@ -0,0 +1,19 @@ +use Test2::V0; +use App::Perlbrew::Util qw(looks_like_url_of_skaji_relocatable_perl); + +subtest "looks_like_url_of_skaji_relocatable_perl", sub { + is(looks_like_url_of_skaji_relocatable_perl($_), T(), "positive case: $_") + for qw( + https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-darwin-amd64.tar.gz + https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-linux-amd64.tar.gz + ); + + is(looks_like_url_of_skaji_relocatable_perl($_), F(), "negative case: $_") + for qw( + https://example.com/ + https://gugod.org/ + https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-linux-x86_64.tar.gz + ); +}; + +done_testing; From beeed355f6f592988f3968be57e7ebfb97a12530 Mon Sep 17 00:00:00 2001 From: Kang-min Liu Date: Wed, 18 Sep 2024 20:25:09 +0900 Subject: [PATCH 2/4] return the details extracted from the URL --- lib/App/Perlbrew/Util.pm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/App/Perlbrew/Util.pm b/lib/App/Perlbrew/Util.pm index d5312439..15afffdf 100644 --- a/lib/App/Perlbrew/Util.pm +++ b/lib/App/Perlbrew/Util.pm @@ -104,7 +104,14 @@ sub looks_like_url_of_skaji_relocatable_perl { my $prefix = "https://github.com/skaji/relocatable-perl/releases/download"; my $version_re = qr/(5\.[0-9][0-9]\.[0-9][0-9]?.[0-9])/; my $name_re = qr/perl-(linux|darwin)-(amd64|arm64)\.tar\.gz/; - $str =~ m{ \Q$prefix\E / $version_re / $name_re }x; + return undef unless $str =~ m{ \Q$prefix\E / $version_re / $name_re }x; + return { + url => $str, + version => $1, + os => $2, + arch => $3, + original_filename => "perl-$2-$3.tar.gz", + }; } 1; From faaf86c1e2ec636235dfe2a7679de4e656ac1206 Mon Sep 17 00:00:00 2001 From: Kang-min Liu Date: Thu, 19 Sep 2024 19:31:24 +0900 Subject: [PATCH 3/4] test about how the extracted details should look like. --- t/util-looks-like.t | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/t/util-looks-like.t b/t/util-looks-like.t index 0e79e7d0..0cc40d38 100644 --- a/t/util-looks-like.t +++ b/t/util-looks-like.t @@ -2,11 +2,24 @@ use Test2::V0; use App::Perlbrew::Util qw(looks_like_url_of_skaji_relocatable_perl); subtest "looks_like_url_of_skaji_relocatable_perl", sub { - is(looks_like_url_of_skaji_relocatable_perl($_), T(), "positive case: $_") - for qw( - https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-darwin-amd64.tar.gz - https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-linux-amd64.tar.gz - ); + is( + looks_like_url_of_skaji_relocatable_perl($_), + hash { + field url => string($_); + field version => string('5.40.0.0'); + field os => in_set( + string('darwin'), + string('linux'), + ); + field arch => string("amd64"); + field original_filename => match(qr/^perl-(.+?)-amd64\.tar\.gz$/); + end(); + }, + "positive case: $_" + ) for qw( + https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-darwin-amd64.tar.gz + https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-linux-amd64.tar.gz + ); is(looks_like_url_of_skaji_relocatable_perl($_), F(), "negative case: $_") for qw( From 3dcdef338543d77f77b06f0a265e33ab571d98b0 Mon Sep 17 00:00:00 2001 From: Kang-min Liu Date: Thu, 19 Sep 2024 20:12:36 +0900 Subject: [PATCH 4/4] make `perlbrew installl` able to accept an URL to skaji/relocatable-perl tarball. It should be able to accept URLs found on this page: https://github.com/skaji/relocatable-perl/releases For example: perlbrew install https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-linux-amd64.tar.gz Or, with `--as` parameter: perlbrew install https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-linux-amd64.tar.gz --as perl-5.40 Currently this only download + extract the tarball, then move its content to the installation dir, without checking whether os/arch actually matches current environment. --- lib/App/perlbrew.pm | 66 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/lib/App/perlbrew.pm b/lib/App/perlbrew.pm index 921cfc4b..f9ffa4bd 100644 --- a/lib/App/perlbrew.pm +++ b/lib/App/perlbrew.pm @@ -21,10 +21,10 @@ BEGIN { use Getopt::Long (); use CPAN::Perl::Releases (); use JSON::PP qw( decode_json ); -use File::Copy qw( copy ); +use File::Copy qw( copy move ); use Capture::Tiny (); -use App::Perlbrew::Util qw( files_are_the_same uniq find_similar_tokens ); +use App::Perlbrew::Util qw( files_are_the_same uniq find_similar_tokens looks_like_url_of_skaji_relocatable_perl ); use App::Perlbrew::Path (); use App::Perlbrew::Path::Root (); use App::Perlbrew::HTTP qw( http_download http_get ); @@ -1227,6 +1227,10 @@ sub run_command_install { exit(-1); } + if ( my $detail = looks_like_url_of_skaji_relocatable_perl($dist) ) { + return $self->do_install_skaji_relocatable_perl($detail); + } + $self->{dist_name} = $dist; # for help msg generation, set to non # normalized name @@ -1630,6 +1634,64 @@ INSTALL return; } +sub do_install_skaji_relocatable_perl { + my ($self, $detail) = @_; + + my $installation_name = $self->{as} || ("skaji-relocatable-perl-" . $detail->{version}); + my $installation_path = $self->root->perls->child($installation_name); + + die "ERROR: Installation target \"${installation_name}\" already exists\n" + if $installation_path->exists; + + my $path = $self->root->dists + ->child("skaji-relocatable-perl") + ->child($detail->{version}) + ->mkpath() + ->child($detail->{original_filename}); + + if (-f $path) { + print "Re-using the downloaded $path\n"; + } else { + my $url = $detail->{url}; + print "Downloading $url as $path\n"; + my $error = http_download( $detail->{url}, $path ); + if ($error) { + die "Failed to download from $url\nError: $error"; + } + } + + my $extracted_path = $self->do_extract_skaji_relocatable_perl_tarball($detail, $path); + + move $extracted_path, $installation_path; + + print "$installation_name is installed at $installation_path.\n"; + + print "$installation_name is successfully installed.\n"; +} + +sub do_extract_skaji_relocatable_perl_tarball { + my ($self, $detail, $tarball_path) = @_; + + my $workdir = $self->builddir + ->child("skaji-relocatable-perl") + ->child($detail->{version}); + + $workdir->rmpath() + if $workdir->exists(); + + $workdir->mkpath(); + + my $tarx = "tar xzf"; + my $extract_command = "cd $workdir; $tarx $tarball_path"; + + system($extract_command) == 0 + or die "Failed to extract $tarball_path"; + + my ($extracted_path) = $workdir->children; + + return $extracted_path; +} + sub do_install_program_from_url { my ( $self, $url, $program_name, $body_filter ) = @_;