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