X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=helpers%2Fbump-version;h=e0c1fa8cbc3ed1f5d13bc69f52854a892764ddd4;hb=f7d6fb435210129982ff62723e5bfcaeb56c63bf;hp=b9c20926ac3759ae83e11136a8ba304e2bdf3424;hpb=8ab5ea70c51d8601bdab7a310b9893fed7afc9b2;p=p5sagit%2FDistar.git diff --git a/helpers/bump-version b/helpers/bump-version index b9c2092..e0c1fa8 100755 --- a/helpers/bump-version +++ b/helpers/bump-version @@ -3,84 +3,222 @@ use strict; use warnings FATAL => 'all'; use File::Find; +use Getopt::Long qw(:config gnu_getopt); +use File::Temp (); -sub version_parts { - my @parts = split /\./, shift; - if (@parts == 2) { - my $dec = pop @parts; - push @parts, $dec =~ /(\d{1,3})/g; - } - $_ += 0 for @parts; - push @parts, 0 - until @parts >= 3; - return @parts; -} +GetOptions( + "git" => \my $git, + "force" => \my $force, + 'n|dry-run' => \my $dry_run, +) or die("Error in command line arguments\n"); -chomp(my $LATEST = qx(grep '^[0-9]' Changes | head -1 | awk '{print \$1}')); +my $old_version = shift + or die "no old version provided!\n"; +my $bump = shift; +my ($new_decimal, $new_vstring) = bump_version($old_version, $bump); -my @parts = version_parts($LATEST); +warn "Bumping $old_version -> $new_decimal" . ($new_decimal ne $new_vstring ? " ($new_vstring)" : '') . "\n"; -my $OLD_DECIMAL = sprintf('%i.%03i%03i', @parts); +my $file_match = qr{ + Makefile\.PL + |lib[/\\].*\.(?:pod|pm) + |bin[/\\].* + |script[/\\].* +}x; -my %bump_part = (major => 0, minor => 1, bugfix => 2); +my $dir_match = qr{ + (?: + . + |lib + |bin + |script + ) + (?:[/\\]|$) +}x; -my @new_parts = @parts; +my %files; +if ($git) { + if (system "git diff --quiet --cached HEAD") { + die "Staged changes!\n"; + } + for (`git ls-files`) { + chomp; + next + unless /^$file_match$/; + $files{$_} = `git show HEAD:"$_"`; + } +} +else { + find({ + no_chdir => 1, + wanted => sub { + my $fn = File::Spec->abs2rel($_, '.'); + if (-d && $fn !~ /^$dir_match$/) { + $File::Find::prune = 1; + return; + } + return + unless -f; + return + unless $fn =~ /^$file_match$/; + open my $fh, '<', $fn + or die "can't open $fn: $!"; + $files{$fn} = do { local $/; <$fh> }; + close $fh; + }, + }, '.'); +} -my $bump_this = $bump_part{$ARGV[0]||'bugfix'}; +my $FILE_RE = qr{ + (^.* \$VERSION \s* = \s* ) + (['"]?) v?([0-9]+(?:[._][0-9]+)*) \2 + ( \s*; ) + (?: + (\s*\#\s*) + v?[.0-9]+ + )? + (.*)$ +}x; +my $MAKE_RE = qr{ + (^.* ['"]?version['"] \s* => \s* ) + (['"]?) v?([0-9]+(?:[._][0-9]+)*) \2 + ( \s*, ) + (?: + (\s*\#\s*) + v?[.0-9]+ + )? + (.*)$ +}x; -if (defined $bump_this) { - $new_parts[$bump_this]++; - $new_parts[$_] = 0 for ($bump_this+1 .. $#new_parts); +my $patch = ''; +for my $file (sort keys %files) { + eval { + my $content = $files{$file}; + my $file_diff = ''; + my $re = $file eq 'Makefile.PL' ? $MAKE_RE : $FILE_RE; + my @lines = split /\r?\n/, $content; + for my $ln (0 .. $#lines) { + my $line = $lines[$ln]; + if ($lines[$ln] =~ $re) { + die "unable to bump version number in $file from $old_version, found $3\n" + if !$force && $3 ne $old_version; + my $comment = ($5 ? $5 . $new_vstring : ''); + my $new_line = "$1'$new_decimal'$4$comment$6"; + $file_diff .= <<"END_DIFF"; +@@ -@{[ $ln ]},3 +@{[ $ln ]},3 @@ + $lines[$ln-1] +-$lines[$ln] ++$new_line + $lines[$ln+1] +END_DIFF + } + } + if ($file_diff) { + $patch .= <<"END_HEADER" . $file_diff; +--- a/$file ++++ b/$file +END_HEADER + } + 1; + } or $dry_run ? warn($@) : die($@); } -elsif ($ARGV[0] =~ /^[0-9]+(?:\.[0-9]+)*$/) { - @new_parts = version_parts($ARGV[0]); + +if ($dry_run) { + print $patch; + exit; } -else { - die "no idea which part to bump - $ARGV[0] means nothing to me" +my ($fh, $file) = File::Temp::tempfile( "bump-version-XXXXXX", TMPDIR => 1 ); +print { $fh } $patch; +close $fh; +system qw(git --no-pager apply --apply --stat), $file + and exit 1; + +if ($git) { + system qw(git apply --cached), $file + and exit 1; + + my $message = "Bumping version to $new_decimal"; + system qw(git commit -m), $message + and exit 1; +} + +sub version_parts { + my $version = shift; + my $dotted = $version =~ s/^v//; + my @parts = split /\./, $version; + if (!$dotted && @parts <= 2) { + tr/_//d for @parts; + if (@parts == 2) { + my $dec = pop @parts; + $dec .= "0" x ((- length $dec) % 3); + push @parts, $dec =~ /(\d{1,3})/g; + } + } + elsif ($version =~ tr/_//) { + die "don't know how to handle underscores in dotted-decimal versions!\n"; + } + $_ += 0 for @parts; + return @parts; } -my $NEW_DECIMAL = sprintf('%i.%03i%03i', @new_parts); +sub bump_version { + my ($version, $new) = @_; -warn "Bumping $OLD_DECIMAL -> $NEW_DECIMAL\n"; -my $vstring = join('.', @parts); + my %bump_part = (major => 0, minor => 1, bugfix => 2, last => -1); + my $bump_this = $bump_part{$new||'last'}; -my %files; -find({ - no_chdir => 1, - wanted => sub { - return - unless -f && /\.pod$|\.pm$/; - my $file = $_; - open my $fh, '<', $file - or die "can't open $file: $!"; - my $content = do { local $/; <$fh> }; - close $fh; - - $content =~ s{ - ( \$VERSION \s* = \s* ) - (['"]?) v?([.0-9]+) \2 - ( - \s*; - (?: \s*\#\s* )? - ) - (v?[.0-9]+)? - }{ - die "unable to bump version number in $file from $OLD_DECIMAL, found $3\n" - if $3 ne $OLD_DECIMAL && $3 ne $vstring; - $1 . "'" . $NEW_DECIMAL . "'" . $4 . ( - $5 ? $vstring : '' - ) - }xe - or return; - - $files{$file} = $content; - }, -}, 'lib'); + my $new_vstring; + my $new_decimal; -for my $file (sort keys %files) { - warn " updating $file\n"; - open my $fh, '>', $file - or die "can't open $file: $!"; - print { $fh } $files{$file}; - close $fh; + if (defined $bump_this) { + if ($version =~ /^v/ || ($version =~ tr/.//) > 1) { + my $v = $version =~ /^(v)/ ? $1 : ''; + my @parts = version_parts($version); + $bump_this += @parts + if $bump_this < 0; + $parts[$_] = 0 for $bump_this+1 .. $#parts; + $parts[$_] = 0 for $#parts+1 .. $bump_this; + $parts[$bump_this]++; + $_ += 0 + for @parts; + $new_decimal = $new_vstring = $v . join '.', @parts; + } + else { + my $alpha_pos = index($version, '_'); + if ($alpha_pos == -1) { + undef $alpha_pos; + } + else { + my $dot_pos = index($version, '.'); + $alpha_pos = $dot_pos == -1 ? -$alpha_pos : $alpha_pos - $dot_pos; + } + $new_decimal = $version; + $new_decimal =~ tr/_//d; + my $dec_len = $new_decimal =~ /(\.\d+)/ ? length($1) - 1 : 0; + if ($bump_this != -1) { + my $cut_len = $bump_this * 3; + $dec_len = $cut_len + if $dec_len < $cut_len; + $new_decimal =~ s/(\..{1,$cut_len}).*/$1/; + } + $new_decimal += 10 ** -($bump_this == -1 ? $dec_len : ($bump_this * 3)); + $new_decimal = sprintf "%.${dec_len}f", $new_decimal; + if (defined $alpha_pos) { + my $dot_pos = index($new_decimal, '.'); + $dot_pos = length $new_decimal + if $dot_pos == -1; + substr $new_decimal, $dot_pos + $alpha_pos, 0, '_'; + } + $new_vstring = 'v' . join '.', version_parts($new_decimal); + } + } + elsif ($new =~ /^v?[0-9]+(?:[._][0-9]+)*$/) { + $new_decimal = $new; + $new_vstring = join('.', version_parts($new_decimal)); + } + else { + die "no idea which part to bump - $new means nothing to me" + } + return ($new_decimal, $new_vstring); } +