newspaint

Documenting Problems That Were Difficult To Find The Answer To

Summarising Local Changes Against A CVS Repository

Say you have a large project checked out from CVS with many subdirectories. And you want to know what files you have changed that need checking in.

You could use the cvs status command but the output can get unwieldy on the screen. The following script presents a coloured text summary.

#!/usr/bin/perl -w # -*-CPerl-*-

use constant DEBUG => 0;

use strict;

my $cvs = "cvs";

# using ANSI?
my $ansicolor = 1;
eval "use Term::ANSIColor;";
if ( $@ ) {
    $ansicolor = undef;
}

# can we detect column width?
my $columns = undef;
if ( ! $columns ) {
    eval {
        my ( $fin, $line );
        if ( open( $fin, "resize |" ) ) {
            while ( defined( $line = <$fin> ) ) {
                if ( $line =~ m/COLUMNS=(\d+)/ ) {
                    $columns = $1;
                    last;
                }
            }
        }
        close( $fin );
    };
    if ( DEBUG() && $@ ) {
        my $err = $@; warn( $err );
    }
}

if ( ! $columns ) {
    eval {
        my ( $fin, $line );
        if ( open( $fin, "stty -a |" ) ) {
	    while ( defined( $line = <$fin> ) ) {
	        if ( $line =~ m/columns\s+(\d+)/ ) {
	            $columns = $1;
		    last;
	        }
            }
	}
	close( $fin );
    };
    if ( DEBUG() && $@ ) {
        my $err = $@; warn( $err );
    }
}
#$columns-- if ( $columns && ( $columns > 1 ) );
if ( DEBUG() ) {
    print( "Using columns of \"$columns\"\n" ) if ( $columns );
    print( "Could not determine column width\n" ) if ( ! $columns );
}

# autoflush on
select( (select(STDERR), $|=1)[0] );
select( (select(STDOUT), $|=1)[0] );

# start the cvs status command
my $arg = join( " ", map { "\"$_\"" } @ARGV );

if ( ! open( FIN, "$cvs status $arg 2>&1 |" ) ) {
    die( "Could not start cvs: $!" );
}

# cycle through each line of text returned by cvs status
my $lastdir = undef;
my $lastlength = 0;
while ( defined( my $line = <FIN> ) ) {
    if ( $line =~ m/^(cvs \S+: )(Examining )(.*)/s ) {
        my $dispdir;

        my $dir = $3;
        if ( ( $columns ) && ( $columns <= length( $1 . $2 . $3 ) ) ) {
            $dir = substr( $3, 0, ( $columns - length( $1 . $2 ) ) - 1 );
        }

        if ( $ansicolor ) {
            eval '$lastdir = $1 .color("yellow") .$2 .$3 .color("reset");';
            eval '$dispdir = $1 .color("yellow") .$2 .$dir .color("reset");';
        } else {
            $lastdir = $1 . $2 . $3;
            $dispdir = $1 . $2 . $dir;
        }

        my $length12dir = length( $1 . $2 . $dir );

        $lastdir =~ s/[\r\n]+//gs;
        $dispdir =~ s/[\r\n]+//gs;

        print( ( ' ' x $lastlength ) . "\r" );
        $lastlength = $length12dir;
        print( $dispdir . "\r" );
    }

    if ( $line =~ m/^(File: )(.*?)(\s+)(Status: )(.*)/s ) {
        my $fileline = undef;
        if ( $ansicolor ) {
            eval '$fileline = $1 . color("cyan") . $2 . color("reset") . $3 . $4 . color("magenta") . $5 . color("reset")';
        } else {
            $fileline = $1 . $2. $3. $4. $5;
        }

        if ( $line !~ m/Status: Up-to-date/ ) {
            if ( $lastdir ) {
                print( ( ' ' x length($lastdir) ) . "\r" );
                print( $lastdir . "\n" );
                $lastdir = undef;
            }

            print( $fileline );
        }
    }
}

# clean up screen
if ( $lastdir ) {
    print( ' ' x length($lastdir) . "\r" );
}

# close cvs
close( FIN );

It first attempts to discover the terminal width so that directory names don’t spill off the edge when displaying what folder is currently being analysed.

Example output would be:

host@server:/tmp/cvs# cvschange.pl
cvs status: Examining mytest
File: verifymsg         Status: Locally Modified
cvs status: Examining nagiosconf
File: nsca.pl           Status: Locally Modified

This script was written in 2006.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: