just comments and debugging
[rersyncrecent.git] / bin / rrr-fsck
blob9e1916145770a36c322593d8ad62ee815c59b05d
1 #!/usr/bin/perl -- -*- mode: cperl -*-
3 =head1 NAME
5 rrr-fsck -
7 =head1 SYNOPSIS
9 rrr-fsck [options] principalfile
11 =head1 OPTIONS
13 =over 8
15 =cut
17 my @opt = <<'=back' =~ /B<--(\S+)>/g;
19 =item B<--dry-run|n>
21 Does nothing, only prints what it would do.
23 =item B<--help|h>
25 Prints a brief message and exists.
27 =item B<--remoteroot=s>
29 If provided fsck will try to mirror missing files from this location.
30 For remote locations requiring authentication you may need to set the
31 environment variables USER and RSYNC_PASSWORD as well.
33 =item B<--verbose|v+>
35 More feedback.
37 =item B<--yes|y>
39 Consider all answers to asked questions to be I<yes>.
41 =back
43 =head1 DESCRIPTION
45 Compares disk contents with index contents and gathers files missing
46 on local disk and files missing in local index.
48 If remoteroot is given missing files are fetched from remote.
50 Files on the local disk that have no counterpart in the index are
51 considered obsolete and the user is asked for each file if the file
52 should be deleted. And if the user confirms it will be deleted.
54 =head1 BUGS
56 There is a race condition when the tree or the index is manipulated
57 while we are running. This implies that the result is only then 100%
58 correct when disk and index are not changed while we are running.
60 There should be an option to declare the files on disk authoritative
61 so that they are added to the index.
63 =cut
66 use strict;
67 use warnings;
69 use lib "/home/k/sources/rersyncrecent/lib";
71 use File::Basename qw(dirname);
72 use File::Find qw(find);
73 use ExtUtils::MakeMaker qw(prompt);
74 use File::Rsync::Mirror::Recent;
75 use File::Spec;
76 use Getopt::Long;
77 use List::Util qw(max);
78 use Pod::Usage qw(pod2usage);
80 our %Opt;
81 GetOptions(\%Opt,
82 @opt,
83 ) or pod2usage(1);
85 if ($Opt{help}) {
86 pod2usage(0);
89 if (@ARGV == 1) {
90 } else {
91 pod2usage(1);
94 my($principal) = @ARGV;
95 my $recc = File::Rsync::Mirror::Recent->new
97 local => $principal,
98 localroot => dirname $principal,
100 for my $passthrough (qw(remoteroot verbose)) {
101 if (my $opt = $Opt{$passthrough}) {
102 $recc->$passthrough($opt);
105 my $root = $recc->localroot;
106 die "Alert: Root not defined, giving up" unless defined $root;
108 my %diskfiles;
109 find({
110 wanted => sub {
111 my @stat = lstat $_;
112 return if -l _;
113 return unless -f _;
114 $diskfiles{$File::Find::name} = $stat[9];
116 no_chdir => 1,
118 $root
121 my $indexfiles = $recc->news;
122 my %seen;
123 my %indexfiles = map {("$root/$_->{path}"=>$_->{epoch})} grep { !$seen{$_->{path}}++ && $_->{type} eq "new" } @$indexfiles;
124 for my $rf (@{$recc->recentfiles}) {
125 my $rfrfile = $rf->rfile;
126 my @stat = stat $rfrfile or die "Could not stat '$rfrfile': $!";
127 $indexfiles{$rfrfile} = $stat[9];
129 my $sprintfd = length(max scalar @$indexfiles, scalar keys %diskfiles);
130 warn sprintf(
131 "diskfiles: %*d\n".
132 "indexfiles: %*d\n",
133 $sprintfd, scalar keys %diskfiles,
134 $sprintfd, scalar keys %indexfiles,
136 my @diskmisses = sort { $indexfiles{$b} <=> $indexfiles{$a} } grep { ! exists $diskfiles{$_} } keys %indexfiles;
137 my @indexmisses = sort { $diskfiles{$a} <=> $diskfiles{$b} } grep { ! exists $indexfiles{$_} } keys %diskfiles;
138 warn sprintf(
139 "not on disk: %*d\n".
140 "not in index: %*d\n",
141 $sprintfd, scalar @diskmisses,
142 $sprintfd, scalar @indexmisses,
144 $DB::single++;
145 for my $dm (@diskmisses) {
146 if ($Opt{"dry-run"}) {
147 warn "Would fetch $dm\n";
148 } elsif ($Opt{remoteroot}) {
149 my $relative = substr $dm, 1 + length $root;
150 $recc->principal_recentfile->get_remotefile($relative);
151 } else {
152 warn "Missing on disk: $dm\n";
155 for my $im (@indexmisses) {
156 if ($Opt{"dry-run"}) {
157 warn "Would remove $im\n";
158 } else {
159 my $ans;
160 if ($Opt{yes}) {
161 warn "Going to unlink '$im'\n";
162 $ans = "y";
163 } else {
164 $ans = prompt "Unlink '$im'?", "y";
166 if ($ans =~ /^y/i) {
167 unlink $im or die "Could not unlink '$im': $!";
171 __END__
174 # Local Variables:
175 # mode: cperl
176 # coding: utf-8
177 # cperl-indent-level: 4
178 # End: