#! /usr/bin/perl use strict; use warnings; use Getopt::Std; use Cwd; use constant FILENAME=>".cvslinks"; use constant ENTRIES=>"CVS/Entries"; our($opt_u,$opt_c,$opt_d,$opt_r,$opt_R,$opt_l,$opt_v); getopts "ucdrRlv"; die "-u (update), -c (commit) or -d (delete) required" if !$opt_u && !$opt_c && !$opt_d; die "-r (recursive)/-R (recursive w/o CVS) and -l (local) are conflicting" if ($opt_r || $opt_R) && $opt_l; $opt_r=1 if !$opt_r && !$opt_R && !$opt_l; # default body(); exit 0; sub body { do_u() if $opt_u; do_c() if $opt_c; do_d() if $opt_d; do_r() if $opt_r; do_R() if $opt_R; } sub verbose { my($msg)=@_; return if !$opt_v; print cwd().": $msg\n"; } sub do_d { local *D; opendir D,"." or die "Cannot open directory \".\": $!"; for (readdir D) { next if ! -l; verbose "Deleting local link $_"; unlink; } closedir D; } sub do_u { local *L; open L,FILENAME or die "File ".FILENAME." cannot be opened: $!"; do_d(); verbose "Creating links from ".FILENAME; my $cmt=0; while () { chomp; my $cmt_old=$cmt; $cmt=!$cmt if /^#!/; next if $cmt || $cmt_old || /^$/; # comment or empty-file (->empty-dir) stub line /^(.+)\t(.+)$/ or warn "Unrecognized line: $_"; verbose "Creating link $1"; symlink $2,$1 or warn "symlink(\"$2\"->\"$1\"): $!"; } close L; } sub do_c { local(*L,*D); opendir D,"." or die "Cannot open directory \".\": $!"; verbose "Storing links to ".FILENAME; my $cmtblock=""; if (open L,FILENAME) { my $cmt=0; while () { my $cmt_old=$cmt; $cmt=!$cmt if /^#!/; next unless $cmt || $cmt_old; # comment $cmtblock.=$_; } close L; } $cmtblock="\n" if !$cmtblock; # empty-file (->empty-dir) stub line open L,">".FILENAME or die "File ".FILENAME." cannot be created: $!"; print L $cmtblock; for (readdir D) { next if ! -l; my $target=readlink or die "Cannot read link $_: $!"; verbose "Storing link $_"; print L "$_\t$target\n"; } closedir D; close L; } sub descent { my($dir)=@_; if (!chdir $dir) { warn "Cannot chdir to $dir: $!"; return; } verbose "Descented to child directory"; body(); chdir ".." or die "Cannot return back to ..: $!"; verbose "Back in parent directory"; } sub do_r { local *C; if (!open C,ENTRIES) { warn "Cannot open file \"".ENTRIES."\": $!"; return; } while () { chomp; next if !m#^D/([^/]*)/#; descent($1); } close C; } sub do_R { local *D; opendir D,"." or die "Cannot open directory \".\": $!"; for (readdir D) { # Beware of symlinked-directories ! next if -l || ! -d || $_ eq "." || $_ eq ".."; descent($_); } closedir D; }