calculate version parts correctly for short versions
[p5sagit/Distar.git] / helpers / bump-version
CommitLineData
8ab5ea70 1#!/usr/bin/env perl
2
3use strict;
4use warnings FATAL => 'all';
5use File::Find;
ece2756d 6use Getopt::Long qw(:config gnu_compat);
7use File::Temp ();
8
9GetOptions(
10 "git" => \my $git,
11) or die("Error in command line arguments\n");
12
13my ($old_version, $bump) = @ARGV;
14my ($new_decimal, $new_vstring) = bump_version($old_version, $bump);
15
16warn "Bumping $old_version -> $new_decimal\n";
17
18my %files;
19if ($git) {
176acdb4 20 if (system "git diff --quiet --cached HEAD") {
ece2756d 21 die "Staged changes!\n";
22 }
23 for (`git ls-files`) {
24 chomp;
25 next
26 unless /^lib\/.*\.(?:pod|pm)$/ || /^Makefile\.PL$/;
27 $files{$_} = `git show HEAD:"$_"`;
28 }
29}
30else {
31 find({
32 no_chdir => 1,
33 wanted => sub {
34 next
35 unless -f;
36 next
37 unless /^lib\/.*\.(?:pod|pm)$/ || /^Makefile\.PL$/;
38 open my $fh, '<', $_
39 or die "can't open $_: $!";
40 $files{$_} = do { local $/; <$fh> };
41 close $fh;
42 },
43 }, 'lib');
44}
45
46my $FILE_RE = qr{
47 (^.* \$VERSION \s* = \s* )
48 (['"]?) v?([0-9]+(?:[._][0-9]+)*) \2
49 ( \s*; )
50 (?:
51 (\s*\#\s*)
52 v?[.0-9]+
53 )?
54 (.*)$
55}x;
56my $MAKE_RE = qr{
57 (^.* version \s* => \s* )
58 (['"]?) v?([0-9]+(?:[._][0-9]+)*) \2
59 ( \s*, )
60 (?:
61 (\s*\#\s*)
62 v?[.0-9]+
63 )?
64 (.*)$
65}x;
66
67my $patch = '';
68for my $file (sort keys %files) {
69 my $content = $files{$file};
70 my $file_diff = '';
71 my $re = $file eq 'Makefile.PL' ? $MAKE_RE : $FILE_RE;
72 my @lines = split /\r?\n/, $content;
73 for my $ln (0 .. $#lines) {
74 my $line = $lines[$ln];
75 if ($lines[$ln] =~ $re) {
76 die "unable to bump version number in $file from $old_version, found $3\n"
77 if $3 ne $old_version;
78 my $comment = ($5 ? $5 . $new_vstring : '');
79 my $new_line = "$1'$new_decimal'$4$comment$6";
80 $file_diff .= <<"END_DIFF";
81@@ -@{[ $ln ]},3 +@{[ $ln ]},3 @@
82 $lines[$ln-1]
83-$lines[$ln]
84+$new_line
85 $lines[$ln+1]
86END_DIFF
87 }
88 }
89 if ($file_diff) {
90 $patch .= <<"END_HEADER" . $file_diff;
91--- a/$file
92+++ b/$file
93END_HEADER
94 }
95}
96
97my ($fh, $file) = File::Temp::tempfile( "bump-version-XXXXXX", TMPDIR => 1 );
98print { $fh } $patch;
99close $fh;
413a726c 100system qw(git --no-pager apply --apply --stat), $file
ece2756d 101 and exit 1;
102
103if ($git) {
104 system qw(git apply --cached), $file
105 and exit 1;
106
107 my $message = "Bumping version to $new_decimal";
108 system qw(git commit -m), $message
109 and exit 1;
110}
8ab5ea70 111
112sub version_parts {
576656c4 113 my $version = shift;
114 my $dotted = $version =~ s/^v//;
115 my @parts = split /\./, $version;
116 if (!$dotted && @parts == 2) {
8ab5ea70 117 my $dec = pop @parts;
576656c4 118 $dec =~ s/_//g;
47ac0560 119 $dec .= "0" x ((- length $dec) % 3);
8ab5ea70 120 push @parts, $dec =~ /(\d{1,3})/g;
121 }
122 $_ += 0 for @parts;
123 push @parts, 0
124 until @parts >= 3;
125 return @parts;
126}
127
ece2756d 128sub bump_version {
129 my ($old_version, $new) = @_;
8ab5ea70 130
ece2756d 131 my %bump_part = (major => 0, minor => 1, bugfix => 2);
132 my $bump_this = $bump_part{$new||'bugfix'};
576656c4 133
ece2756d 134 my $new_vstring;
135 my $new_decimal;
8ab5ea70 136
ece2756d 137 if (defined $bump_this) {
138 my @new_parts = version_parts($old_version);
139 $new_parts[$bump_this]++;
140 $new_parts[$_] = 0 for ($bump_this+1 .. $#new_parts);
141 $new_vstring = join('.', @new_parts);
142 my $alpha_pos = index($old_version, '_');
143 my $format = '%i.' . ( '%03i' x (@new_parts - 1) );
144 $new_decimal = sprintf($format, @new_parts);
145 substr $new_decimal, $alpha_pos, 0, '_'
146 if $alpha_pos != -1;
147 }
148 elsif ($new =~ /^v?[0-9]+(?:[._][0-9]+)*$/) {
149 $new_decimal = $new;
150 $new_vstring = join('.', version_parts($new_decimal));
151 }
152 else {
153 die "no idea which part to bump - $new means nothing to me"
154 }
155 return ($new_decimal, $new_vstring);
a4c19845 156}
157