mocksetup: /unsafe+/hdd -> /quad
[nethome.git] / bin / cvsutil
index cd999a5..72c19d5 100755 (executable)
@@ -1,6 +1,14 @@
 #! /usr/bin/perl
 #
 #      $Id$
+#
+#      Recommended aliases:
+#              alias cvsfiles='cvsutil --files --print'
+#              alias cvsignores='cvsutil --ignores --print'
+#              alias cvsignoresall='cvsutil --ignores --workings --print'
+#              alias cvsignoresrm='cvsutil --ignores --rm'
+#              alias cvsignoresrmall='cvsutil --ignores --workings --rm'
+#              alias cvsignoresallrm='cvsutil --ignores --workings --rm'
 
 use strict;
 use warnings;
@@ -8,6 +16,22 @@ use warnings;
 use Getopt::Long;
 use Cwd qw(chdir fastgetcwd);
 use Errno qw(ENOENT);
+use Carp qw(confess cluck croak carp);
+BEGIN {
+       if (!eval q{ use File::Remove qw(remove); 1; }) {{
+               sub main::remove(@)
+               {
+                       my $r="";
+                       if ("SCALAR" eq ref $_[0]) {
+                               $r="-r" if ${$_[0]};
+                               shift;
+                               }
+                       my $cmd="rm -f $r ".join(" ",map({s/'/'\\''/g;"'$_'";} @_));
+                       my $err=system($cmd) and confess("$cmd: $cmd");
+                       return @_;
+               }
+               }}
+}
 
 use constant ENTRIES  =>"CVS/Entries";
 use constant CVSIGNORE=>".cvsignore";
@@ -77,8 +101,8 @@ my($msg,%opts)=@_;
 
        my $errstr=$!;
        $msg.=" in \"".fastgetcwd."\" (CVS \"$dir_dirname\")".($opts{"noerrno"} ? "" : ": $errstr");
-       die $msg if $opt_fatal;
-       warn $msg;
+       croak $msg if $opt_fatal;
+       carp $msg;
 }
 
 sub fordirs
@@ -120,6 +144,17 @@ sub localdircore
        fordirs \&localdir,@dir_dirs;
 }
 
+sub filterout
+{
+my($from,@what)=@_;
+
+       my %hash=map { $_=>1; } @$from;
+       for (@what) {
+               delete $hash{$_};
+               }
+       return keys %hash;
+}
+
 sub localreaddir
 {
        local *E;
@@ -129,9 +164,12 @@ sub localreaddir
                }
        while (<E>) {
                chomp;
+               next if /^D$/;
                do { push @dir_dirs ,$1; next; } if m#^D/([^/]*)/#;
+               next if m#^/[^/]*/-#;   # deleted file: /filename/-1.1/dummy timestamp//
+               # New file is a valid entry!
+               # next if m#^/[^/]*/0/#;        # new file: /filename/0/dummy timestamp//
                do { push @dir_files,$1; next; } if m#^/([^/]*)/# ;
-               next if /^D$/;
                mayfatal "File ".ENTRIES." contains invalid line \"$_\"",("noerrno"=>1);
                }
        close E;
@@ -148,6 +186,7 @@ sub localreaddir
                                }
                        }
                close I;
+               @dir_ignores=filterout \@dir_ignores,@dir_dirs,@dir_files;
                }
        else {
                mayfatal "File \"".CVSIGNORE."\" cannot be opened" if !$!{ENOENT};
@@ -158,13 +197,8 @@ sub localreaddir
                mayfatal "Cannot read directory \".\"";
                return 0;
                }
-       @dir_workings=readdir D;
+       @dir_workings=filterout [readdir D],@dir_dirs,@dir_files,@dir_ignores,@all_ignore,".","..";
        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;
 }
 
@@ -188,9 +222,14 @@ sub localactionrm
 {
 my($filename)=@_;
 
-       if (!unlink $filename) {
+       # &chmod follows the symlinks.
+       -l $filename or chmod 0700,$filename or do {
+               mayfatal "File \"$_\" cannot be chmod(2)ed" if !$!{ENOENT};
+               };
+       # '\1' for '-r':
+       remove \1,$filename or do {
                mayfatal "File \"$_\" cannot be removed" if !$!{ENOENT};
-               }
+               };
 }
 
 sub localactionrootset