File: build-git

package info (click to toggle)
libgit-repository-perl 1.325-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 376 kB
  • sloc: perl: 661; makefile: 7
file content (270 lines) | stat: -rwxr-xr-x 8,130 bytes parent folder | download | duplicates (2)
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#!/usr/bin/env perl
use strict;
use warnings;
use Pod::Usage;
use File::Spec;
use File::Path qw( remove_tree );
use File::Temp qw( tempdir );
use Cwd qw( cwd );
use Getopt::Long;
use Git::Repository;
use Git::Version::Compare qw( cmp_git );
use System::Command 1.117;    # loop_on

# command-line options
my %option = (
    source      => '/opt/src/git',
    destination => '/opt/git',
    limit       => 0,
    verbose     => 0,
    rc          => 1,
);
GetOptions(
    \%option,  'source=s', 'destination=s', 'verbose+', 'quiet',
    'since=s', 'until=s',  'limit=i',       'force',
    'list',    'missing',  'installed',     'rc!',
    'fetch',   'test',     'docs',
    'help',    'manual',
) or pod2usage( -verbose => 0 );

# simple help/manual
pod2usage( -verbose => 1 ) if $option{help};
pod2usage( -verbose => 2 ) if $option{manual};

# verbosity options
my %run_opt;
$option{quiet}   = 1     if $option{test};
$option{verbose} = 0     if $option{quiet};
$run_opt{stderr} = undef if !$option{verbose};
$run_opt{stdout} = sub { print shift } if $option{verbose} > 1;

# git.git
my $r = Git::Repository->new( work_tree => $option{source} );

# fetch recent commits
$r->run( 'fetch' ) if $option{fetch};

# map version numbers to tags
my %tag_for = map { ( my $v = substr $_, 1 ) =~ y/-/./; ( $v => $_ ) }
  grep /^v[^0]/ && !/^v1\.0rc/,    # skip anything before 1.0
  $r->run( tag => '-l', 'v*' );

# select the versions to build and install
my @versions = sort cmp_git @ARGV ? @ARGV : keys %tag_for;

# replace aliases with the canonical name
{
    my %alias = (
        '1.0.1'   => '1.0.0a',
        '1.0.2'   => '1.0.0b',
    );
    my %seen;
    @versions = grep !$seen{$_}++, map $alias{$_} || $_, @versions;
}

@versions = grep !/rc/, @versions if !$option{rc};

@versions = grep !is_installed($_), @versions if $option{missing};
@versions = grep is_installed($_),  @versions if $option{installed};

@versions = grep cmp_git( $option{since}, $_ ) <= 0, @versions if $option{since};
@versions = grep cmp_git( $_, $option{until} ) <= 0, @versions if $option{until};

@versions = $option{limit} > 0
  ? @versions[ -$option{limit} .. -1 ]       # <limit> most recent
  : @versions[ 0 .. -$option{limit} - 1 ]    # <limit> most ancient
  if $option{limit};


# pick up invalid versions
my @nope = grep !exists $tag_for{$_}, @versions;
die "Can't compile non-existent versions: @nope\n" if @nope;

# just list the selected versions
print map "$_\n", @versions and exit if $option{list};

# test outputs TAP
if ( $option{test} ) {
    require Test::More;
    import Test::More;
    plan( tests => scalar @versions );
    $option{destination} = tempdir( CLEANUP => 1 );
}

# build install select versions
chdir $option{source} or die "Can't chdir to $option{source}: $!";
for my $version (@versions) {

    # skip if that git already exists (and runs)
    if ( is_installed($version) && !$option{force} ) {
        print "*** GIT $version ALREADY INSTALLED ***\n" if !$option{quiet};
        next;
    }
    else {
        print "*** GIT $version ***\n" if !$option{quiet};
        $r->run( checkout => '-f', '-q', $tag_for{$version} );
        $r->run( clean => '-xqdf' );

        # Fix various issues in the Git sources

        # Fix GIT-VERSION-GEN to use `git describe` instead of `git-describe`
        if (
            cmp_git( $version, '1.3.3' ) <= 0
            && cmp_git( '1.1.0', $version ) <= 0
            && do { no warnings; `git-describe`; $? != 0 }
          )
        {
            local ( $^I, @ARGV ) = ( '', 'GIT-VERSION-GEN' );
            s/git-describe/git describe/, print while <>;
        }

        # fix GIT_VERSION in the Makefile
        if ( cmp_git( $version, '1.0.9' ) == 0 ) {
            local ( $^I, @ARGV ) = ( '', 'Makefile' );
            s/^GIT_VERSION = .*/GIT_VERSION = $version/, print while <>;
        }

        # add missing #include <sys/resource.h>
        elsif (   cmp_git( $version, '1.7.5.rc0' ) <= 0
            && cmp_git( '1.7.4.2', $version ) <= 0 )
        {
            $r->run( 'cherry-pick', '-n',
                'ebae9ff95de2d0b36b061c7db833df4f7e01a41d' );

            # force the expected version number
            my $version_file = File::Spec->catfile( $r->work_tree, 'version' );
            open my $fh, '>', $version_file
              or die "Can't open $version_file: $!";
            print $fh "$version\n";
        }

        # settings
        my $prefix = File::Spec->catdir( $option{destination}, $version );
        my @make = ( make => "prefix=$prefix" );

        # clean up environment (possibly set by local::lib)
        local $ENV{PERL_MB_OPT};
        local $ENV{PERL_MM_OPT};
        remove_tree( $prefix ) if -e $prefix;

        # build
        run_cmd( @make => '-j3' );

        # install
        run_cmd( @make => 'install' );
        run_cmd( @make => 'install-doc' ) if $option{docs};

        # test the installation and remove all
        if ( $option{test} ) {
            ok( is_installed($version), "$version installed successfully" );
            remove_tree( $prefix );
        }
    }
}

sub run_cmd {
    print "* @_\n" if !$option{quiet};
    System::Command->loop_on( command => \@_, %run_opt ) or die "FAIL: @_\n";
}

sub is_installed {
    my ($version) = @_;
    my $git =
      File::Spec->catfile( $option{destination}, $version, 'bin', 'git' );
    return eval { Git::Repository->version_eq( $version, { git => $git } ) };
}

__END__

=pod

=head1 NAME

build-git - Build and install any Git

=head1 SYNOPSIS

    # clone git.git

    # build and install Git 1.7.2
    $ build-git 1.7.2

    # build and install all versions between 1.6.5 and 2.1.0
    $ build-git --since 1.6.5 --until 2.1.0

    # build and install all versions of Git (since 1.0.0)
    $ build-git

    # build and install the 5 most recent versions of the selection
    $ build-git --limit 5 ...

    # build and install the 5 most ancient versions of the selection
    $ build-git --limit -5 ...

    # fetch the latest commit and install the latest git
    $ build-git --fetch --limit 1

=head1 OPTIONS AND ARGUMENTS

=head2 Options

 --source <directory>         The location of the git.git clone checkout

 --destination <directory>    The location of the Git collection

 --fetch                      Start by doing a `git fetch`

 --list                       List the selected versions and exit

 --test                       Compile, install, test and uninstall
                              the selected versions. Outputs TAP.
                              (Implies --quiet and force --destination to
                              a temporary directory.)

 --since <version>            Select versions greater or equal to <version>

 --until <version>            Select versions less or equal to <version>

 --missing                    Select only non-installed versions

 --installed                  Select only installed versions
                              (incompatible with the --missing option)

 --limit <count>              Limit the number of versions in the selection
                              (if <count> is positive, keep the most recent
                              ones, if <count> is negative, keep the oldest)

 --verbose                    Used once, shows the STDERR of the commands
                              run to compile and install Git.
                              Used twice, also shows the STDOUT.

 --quiet                      Silence all output, including the progress status

=head2 Arguments

If no argument is given, all versions are selected.

=head1 DESCRIPTION

B<build-git> is a small utility to build and install any version of Git.

It automatically applies some necessary patches that are needed to compile
Git on recent systems.

It is used to test the L<Git::Repository> module against all versions
of Git.

=head1 AUTHOR

Philippe Bruhat (BooK) <book@cpan.org>

=head1 COPYRIGHT

Copyright 2016 Philippe Bruhat (BooK), all rights reserved.

=head1 LICENSE

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

=cut