publicscripts/mycp/mycp

308 lines
6.6 KiB
Perl
Executable file

#!/usr/bin/perl -w
# $Id$
# $Source$
#
# Copyright (c) 2003 Ward Wouts <ward@wouts.nl>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
use strict;
use Sys::Hostname;
use Getopt::Std;
use File::Basename;
use File::Copy;
use Cwd;
use Cwd 'abs_path';
use vars qw(
$hostname
$cvspath
$editor
$cpcmd
$cvscmd
$mkdircmd
$sudocmd
);
$hostname = hostname();
#my $cvspath = "$ENV{HOME}/worktrees/systems/$hostname";
$editor = "vi";
$cpcmd = "/bin/cp";
$cvscmd = "/usr/bin/cvs";
$mkdircmd = "/bin/mkdir";
$sudocmd = "/usr/bin/sudo";
&readconfig;
my %option = ();
&cmdline;
if ( $cvspath ) {
&checkcvspath;
foreach ( @ARGV ) {
if ( -f $_ ) {
&incvs($_); # check if file exists in cvs else make it so
unless (&cmptocvs($_)) { # compare file to cvs
print "$_ not in sync with cvs version\n";
print "please fix this\n";
print "press enter to continue\n";
my $line = <>;
next;
}
if ( $option{e} ) {
&edit($_); # edit file
unless (&cmptocvs($_)) { # if changed... then:
&cvsupdate($_); # copy file to cvs & check in into cvs
# copy file back; don't change permissions
}
}
} else {
print "$_ is not a file, skipping. Press enter to continue.\n";
my $enter = <>;
}
}
} else {
foreach ( @ARGV ) {
&backup($_);
if ( $option{e} ) {
&edit;
}
}
}
sub cmdline {
getopts("eh", \%option);
if ( $option{h} ) { &help; }
if ( scalar(@ARGV) == 0 ) { &help; }
}
sub readconfig {
if ( -f "$ENV{HOME}/.mycprc" && -r "$ENV{HOME}/.mycprc" ) {
do "$ENV{HOME}/.mycprc" or die "Couldn't parse $ENV{HOME}/.mycprc\n";
} elsif ( -f "/etc/mycp" && -r "/etc/mycp" ) {
do "/etc/mycp" or die "Couldn't parse /etc/mycp\n";
}
}
sub backup($) {
my $file = shift;
my ( $base, $dir, $backup, @stat, @timestamp, $sfx, $n );
$base = basename($file);
$dir = dirname($file);
my @months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
if ( -f $file ) {
@stat = stat($file);
@timestamp = localtime($stat[9]);
$timestamp[5] += 1900;
if ( length($timestamp[3]) < 2 ) { $timestamp[3] = "0$timestamp[3]"; }
#
# ouderwetse moron style
# sane style introduceren
#
$sfx = "$timestamp[3]$months[$timestamp[4]]$timestamp[5]";
print "Creating \"$dir/OLD\" directory\n";
unless ( -d "$dir/OLD" ) {
if ( -w $dir ) {
mkdir "$dir/OLD", 0777 or die "Couldn't create $dir/OLD: $!\n";
} else {
system("$sudocmd mkdir " . &escape("$dir/OLD"));
}
}
$backup = "$dir/OLD/$base.$sfx";
if ( -e $backup && ! &cmp($file, $backup) ) {
$n = 1;
while ( -e "$backup-$n" && ! &cmp($file, "$backup-$n") ) {
$n++;
}
$backup = "$backup-$n";
}
if ( -w $file || -w &fullpath($file) ) {
copy("$file", "$backup") or die "Couldn't copy $file to $backup: $!\n";
} else {
system("$sudocmd $cpcmd " . &escape($file) . " " . &escape($backup));
}
} else {
die "No such file: $file\n";
}
}
sub incvs($) {
my $file = shift;
my $path = &fullpath($file);
if ( -f "$cvspath/$path/" . basename($file) ) {
return 1;
} else {
&cvsadd($file);
&checkin($file);
}
}
sub edit($) {
if ( exists $ENV{'EDITOR'} ) {
$editor = $ENV{'EDITOR'};
}
if ( -w $_ ) {
system("$editor " . &escape($_));
} else {
system("$sudocmd $editor ". &escape($_));
}
}
sub checkcvspath($) {
unless ( -d $cvspath ) {
print "$cvspath is not a directory. Set up cvs environment first.\n";
exit;
}
}
sub cvsadd($) {
my $file = shift;
my $cwd = cwd;
my $path = &fullpath($file);
$path =~ s|^\/||;
my $checkpath = $cvspath;
my $parent = $cvspath;
print "PATH: $path\n";
foreach my $i (split '/', $path) {
$checkpath .= "/$i";
if ( -d $checkpath ) {
print "$i issa dir\n";
} elsif ( -e $checkpath ) {
print "$i is not a dir, PROBLEM. Fix this by hand.\n";
exit;
} else {
print "making $checkpath\n";
mkdir $checkpath;
print "cd $parent\n";
chdir $parent;
system("$cvscmd add " . &escape($i));
}
$parent = $checkpath;
}
print "FILE: $file\n";
print "PATH: $checkpath\n";
copy($file, $checkpath) || die "error copying file to cvstree: $!\n";
chdir $checkpath;
system("$cvscmd add " . &escape(basename($file)));
chdir $cwd;
}
sub cvsupdate($) {
my $file = shift;
&copytocvs($file);
&checkin($file);
&copyfromcvs($file);
}
sub copytocvs($) {
my $file = shift;
my $cwd = cwd;
my $path = "$cvspath/" . &fullpath($file);
copy($file, $path);
chdir($path);
system("$cvscmd ci " . &escape(basename($file)));
chdir $cwd;
}
sub checkin($) {
my $file = shift;
my $cwd = cwd;
my $path = &fullpath($file);
chdir "$cvspath/$path";
system("$cvscmd ci " . &escape(basename($file)));
chdir $cwd;
}
sub copyfromcvs($) {
my $file = shift;
my $path = &fullpath($file);
my $fullname = "$path/" . basename($file);
if ( -w $fullname) {
copy("$cvspath/$fullname", $fullname);
} else {
system("$sudocmd $cpcmd " . &escape("$cvspath/$fullname") . " " . &escape($fullname));
}
# also check file permissions
}
sub cmptocvs($) {
my $file = shift;
my $path = &fullpath($file);
my $fullname = "$path/" . basename($file);
return &cmp("$cvspath/$fullname", $fullname);
}
sub cmp($$) {
my $source = shift;
my $target = shift;
open(FH, "<$source") or die "Couldn't open file $source: $!\n";
my $sf = do { local $/; <FH> };
close(FH);
open(FH, "<$target") or die "Couldn't open file $target: $!\n";
my $tf = do { local $/; <FH> };
close(FH);
$tf eq $sf;
}
sub askyn($) {
my $question = shift;
while (1) {
print "$question [y/n]? ";
my $line = <>;
if ( $line =~ /^y$/ ) {
return 1;
} elsif ( $line =~ /^n$/ ) {
return 0;
}
}
}
sub escape($) {
my $string = shift;
$string =~ s/([ \&\;\`\'\\\"\|\*\?\~\<\>\^\(\)\[\]\{\}\$\010\013\020\011])/\\${1}/g;
return $string;
}
sub fullpath($) {
my $file = shift;
my $path = dirname($file);
if ( $path =~ /^\// ) {
return $path;
} elsif ( $path =~ /^\.$/ ) {
return cwd;
} else {
$path = cwd . "/" . dirname($file);
$path = abs_path($path);
return $path;
}
}
sub help {
print <<EOT;
Usage: mycp [-e] [-h] <file1> [file2] ...";
EOT
exit;
}