From: short <> Date: Sun, 3 Mar 2002 22:33:05 +0000 (+0000) Subject: Utility to replace cvsignorerm{,all}{,rm} X-Git-Tag: bp_liverpm~166 X-Git-Url: https://git.jankratochvil.net/?p=nethome.git;a=commitdiff_plain;h=9d45569122b4c86a98c42fee954885f33af27e8d Utility to replace cvsignorerm{,all}{,rm} Feature: Proper distinction between files/ignores/workings/dirs Feature: safely sets CVS/Root --- diff --git a/bin/cvsutil b/bin/cvsutil new file mode 100755 index 0000000..27a4ab5 --- /dev/null +++ b/bin/cvsutil @@ -0,0 +1,276 @@ +#! /usr/bin/perl + +use strict; +use warnings; + +use Getopt::Long; +use Cwd qw(chdir fastgetcwd); +use Errno qw(ENOENT); + +use constant ENTRIES =>"CVS/Entries"; +use constant CVSIGNORE=>".cvsignore"; +use constant ROOT =>"CVS/Root"; + +my($opt_files,$opt_ignores,$opt_workings,$opt_dirs); +my($opt_rm,$opt_print); +our($opt_root); # undefined=>no rooting, ""=>print roots or first phase for root checking, ne ""=>set roots +my($opt_verbose,$opt_fatal); +my($opt_force); # set roots without their checking +my(@opt_ignore); + +$Getopt::Long::ignorecase=0; +$Getopt::Long::bundling=1; +die if !GetOptions_shortfilter( + "f|files!" ,\$opt_files, + "i|ignores!" ,\$opt_ignores, + "w|workings!",\$opt_workings, + "d|dirs!" ,\$opt_dirs, + "r|rm!" ,\$opt_rm, + "p|print!" ,\$opt_print, + "root:s" ,\$opt_root, + "v|verbose!" ,\$opt_verbose, + "fatal!" ,\$opt_fatal, + "force!" ,\$opt_force, + "I|ignore=s" ,\@opt_ignore, + ); + +die "--root possible only with (optional and ignored) -d|--dirs" + if defined $opt_root && ($opt_files || $opt_ignores || $opt_workings || $opt_dirs || $opt_rm || $opt_print); +die "-d|--dirs forbidden with -r|--rm" + if $opt_dirs && $opt_rm; +die "Nothing to do (no -r|--rm, no -p|--print)" + if !$opt_rm && !$opt_print && !defined $opt_root; +die "Nothing to process (no -f|--files, no -i|--ignores, no -w|--workings, no -d|--dirs)" + if !defined $opt_root && (!$opt_files && !$opt_ignores && !$opt_workings && !$opt_dirs); + +my @all_ignore=("CVS"); +for (@opt_ignore) { + push @all_ignore,$_; + @all_ignore=() if $_ eq "!"; + } + +my($root_contents,@root_dirs); + +@ARGV=(".") if !@ARGV; +our(@dir_dirs)=@ARGV; +our(@dir_files,@dir_ignores,@dir_workings,@dir_victims); +our($dir_dirname)=""; +unless ((defined $opt_root && $opt_root ne "") && $opt_force) { + local($opt_root)=$opt_root; + $opt_root="" if defined $opt_root && $opt_root ne ""; + localdircore(); + } + +actionrootfinal() if defined $opt_root && $opt_root eq ""; +if (defined $opt_root && $opt_root ne "") { + die "Non-matching \"".ROOT."\" contents, use --force for override" if !@root_dirs && !$opt_force; + localdircore(); + } + +exit 0; + +sub mayfatal +{ +my($msg,%opts)=@_; + + my $errstr=$!; + $msg.=" in \"".fastgetcwd."\" (CVS \"$dir_dirname\")".($opts{"noerrno"} ? "" : ": $errstr"); + die $msg if $opt_fatal; + warn $msg; +} + +sub fordirs +{ +my($func,@dirs)=@_; + + my $origdir=fastgetcwd; + for (@dirs) { + if (!chdir $_) { + mayfatal "Unable to process directory \"$_\""; + next; + } + &$func($_); + chdir $origdir; + } +} + +sub localdir +{ +my($localdirname)=@_; + + verbose("localdir(\"$localdirname\") entry"); + + local(@dir_dirs,@dir_files,@dir_ignores,@dir_workings,@dir_victims); + local($dir_dirname)=$dir_dirname.$localdirname."/"; + + localreaddir() or return; + + localdircore(); + + verbose("localdir(\"$localdirname\") exit"); +} + +sub localdircore +{ + localvictims() if !defined $opt_root; + localaction(); + + fordirs \&localdir,@dir_dirs; +} + +sub localreaddir +{ + local *E; + if (!open E,ENTRIES) { + mayfatal "File \"".ENTRIES."\" cannot be opened"; + return 0; + } + while () { + chomp; + do { push @dir_dirs ,$1; next; } if m#^D/([^/]*)/#; + do { push @dir_files,$1; next; } if m#^/([^/]*)/# ; + next if /^D$/; + mayfatal "File ".ENTRIES." contains invalid line \"$_\"",("noerrno"=>1); + } + close E; + + return 1 if defined $opt_root; + + local *I; + if (open I,CVSIGNORE) { + while () { + while (/\S+/g) { + for (<$&>) { + push @dir_ignores,$_ if -e $_; + } + } + } + close I; + } + else { + mayfatal "File \"".CVSIGNORE."\" cannot be opened" if !$!{ENOENT}; + } + + local *D; + if (!opendir D,".") { + mayfatal "Cannot read directory \".\""; + return 0; + } + @dir_workings=readdir D; + closedir D; + my %delworkings=map { $_=>1; } @dir_workings; + for (@dir_dirs,@dir_files,@dir_ignores,@all_ignore,".","..") { + delete $delworkings{$_}; + } + @dir_workings=keys %delworkings; + return 1; +} + +sub localvictims +{ + push @dir_victims,@dir_files if $opt_files; + push @dir_victims,@dir_ignores if $opt_ignores; + push @dir_victims,@dir_workings if $opt_workings; + push @dir_victims,@dir_dirs if $opt_dirs; +} + +sub localactionprint +{ +my($filename)=@_; + + mayfatal "File \"$filename\" does not exist",("noerrno"=>1) if !-e $filename; + print "${dir_dirname}$filename\n"; +} + +sub localactionrm +{ +my($filename)=@_; + + if (!unlink $filename) { + mayfatal "File \"$_\" cannot be removed" if !$!{ENOENT}; + } +} + +sub localactionrootset +{ + local *R; + if (!open R,'>',ROOT) { + mayfatal "File \"".ROOT."\" cannot be written"; + return; + } + print R "$opt_root\n"; + close R; +} + +sub localactionrootprint +{ + local *R; + if (!open R,ROOT) { + mayfatal "File \"".ROOT."\" cannot be opened"; + return; + } + local $/=undef; + localactionrootprintcheck(); + close R; +} + +sub localactionrootprintcheck +{ +my($contents)=@_; + + if (!defined $root_contents) { + push @root_dirs,$dir_dirname; + $root_contents=$contents; + return; + } + if (@root_dirs && $root_contents eq $contents) { + push @root_dirs,$dir_dirname; + return; + } + if (@root_dirs) { + print map "$_: $root_contents",@root_dirs; + @root_dirs=(); + } + print "$dir_dirname: $contents"; +} + +sub actionrootfinal +{ + return if !@root_dirs; + print $root_contents; +} + +sub localaction +{ + if ("" ne $dir_dirname && defined $opt_root) { + localactionrootset() if defined $opt_root && "" ne $opt_root; + localactionrootprint() if defined $opt_root && "" eq $opt_root; + return; + } + for (@dir_victims) { + localactionprint $_ if $opt_print; + localactionrm $_ if $opt_rm; + } +} + +sub verbose +{ +my($msg)=@_; + + return if !$opt_verbose; + print fastgetcwd.": $msg\n"; +} + +sub GetOptions_shortfilter +{ + my @r; + while ($_=shift) { + if (/^(\w)\|/) { + my $ref=shift; + push @r,$1,$ref,$',$ref; + next; + } + push @r,$_; + } + return GetOptions @r; +}