git-svn info: implement info command
Implement "git-svn info" for files and directories based on the "svn info" command. Note that the -r/--revision argument is not supported yet. Added 18 tests in t/t9119-git-svn-info.sh. [ew: small fix to work without arguments on all working directories] Signed-off-by: David D. Kilzer <ddkilzer@kilzer.net> Acked-by: Eric Wong <normalperson@yhbt.net>
This commit is contained in:

committed by
Eric Wong

parent
b2b3ada7fc
commit
e6fefa926d
133
git-svn.perl
133
git-svn.perl
@ -178,6 +178,10 @@ my %cmd = (
|
||||
'file|F=s' => \$_file,
|
||||
'revision|r=s' => \$_revision,
|
||||
%cmt_opts } ],
|
||||
'info' => [ \&cmd_info,
|
||||
"Show info about the latest SVN revision
|
||||
on the current branch",
|
||||
{ } ],
|
||||
);
|
||||
|
||||
my $cmd;
|
||||
@ -586,12 +590,18 @@ sub cmd_create_ignore {
|
||||
|
||||
sub canonicalize_path {
|
||||
my ($path) = @_;
|
||||
my $dot_slash_added = 0;
|
||||
if (substr($path, 0, 1) ne "/") {
|
||||
$path = "./" . $path;
|
||||
$dot_slash_added = 1;
|
||||
}
|
||||
# File::Spec->canonpath doesn't collapse x/../y into y (for a
|
||||
# good reason), so let's do this manually.
|
||||
$path =~ s#/+#/#g;
|
||||
$path =~ s#/\.(?:/|$)#/#g;
|
||||
$path =~ s#/[^/]+/\.\.##g;
|
||||
$path =~ s#/$##g;
|
||||
$path =~ s#^\./## if $dot_slash_added;
|
||||
return $path;
|
||||
}
|
||||
|
||||
@ -743,6 +753,104 @@ sub cmd_commit_diff {
|
||||
}
|
||||
}
|
||||
|
||||
sub cmd_info {
|
||||
my $path = canonicalize_path(shift or ".");
|
||||
unless (scalar(@_) == 0) {
|
||||
die "Too many arguments specified\n";
|
||||
}
|
||||
|
||||
my ($file_type, $diff_status) = find_file_type_and_diff_status($path);
|
||||
|
||||
if (!$file_type && !$diff_status) {
|
||||
print STDERR "$path: (Not a versioned resource)\n\n";
|
||||
return;
|
||||
}
|
||||
|
||||
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
|
||||
unless ($gs) {
|
||||
die "Unable to determine upstream SVN information from ",
|
||||
"working tree history\n";
|
||||
}
|
||||
my $full_url = $url . ($path eq "." ? "" : "/$path");
|
||||
|
||||
my $result = "Path: $path\n";
|
||||
$result .= "Name: " . basename($path) . "\n" if $file_type ne "dir";
|
||||
$result .= "URL: " . $full_url . "\n";
|
||||
|
||||
my $repos_root = $gs->ra->{repos_root};
|
||||
Git::SVN::remove_username($repos_root);
|
||||
$result .= "Repository Root: $repos_root\n";
|
||||
$result .= "Repository UUID: $uuid\n" unless $diff_status eq "A";
|
||||
$result .= "Revision: " . ($diff_status eq "A" ? 0 : $rev) . "\n";
|
||||
|
||||
$result .= "Node Kind: " .
|
||||
($file_type eq "dir" ? "directory" : "file") . "\n";
|
||||
|
||||
my $schedule = $diff_status eq "A"
|
||||
? "add"
|
||||
: ($diff_status eq "D" ? "delete" : "normal");
|
||||
$result .= "Schedule: $schedule\n";
|
||||
|
||||
if ($diff_status eq "A") {
|
||||
print $result, "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
my ($lc_author, $lc_rev, $lc_date_utc);
|
||||
my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $path);
|
||||
my $log = command_output_pipe(@args);
|
||||
my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
|
||||
while (<$log>) {
|
||||
if (/^${esc_color}author (.+) <[^>]+> (\d+) ([\-\+]?\d+)$/o) {
|
||||
$lc_author = $1;
|
||||
$lc_date_utc = Git::SVN::Log::parse_git_date($2, $3);
|
||||
} elsif (/^${esc_color} (git-svn-id:.+)$/o) {
|
||||
(undef, $lc_rev, undef) = ::extract_metadata($1);
|
||||
}
|
||||
}
|
||||
close $log;
|
||||
|
||||
Git::SVN::Log::set_local_timezone();
|
||||
|
||||
$result .= "Last Changed Author: $lc_author\n";
|
||||
$result .= "Last Changed Rev: $lc_rev\n";
|
||||
$result .= "Last Changed Date: " .
|
||||
Git::SVN::Log::format_svn_date($lc_date_utc) . "\n";
|
||||
|
||||
if ($file_type ne "dir") {
|
||||
my $text_last_updated_date =
|
||||
($diff_status eq "D" ? $lc_date_utc : (stat $path)[9]);
|
||||
$result .=
|
||||
"Text Last Updated: " .
|
||||
Git::SVN::Log::format_svn_date($text_last_updated_date) .
|
||||
"\n";
|
||||
my $checksum;
|
||||
if ($diff_status eq "D") {
|
||||
my ($fh, $ctx) =
|
||||
command_output_pipe(qw(cat-file blob), "HEAD:$path");
|
||||
if ($file_type eq "link") {
|
||||
my $file_name = <$fh>;
|
||||
$checksum = Git::SVN::Util::md5sum("link $file_name");
|
||||
} else {
|
||||
$checksum = Git::SVN::Util::md5sum($fh);
|
||||
}
|
||||
command_close_pipe($fh, $ctx);
|
||||
} elsif ($file_type eq "link") {
|
||||
my $file_name =
|
||||
command(qw(cat-file blob), "HEAD:$path");
|
||||
$checksum =
|
||||
Git::SVN::Util::md5sum("link " . $file_name);
|
||||
} else {
|
||||
open FILE, "<", $path or die $!;
|
||||
$checksum = Git::SVN::Util::md5sum(\*FILE);
|
||||
close FILE or die $!;
|
||||
}
|
||||
$result .= "Checksum: " . $checksum . "\n";
|
||||
}
|
||||
|
||||
print $result, "\n";
|
||||
}
|
||||
|
||||
########################### utility functions #########################
|
||||
|
||||
sub rebase_cmd {
|
||||
@ -1050,6 +1158,31 @@ sub linearize_history {
|
||||
(\@linear_refs, \%parents);
|
||||
}
|
||||
|
||||
sub find_file_type_and_diff_status {
|
||||
my ($path) = @_;
|
||||
return ('dir', '') if $path eq '.';
|
||||
|
||||
my $diff_output =
|
||||
command_oneline(qw(diff --cached --name-status --), $path) || "";
|
||||
my $diff_status = (split(' ', $diff_output))[0] || "";
|
||||
|
||||
my $ls_tree = command_oneline(qw(ls-tree HEAD), $path) || "";
|
||||
|
||||
return (undef, undef) if !$diff_status && !$ls_tree;
|
||||
|
||||
if ($diff_status eq "A") {
|
||||
return ("link", $diff_status) if -l $path;
|
||||
return ("dir", $diff_status) if -d $path;
|
||||
return ("file", $diff_status);
|
||||
}
|
||||
|
||||
my $mode = (split(' ', $ls_tree))[0] || "";
|
||||
|
||||
return ("link", $diff_status) if $mode eq "120000";
|
||||
return ("dir", $diff_status) if $mode eq "040000";
|
||||
return ("file", $diff_status);
|
||||
}
|
||||
|
||||
package Git::SVN::Util;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
Reference in New Issue
Block a user