App-Bootstrap-Perl

 view release on metacpan or  search on metacpan

bin/bootstrap-perl  view on Meta::CPAN

                    "perl",
                    _perl_base_name(@_),
                   );
}

sub _perl_pathprefix {
        my ($perl_revision, $perl_version, $perl_subversion, $usethreads, $bit64, $taintsupport, $silentnotaint, $gitdescribe, $gitchangeset, $exe_suffixes, $blead) = @_;

        return join("-",
                    $prefixbase."/perl",
                    _perl_base_name(@_),
                    $gitdescribe,
                   );
}

# ========== setup user log ==========

setup_user();

# ========== getopt ==========

my $ok = GetOptions (
                     "prefix=s"     => \$prefix,
                     "prefixbase=s" => \$prefixbase,
                     "version|commit|c=s" => \$version,
                     "installdeps=s" => \$installdeps,
                     "sourcetgz=s"  => \$sourcetgz,
                     "blead!"       => \$blead,
                     "usethreads!"  => \$usethreads,
                     "use64bit!"    => \$bit64,
                     "taintsupport!" => \$taintsupport,
                     "silentnotaint!" => \$silentnotaint,
                     "help|h"       => \$help,
                     "jobs|j=i"     => \$jobs,
                     "test|t"       => \$test,
                     "cpan!"        => \$cpan,
                     "cleancpansources!" => \$cleancpansources,
                     "forcecpancfg!" => \$forcecpancfg,
                     "forcebuildperl!" => \$forcebuildperl,
                     "forcemoduleinstall!" => \$forcemoduleinstall,
                     'perlformance' => \$perlformance,
                     'perlformance-local' => \$perlformance_local,
                     'perlformance-report' => \$perlformance_report,
                     'dry|n'        => \$dry,
                     'mirror|m=s@'  => \@mirrors,
                     'module|M=s@'  => \@modules,
                     'run|r=s@'     => \@runscripts,
                     'runargs=s@'   => \@runargs,
                     'confargs=s@'  => \@confargs,
                     'exesuffixes=s@' => \@exesuffixes,
                     'giturl|g=s'   => \$giturl,
                    );

if ($help) {
        exec("perldoc", "bootstrap-perl") or do {
                print $USER "\nPlease see 'perldoc bootstrap-perl' for help.\n";
                exit 0;
        }
}

my $DISTROPREFSREPO     = "git://github.com/renormalist/cpanpm-distroprefs.git";
my $DISTROPREFSSRCBASE  = "$build_path";
my $DISTROPREFSSRC1     = "$DISTROPREFSSRCBASE/cpanpm-distroprefs/cpanpm/distroprefs";
my $DISTROPREFSSRC2     = "$DISTROPREFSSRCBASE/cpanpm-distroprefs/renormalist/distroprefs";
my $DISTROPREFSDIR      = $prefixbase."/cpan/prefs";
my $SOURCESDIR          = $prefixbase."/cpan/sources";
my $CPANBUILDDIR        = $prefixbase."/cpan/build";

# defaults
my @default_runscripts = ();
my @default_confargs   = ();
my @default_runargs    = ();
my @default_modules    = ();
my @default_mirrors    = (qw( http://search.cpan.org/CPAN/ ));

return if defined($::{"no_run"});
print $USER "\n";
print $USER "============================================================\n";
print $USER "Bootstrap Perl - $timestamp\n";
print $USER "============================================================\n";

# giturl "." means clone from local dir
if ($giturl eq '.') {
        $giturl = getcwd;
        my $firstcommit = qx!git log --oneline 8d063cd8450e59ea1c611a2f4f5a21059a2804f1 2> /dev/null!;
        if ($firstcommit !~ /a "replacement" for awk and sed/) {
                print $USER "Local git repo does not look like it is Perl's.\n";
                exit 1;
        }
}

# version "." is replaced with current repo's HEAD
if ($version =~ /^\./) {
        my $rev = print_and_qx_chomp qq!git rev-parse HEAD!;
        $version =~ s/^\./$rev/ if $rev;
}

if ($perlformance_local) {
        $giturl             = ".";
        @default_modules    = qw(Benchmark::Perl::Formance);
        @default_mirrors    = "file://".$ENV{HOME}."/CPAN/";
        @default_runscripts = qw(benchmark-perlformance);
        @default_runargs    = ("--plugins=Fib,FibOO,DPath,Mem,Rx,Shootout::fasta,Shootout::binarytrees,Shootout::nbody,Shootout::spectralnorm");
}
if ($perlformance or $perlformance_report) {
        @default_modules    = qw(Task::PerlFormance);
        @default_mirrors    = "file://".$ENV{HOME}."/CPAN/";
        @default_runscripts = qw(benchmark-perlformance);
        @default_runargs    = qw(--plugins=ALL);
}
if ($perlformance_report) {
        @default_runscripts = qw(tapper-testsuite-benchmark-perlformance);
        @default_runargs    = qw(--plugins=ALL);
        @default_runargs    = ("-Doptimize='-O2 -falign-loops=8 -falign-jumps=8 -falign-functions=64 -falign-labels=8 -mpreferred-stack-boundary=8 -minline-all-stringops'");
}

# modules/mirros/runscripts can be comma-separated
my @MODULES     = map { chomp; $_ } map { split(qr/,/, $_) } (@modules    ? @modules    : @default_modules);
my @CPANMIRRORS = map { chomp; $_ } map { split(qr/,/, $_) } (@mirrors    ? @mirrors    : @default_mirrors);
my @RUNSCRIPTS  = map { chomp; $_ } map { split(qr/,/, $_) } (@runscripts ? @runscripts : @default_runscripts);
my @RUNARGS     = map { chomp; $_ } map { split(qr/;/, $_) } (@runargs    ? @runargs    : @default_runargs);
my @EXESUFFIXES = sort map { chomp; $_ } map { split(qr/,/, $_) } @exesuffixes;
my $CONFARGS    = join " ", map { chomp; $_ } (@confargs ? @confargs : @default_confargs); # repeatable, but no comma-separate

# ========== build dependencies ==========

bin/bootstrap-perl  view on Meta::CPAN

}

# binaries
my $CPAN     = print_and_qx_chomp qq!ls -drt1 $PREFIX/bin/cpan5.*.*     | tail -1!;
my $PERL     = print_and_qx_chomp qq!ls -drt1 $PREFIX/bin/perl5.*.*     | tail -1!;
my $PERLDOC  = print_and_qx_chomp qq!ls -drt1 $PREFIX/bin/perldoc5.*.*  | tail -1!;
my $POD2TEXT = print_and_qx_chomp qq!ls -drt1 $PREFIX/bin/pod2text5.*.* | tail -1!;

# cpan config
my $CFG   = print_and_qx_chomp qq!$PERLDOC -l CPAN | sed -e "s/CPAN\.pm/CPAN\\/Config.pm/"!;
my $MYCFG = print_and_qx_chomp qq!$PERLDOC -l CPAN | sed -e "s/CPAN\.pm/CPAN\\/MyConfig.pm/"!;

my $bin_perl     = "$PREFIX/bin/perl";
my $bin_cpan     = "$PREFIX/bin/cpan";
my $bin_perldoc  = "$PREFIX/bin/perldoc";
my $bin_pod2text = "$PREFIX/bin/pod2text";
my $bin_mycpan   = "$PREFIX/bin/mycpan";

# some dists don't find the versioned developer files
print_and_system "if [ ! -e $bin_perl     ] ; then ln -sf $PERL     $bin_perl     ; echo Created symlink $bin_perl ; else echo Already exists: $bin_perl ; fi";
print_and_system "if [ ! -e $bin_cpan     ] ; then ln -sf $CPAN     $bin_cpan     ; echo Created symlink $bin_cpan ; else echo Already exists: $bin_cpan ; fi";
print_and_system "if [ ! -e $bin_perldoc  ] ; then ln -sf $PERLDOC  $bin_perldoc  ; echo Created symlink $bin_perldoc ; else echo Already exists: $bin_perldoc ; fi";
print_and_system "if [ ! -e $bin_pod2text ] ; then ln -sf $POD2TEXT $bin_pod2text ; echo Created symlink $bin_pod2text ; else echo Already exists: $bin_pod2text ; fi";

# our own cpan cmd with explicit config
if (not -e $bin_mycpan) {
  open (my $MYCPAN, '>', $bin_mycpan) or die "Can not create $bin_mycpan";
  print $MYCPAN qq{#! /bin/bash\n};
  print $MYCPAN qq{$CPAN -j $CFG "\$\@"\n};
  close $MYCPAN;
  print_and_system qq!chmod +x $bin_mycpan!;
}

print $USER "# PERL:     $PERL\n";
print $USER "# CPAN:     $CPAN\n";
print $USER "# MYCPAN:   $bin_mycpan\n";
print $USER "# PERLDOC:  $PERLDOC\n";
print $USER "# POD2TEXT: $POD2TEXT\n";
print $USER "# CPANCFG:  $CFG\n";

sub bin_cpan { $bin_cpan || "" }

# ========== cpan ==========

sub install_cpan_module {
        my ($perl, $cpan, $cfg, $reinstall, $force, $module) = @_;

        my $_f = ($force) ? "-f" : "";

        # remember shell bool logic, exitcode!=0 means fail means we install

        if (system "$perl -M$module -e1 2> /dev/null" || $reinstall) { # already exists or reinstall
            print_and_system qq{$cpan -j $cfg $_f -i $module};
        }
}

if ($cpan)
{
        print $USER "*** PREPARE cpan\n";

        # distroprefs: get all from git
        print_and_system "mkdir -p $DISTROPREFSSRCBASE";
        print_and_system "cd $DISTROPREFSSRCBASE && git clone $DISTROPREFSREPO" unless -d "$DISTROPREFSSRCBASE/cpanpm-distroprefs";
        print_and_system "cd $DISTROPREFSSRCBASE/cpanpm-distroprefs && git pull";
        print_and_system "cd $DISTROPREFSSRCBASE/cpanpm-distroprefs && git submodule update --init --recursive";
        print_and_system "cd $DISTROPREFSSRCBASE/cpanpm-distroprefs && git pull";
        # distroprefs: merge our flavour
        print_and_system qq!mkdir -p $DISTROPREFSDIR!;
        print_and_system qq!rsync -r $DISTROPREFSSRC1/ $DISTROPREFSDIR/!;
        print_and_system qq!rsync -r $DISTROPREFSSRC2/ $DISTROPREFSDIR/!;

        # Cleanup build dir
        print_and_system qq!rm -fr $CPANBUILDDIR!;

        # Configure CPAN initially
        if ($forcecpancfg or ! -e $CFG) {
                print $USER "*** CONFIGURE cpan\n";

                my $CPANCFG = do { local $/; <DATA> };
                my $MIRRORSLIST = join(" ", @CPANMIRRORS);
                $CPANCFG =~ s/__DISTROPREFSDIR__/$DISTROPREFSDIR/g;
                $CPANCFG =~ s/__MIRRORS__/$MIRRORSLIST/g;
                $CPANCFG =~ s/__PREFIXBASE__/$prefixbase/g;

                # the real cpan config
                open my $CPANCFGFILE, ">", $CFG or die "Can not create $CFG";
                print $CPANCFGFILE $CPANCFG;
                close $CPANCFGFILE;

                # empty MyConfig to suppress loading one from ~/.cpan/
                open my $MYCPANCFGFILE, ">", $MYCFG or die "Can not create $MYCFG";
                print $MYCPANCFGFILE "package CPAN::MyConfig;\n1;\n\n=head1 ABOUT\n\nEmpty CPAN::MyConfig to suppress loading one from C<~/.cpan/>.\n\n=cut\n\n";
                close $MYCPANCFGFILE;
        } else {
                print $USER "*** SKIP configuring cpan".(-e $CFG ? " - found $CFG" : "")."\n";
        }

        # remove stale cpan lock
        my $cpanlock = "$prefixbase/cpan/.lock";
        if (-e $cpanlock) {
                my ($pid, $host) = qx!cat $cpanlock!;
                chomp $pid;
                my $exists = kill 0, $pid;
                if (not $exists) {
                        print $LOGFILE "# Remove stale CPAN.pm lock.\n";
                        print_and_system qq!rm -f $cpanlock!;
                }
        }

        # optionally remove sources cache to avoid conflicts,
        # like happening with hot-patched CPAN mirrors (via Pinto)
        if ($cleancpansources) {
                print $LOGFILE "# Remove $SOURCESDIR.\n";
                print_and_system qq!rm -fr '$SOURCESDIR'!;
        }

        # force a CPAN.pm with all features we need, assume old-school CPAN.pm
        print_and_system qq{if [ -L $bin_cpan -o ! -e $bin_cpan ] ; then echo Why?: /bin/rm -f $bin_cpan ; echo "force install CPAN" | $PERL -MCPAN -e shell ; fi};

        # once upon a time the cpan exe missed the executable bit - set it to be sure
        print_and_system qq!chmod +x $CPAN!;
        print_and_system qq!chmod +x $bin_cpan!;

        print $USER "*** INSTALL cpan dependencies\n";

        # install extended cpan toolchain; contains some "force" where we know they are really required
        install_cpan_module($PERL, $bin_cpan, $CFG, NO_REINSTALL, FORCE, "CPAN::DistnameInfo");

bin/bootstrap-perl  view on Meta::CPAN


  $ bootstrap-perl --giturl git://github.com/mirrors/perl.git
  $ bootstrap-perl -g git://github.com/mirrors/perl.git # same
  $ bootstrap-perl -g .                                 # local dir

The giturl is always cloned from the specified giturl to a temporary
working directory, so your local subdir stays untouched.

=head3 install directory

Install into other install directory than the unified naming schema
(see below for more on this schema):

  $ bootstrap-perl --prefix <PREFIX>

Use the unified naming schema but not under C</$HOME/.bootstrapperl/$HOSTNAME>:

  $ bootstrap-perl --prefixbase /foo/bar

=head3 install build dependencies

Provide the distro for which to install known build dependencies, like
gcc, git, make, etc.:

 $ bootstrap-perl --installdeps=debian

Currently there is only one: C<debian>. Simply send me a patch for
your preferred distro, it's easy.

=head3 parallel build

Use this many parallel jobs to build:

  $ bootstrap-perl --jobs <n>
  $ bootstrap-perl -j <n>

Default is to use core count + 1.

=head3 test

Run the perl test suite:

  $ bootstrap-perl --test
  $ bootstrap-perl -t

Default is B<not> to run the tests.

=head3 (re-)build Perl

You can specify whether you want to compile perl even when an
executable C<perl> already exists:

  $ bootstrap-perl --forcebuildperl
  $ bootstrap-perl --noforcebuildperl

Default is B<off>.

=head3 bootstrap CPAN

You can specify whether to bootstrap a full CPAN environment with
distroprefs and dependencies:

  $ bootstrap-perl --cpan
  $ bootstrap-perl --nocpan

Default is B<on>.

=head3 (re-)configure CPAN

You can specify whether to (re-)write a CPAN config
(C<CPAN/Config.pm>, C<CPAN/MyConfig.pm>) even when it already exists:

  $ bootstrap-perl --forcecpancfg
  $ bootstrap-perl --noforcecpancfg

Default is B<on>.

=head3 use threads

Build a threaded Perl (C<-Dusethreads>):

  $ bootstrap-perl --usethreads

which is already the default. To build non-threaded Perl use:

  $ bootstrap-perl --nousethreads

=head3 use 64bit

Build a 64bit enabled Perl (C<-Duse64bitall>):

  $ bootstrap-perl --use64bit

which is already the default. To build Perl without 64bit use:

  $ bootstrap-perl --nouse64bit

=head3 taint support

Perl can be built without taint support (C<-DNO_TAINT_SUPPORT>, C<-DSILENT_NO_TAINT_SUPPORT>).

To build a Perl with taint support:

  $ bootstrap-perl --taintsupport

which is already the default.

To build Perl without taint support use:

  $ bootstrap-perl --notaintsupport

To make the notaintsupport silent, combine it with --silentnotaint:

  $ bootstrap-perl --notaintsupport --silentnotaint

(sic, both are needed).

=head3 version numbers vs. blead

By default the Perl version number is derived from git-describe and
kept for later reference (e.g., for codespeed exe name). However, if you

bin/bootstrap-perl  view on Meta::CPAN

  $ bootstrap-perl --module YAML::Syck --forcemoduleinstall
  $ bootstrap-perl -M YAML::Syck -M Digest::SHA1 -M IO::Tty -M LWP
  $ bootstrap-perl -M YAML::Syck,Digest::SHA1 -M IO::Tty,LWP

(Option can be repeated and allow comma separated lists.)

=head3 run scripts

Run these scripts relative to built <PREFIX>/bin/:

  $ bootstrap-perl --run tapper-testsuite-benchmark-perlformance
  $ bootstrap-perl --run tapper-testsuite-benchmark-perlformance --runargs="--plugins=Fib,FibOO;-vvv"
  $ bootstrap-perl -r tapper-testsuite-benchmark-perlformance -r primes.pl

(Option C<--run> can be repeated and allows comma separated lists.)

(Option C<--runargs> can be repeated and allows semicolon[sic] separated lists.)

=head3 run Perl::Formance benchmarks

To do everything in one go needed for running
Benchmark::Perl::Formance do:

  $ bootstrap-perl --perlformance

This sets defaults equivalent to C<-M Task::PerlFormance> C<-m
http://perlformance.net/PINTO/perlformance/> C<--run
benchmark-perlformance> C<--runargs=--plugins=ALL>.

You can override parts of that like this:

  $ bootstrap-perl --perlformance --runargs="--plugins=Fib,FibOO"

to specify different set ob benchmarks.

To use current subdir as Perl's repo and run only
those benchmarks with no extra dependencies

  $ bootstrap-perl --perlformance-local
  $ bootstrap-perl --perlformance-local -c .
  $ bootstrap-perl --perlformance-local -c .^
  $ bootstrap-perl --perlformance-local -c .~5

=head2 Unified installation prefix schema

It uses a unified naming schema for it's installation PREFIX:

  /$HOME/.bootstrapperl/$HOSTNAME/perl-5.<VERSION>-<(no)?thread>-<(no)?64bit>-<(no)?taint>-<git-describe>

which leads to paths like this:

  /home/ss5/.bootstrapperl/zomtec/perl-5.10-thread-64bit-taint-v5.10.0
  /home/ss5/.bootstrapperl/zomtec/perl-5.15-thread-64bit-taint-v5.15.5-258-ge7d0a3f

This naming schema consist of the major version, basic configuration
and I<git-describe>.

=head1 ABOUT

The script B<bootstrap-perl> bootstraps Perl installations with
complete CPAN environment, inclusive distroprefs, from git.

It was originally developed to be used by
L<Benchmark::Perl::Formance|Benchmark::Perl::Formance> and now lives
on its own.

It should work for Perl versions from 5.8.6 to blead. Occasionally it
cherry-picks a very few patches to fix some known build issues, like
for 5.8.x.

=head1 AUTHOR

Steffen Schwigon <ss5@renormalist.net>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2021 by Steffen Schwigon.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut

__DATA__

# Have POD in it so perldoc -l can find its path.

=head1 ABOUT

B<AUTO-GENERATED> -- see L<https://metacpan.org/pod/bootstrap-perl>

This is CPAN.pm's systemwide configuration file. This file provides
defaults for users, and the values can be changed in a per-user
configuration file. The user-config file is being looked for as
~/.cpan/CPAN/MyConfig.pm.

=cut

$CPAN::Config = {
  'applypatch' => q[/usr/bin/applypatch],
  'auto_commit' => q[1],
  'build_cache' => q[10],
  'build_dir' => q[__PREFIXBASE__/cpan/build],
  'build_dir_reuse' => q[0],
  'build_requires_install_policy' => q[yes],
  'bzip2' => q[/bin/bzip2],
  'cache_metadata' => q[0],
  'check_sigs' => q[0],
  'colorize_debug' => q[bold cyan],
  'colorize_output' => q[1],
  'colorize_print' => q[bold blue],
  'colorize_warn' => q[bold red],
  'commandnumber_in_prompt' => q[0],
  'connect_to_internet_ok' => q[0],
  'cpan_home' => q[__PREFIXBASE__/cpan],
  'dontload_hash' => {  },
  'ftp' => q[/usr/bin/ftp],
  'patch' => q[/usr/bin/patch],
  'ftp_passive' => q[1],
  'ftp_proxy' => q[],
  'getcwd' => q[cwd],
  'gpg' => q[/usr/bin/gpg],
  'gzip' => q[/bin/gzip],
  'halt_on_failure' => q[0],
  'histfile' => q[__PREFIXBASE__/cpan/histfile],
  'histsize' => q[100],
  'http_proxy' => q[],
  'inactivity_timeout' => q[0],
  'index_expire' => q[0],
  'inhibit_startup_message' => q[0],
  'keep_source_where' => q[__PREFIXBASE__/cpan/sources],
  'load_module_verbosity' => q[v],
  'lynx' => q[],
  'make' => q[/usr/bin/make],
  'make_arg' => q[],
  'make_install_arg' => q[],
  'make_install_make_command' => q[/usr/bin/make],
  'makepl_arg' => q[],
  'mbuild_arg' => q[],
  'mbuild_install_arg' => q[],
  'mbuild_install_build_command' => q[./Build],
  'mbuildpl_arg' => q[],
  'ncftp' => q[],
  'ncftpget' => q[],
  'no_proxy' => q[],
  'pager' => q[/usr/bin/less],
  'perl5lib_verbosity' => q[v],
  'prefer_installer' => q[MB],
  'prefs_dir' => q[__DISTROPREFSDIR__],
  'prerequisites_policy' => q[follow],
  'scan_cache' => q[atstart],
  'shell' => q[/bin/bash],
  'show_unparsable_versions' => q[0],
  'show_upload_date' => q[0],
  'show_zero_versions' => q[0],
  'tar' => q[/bin/tar],
  'tar_verbosity' => q[v],
  'term_is_latin' => q[0],
  'term_ornaments' => q[1],
  'test_report' => q[0],
  'trust_test_report_history' => q[0],
  'unzip' => q[],
  'urllist' => [qw[__MIRRORS__]],
  'use_sqlite' => q[0],
  'version_timeout' => q[15],
  'wget' => q[/usr/bin/wget],
  'yaml_load_code' => q[0],
  'yaml_module' => q[YAML],
};
1;



( run in 0.755 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )