Root
Revision Rotator

Revision Rotator

Suppose you have a list of files like this:

a.v0    a.v1    a.v2    a.v3    a.v4    a.v5

It would be nice to "recycle" or rotate the filenames such that the result is:

a.v0    a.v1    a.v2    a.v3    a.v4

That is, files in the list are renamed to their predecessors, while the first file in the list is removed. This is a maintanance tool for a poorman's versioning system.

Code

I've written such a thing in Perl. Here is the code:

#!/usr/bin/perl -w
# Revision rotator
#
# Takes filenames of the form *.vi, where i is a positive integer,
# and operates on them such that the file with the smallest
# value of i is unlinked, and successors (as ordered by the numerical
# values of i) are renamed to their predecessors. Example:
#
# Input filenames: a.v5 a.v4 a.v1 a.v3 a.v2 a.v0
#
# Will perform:
#
#  unlink a.v0
#  mv a.v1 a.v0
#  mv a.v2 a.v1
#  mv a.v3 a.v2
#  mv a.v4 a.v3
#  mv a.v5 a.v4
#
# Functions correctly for i>9.
#
# Author: Michal Guerquin
# March, 2005

use strict;

my @files = @ARGV;

## make sure files are valid ".v#" files
for my $f (@files)
{
  if (not $f =~ /\.v(\d+)$/)
  {
    die "Invalid file specified: $f\n";
  }
}

## sort filenames by their trailing number
@files = sort ( { $a=~/(\d+)$/;my $aa=$1;$b=~/(\d+)$/;my $bb=$1; $aa <=> $bb } @ARGV);

## a list of cmds to execute
my @actions;

## for each file in the (sorted) list
for (my $i=0; $i<=$#files; $i++)
{
  ## if it's the first one, unlink it
  if ($i == 0)
  {
    push @actions, "unlink " . $files[$i];
  }
  ## otherwise, extract the name and version number,
  ## subtract 1 from v. number, and move file accordingly
  elsif ($i>0)
  {
    $files[$i] =~ /(.*)\.v(\d+)$/;
    my $fname = $1;
    my $newver = $2 - 1;

    push @actions, "mv " . $files[$i] . " " . $fname . ".v" . $newver;

    ## alternative behavior:
    ## this moves to the files "predecessor". so in a
    ## list of files a.v5, a.v7, a.v8, actions will
    ## be:
    ##
    ##   mv a.v7 a.v5
    ##   mv a.v8 a.v7
    ##
    ## push @actions, "mv " . $files[$i] . " " . $files[$i-1];
  }
}

## announce what will happen
print "Will perform the following commands:\n\n";
foreach my $a (@actions)
{
  print "  " . $a . "\n";
}
print "\nOkay to proceed? (y/n) ";

my $p = ;

$p = lc($p);
chomp($p);

if ($p ne "y")
{
  die "Aborted.\n";
}

## execute each command, printing status as it happens
foreach my $a (@actions)
{
  print "system(\"" . $a . "\");\n";
  system($a);
}

Usage

You can try it out like this, assuming you saved the above in a file revrotate.pl, and have a set of files a.v0 through a.v5:
$ ls a*
a.v0    a.v1    a.v2    a.v3    a.v4    a.v5
$ revrotate.pl a*
Will perform the following commands:

  unlink a.v0
  mv a.v1 a.v0
  mv a.v2 a.v1
  mv a.v3 a.v2
  mv a.v4 a.v3
  mv a.v5 a.v4

Okay to proceed? (y/n) y
system("unlink a.v0");
system("mv a.v1 a.v0");
system("mv a.v2 a.v1");
system("mv a.v3 a.v2");
system("mv a.v4 a.v3");
system("mv a.v5 a.v4");
$ ls a*
a.v0    a.v1    a.v2    a.v3    a.v4

I've found a really good use for this. Maybe you will too!


This is http://michal.guerquin.com/revrotate.html, updated 2005-03-08 01:01 EST

Contact: michalg at domain where domain is gmail.com (more)