Fix cleanup and diff.
[nethome.git] / bin / cvslinks
1 #! /usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use Getopt::Std;
7 use Cwd;
8
9 use constant FILENAME=>".cvslinks";
10 use constant ENTRIES=>"CVS/Entries";
11
12
13 our($opt_u,$opt_c,$opt_d,$opt_r,$opt_R,$opt_l,$opt_v);
14 getopts "ucdrRlv";
15
16 die "-u (update), -c (commit) or -d (delete) required"        if !$opt_u && !$opt_c && !$opt_d;
17 die "-r (recursive)/-R (recursive w/o CVS) and -l (local) are conflicting"
18                 if ($opt_r || $opt_R) && $opt_l;
19
20 $opt_r=1 if !$opt_r && !$opt_R && !$opt_l; # default
21
22 body();
23 exit 0;
24
25 sub body
26 {
27         do_u() if $opt_u;
28         do_c() if $opt_c;
29         do_d() if $opt_d;
30         do_r() if $opt_r;
31         do_R() if $opt_R;
32 }
33
34 sub verbose
35 {
36 my($msg)=@_;
37
38         return if !$opt_v;
39         print cwd().": $msg\n";
40 }
41
42 sub do_d
43 {
44         local *D;
45         opendir D,"." or die "Cannot open directory \".\": $!";
46         for (readdir D) {
47                 next if ! -l;
48                 verbose "Deleting local link $_";
49                 unlink;
50                 }
51         closedir D;
52 }
53
54 sub do_u
55 {
56         local *L;
57         open L,FILENAME or die "File ".FILENAME." cannot be opened: $!";
58         do_d();
59         verbose "Creating links from ".FILENAME;
60         my $cmt=0;
61         while (<L>) {
62                 chomp;
63                 my $cmt_old=$cmt;
64                 $cmt=!$cmt if /^#!/;
65                 next if $cmt || $cmt_old || /^$/; # comment or empty-file (->empty-dir) stub line
66                 /^(.+)\t(.+)$/ or warn "Unrecognized line: $_";
67                 verbose "Creating link $1";
68                 symlink $2,$1 or warn "symlink(\"$2\"->\"$1\"): $!";
69                 }
70         close L;
71 }
72
73 sub do_c
74 {
75         local(*L,*D);
76         opendir D,"." or die "Cannot open directory \".\": $!";
77         verbose "Storing links to ".FILENAME;
78         my $cmtblock="";
79         if (open L,FILENAME) {
80                 my $cmt=0;
81                 while (<L>) {
82                         my $cmt_old=$cmt;
83                         $cmt=!$cmt if /^#!/;
84                         next unless $cmt || $cmt_old; # comment
85                         $cmtblock.=$_;
86                         }
87                 close L;
88                 }
89         $cmtblock="\n" if !$cmtblock; # empty-file (->empty-dir) stub line
90         open L,">".FILENAME or die "File ".FILENAME." cannot be created: $!";
91         print L $cmtblock;
92         for (readdir D) {
93                 next if ! -l;
94                 my $target=readlink or die "Cannot read link $_: $!";
95                 verbose "Storing link $_";
96                 print L "$_\t$target\n";
97                 }
98         closedir D;
99         close L;
100 }
101
102 sub descent
103 {
104 my($dir)=@_;
105
106         if (!chdir $dir) {
107                 warn "Cannot chdir to $dir: $!";
108                 return;
109                 }
110         verbose "Descented to child directory";
111         body();
112         chdir ".." or die "Cannot return back to ..: $!";
113         verbose "Back in parent directory";
114 }
115
116 sub do_r
117 {
118         local *C;
119         if (!open C,ENTRIES) {
120                 warn "Cannot open file \"".ENTRIES."\": $!";
121                 return;
122                 }
123         while (<C>) {
124                 chomp;
125                 next if !m#^D/([^/]*)/#;
126                 descent($1);
127                 }
128         close C;
129 }
130
131 sub do_R
132 {
133         local *D;
134         opendir D,"." or die "Cannot open directory \".\": $!";
135         for (readdir D) {
136                 # Beware of symlinked-directories !
137                 next if -l || ! -d || $_ eq "." || $_ eq "..";
138                 descent($_);
139                 }
140         closedir D;
141 }