--- /usr/bin/git-cvsexportcommit.orig 2008-10-02 01:16:23.000000000 +0100 +++ /home/nick/bin/git-cvsexportcommit 2008-10-02 01:17:13.000000000 +0100 @@ -7,6 +7,18 @@ use Data::Dumper; use File::Basename qw(basename dirname); +# read in the first line of a file +sub first_line { + my ($file) = @_; + my $line = ''; + + return unless open my $fh, "<$file"; + chomp ($line = <$fh>); + close $fh; + return $line; +} + + our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w); getopts('uhPpvcfam:d:w:'); @@ -193,21 +205,63 @@ push @canstatusfiles, $f; } + +# Get the root path the CVS working directory thinks its respository is at. +# (We're in the working dir). Note we assume the repository agrees on this +# throughout, which isn't necessarily true, but if not it's just bonkers. +my $root_path = first_line("CVS/Root") || ''; + +# likewise the module +my $module_path = first_line("CVS/Repository") || ''; + +# try and strip off all but the path from the root - we assume the path has no colons +$root_path =~ s/^.*://; +$root_path =~ s{/*$}{/$module_path}; # concatenate the paths + + +# lightly tested - seems ok with unknown files, and CVS repos using non-symbolic modules + +# get the files' statuses my %cvsstat; if (@canstatusfiles) { if ($opt_u) { my @updated = xargs_safe_pipe_capture([@cvs, 'update'], @canstatusfiles); print @updated; } + my @cvsoutput; @cvsoutput = xargs_safe_pipe_capture([@cvs, 'status'], @canstatusfiles); - my $matchcount = 0; - foreach my $l (@cvsoutput) { - chomp $l; - if ( $l =~ /^File:/ and $l =~ /Status: (.*)$/ ) { - $cvsstat{$canstatusfiles[$matchcount]} = $1; - $matchcount++; + + chomp @cvsoutput; + my ($status, $path, $repo_path); + my %expected_paths = map { $_ => 1 } @canstatusfiles; + + # Use $_ implcitly here to simplify the regex expressions. + # Note that foreach saves and restores $_ for us + foreach (@cvsoutput) { + # Grab the information when we see it + $status = $1, next if /^File:.*Status:\s*(.*)/i; + $path = $1, next if /^cvs server: nothing known about (.*)/i; + + next unless m{Repository revision:[\s\d.]*(.*)}i; + $repo_path = $1; + + # At this point we can try and reconstruct the file path + if (!$path && $repo_path !~ /No entry for/i) { + $repo_path =~ s{Attic/?}{}i; + $repo_path =~ s{,v\s*$}{}i; + $repo_path =~ s{^$root_path/}{}; + + $path = $repo_path; } + + warn "Failed to get a path from the CVS status entry containing:\n$_" + unless $path; + warn "Found a path in the CVS output we didn't ask for: '$path'" + unless exists $expected_paths{$path}; + + $cvsstat{$path} = $status; + $path = $repo_path = $status = undef; } } @@ -331,7 +385,8 @@ @output = (<$child>); close $child or die join(' ',@_).": $! $?"; } else { - exec(@_) or die "$! $?"; # exec() can fail the executable can't be found + open STDERR, ">&STDOUT" or warn "child can't dup STDERR";; + exec(@_) or die "$! $?"; # exec() can fail the executable can't be found } return wantarray ? @output : join('',@output); }