{"thread":{"id":"10965","subject":"[PATCH 3/3 v3] git-svn: info --url [path]","startedAt":"2007-11-21T19:57:16Z","lastAt":"2007-11-22T04:17:53Z","messageCount":11,"participants":["David D. Kilzer","Eric Wong","Adam Roben"],"isPatch":true,"patchVersion":3,"patchTotal":3},"messages":[{"id":"60560","messageId":"1195675039-26746-1-git-send-email-ddkilzer@kilzer.net","threadId":"10965","inReplyTo":null,"subject":"[PATCH 0/3 v3] Implement git-svn info","fromName":"David D. Kilzer","fromEmail":"ddkilzer@kilzer.net","sentAt":"2007-11-21T19:57:16Z","receivedAt":"2007-11-21T19:57:16Z","isPatch":true,"sender":{"key":"ddkilzer@kilzer.net","avatar":"https://avatars.githubusercontent.com/u/263571?v=4"},"body":"Changes since the last patch series I posted (last night):\n\n- Patch 1/3: No changes.\n- Patch 2/3: Only changes to test code.\n  - Renamed t/t9117-git-svn-info.sh to t/t9119-git-svn-info.sh.\n  - Removed static expected.* files and reinstated dynamic generation.\n  - Replaced \"touch -c -r\" with ptouch (portable/perl touch) function.\n    (Should this go in t/lib-git-svn.sh?)\n  - Use sed(1) inline to work around minor \"svn info\" vs. \"git svn info\"\n    difference.\n  - Minor test name and expected.*/actual.* file name changes.\n  - Updated comments.\n- Patch 3/3: Added 17 more tests (mirroring the existing 18 tests from\n  Patch 2/3).\n\n\"David D. Kilzer\" <ddkilzer@kilzer.net> wrote:\n> \"David D. Kilzer\" <ddkilzer@kilzer.net> wrote:\n> > Eric Wong <normalperson@yhbt.net> wrote:\n> > > Can we expect the output of \"svn info\" to not change between\n> > > versions?  I know \"svn status\" has changed between versions of\n> > > svn.  I'd prefer if we keep the expected.* files hard-coded\n> > > in a test directory and compare those instead.  Maybe use sed\n> > > to substitute placeholders for timestamps..\n> > Done.\n> Grrr.  I remember the reason I didn't do this in the first place.\n> In Patch 2/3, there are now hard-coded directory paths and my\n> username in the static expected-* files.\n\nActually, using \"svn info\" to dynamically generate the results means\nthat the tests will break when \"svn info\" does change, which is a good\nthing.  In other words, I think we want to know when that happens so\nthat we can make a decision about whether to support the change or not.\n\nDave\n"},{"id":"60561","messageId":"1195675039-26746-2-git-send-email-ddkilzer@kilzer.net","threadId":"10965","inReplyTo":"1195675039-26746-1-git-send-email-ddkilzer@kilzer.net","subject":"[PATCH 1/3 v3] git-svn: extract reusable code into utility functions","fromName":"David D. Kilzer","fromEmail":"ddkilzer@kilzer.net","sentAt":"2007-11-21T19:57:17Z","receivedAt":"2007-11-21T19:57:17Z","isPatch":true,"sender":{"key":"ddkilzer@kilzer.net","avatar":"https://avatars.githubusercontent.com/u/263571?v=4"},"body":"Extacted canonicalize_path() in the main package.\n\nCreated new Git::SVN::Util package with an md5sum() function.  A\nnew package was created so that Digest::MD5 did not have to be\nloaded in the main package.  Replaced code in the SVN::Git::Editor\nand SVN::Git::Fetcher packages with calls to md5sum().\n\nExtracted the format_svn_date(), parse_git_date() and\nset_local_timezone() functions within the Git::SVN::Log package.\n\nSigned-off-by: David D. Kilzer <ddkilzer@kilzer.net>\n---\n git-svn.perl |   96 ++++++++++++++++++++++++++++++++++++++-------------------\n 1 files changed, 64 insertions(+), 32 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 5b1deea..98c980f 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -48,7 +48,8 @@ BEGIN {\n \tforeach (qw/command command_oneline command_noisy command_output_pipe\n \t            command_input_pipe command_close_pipe/) {\n \t\tfor my $package ( qw(SVN::Git::Editor SVN::Git::Fetcher\n-\t\t\tGit::SVN::Migration Git::SVN::Log Git::SVN),\n+\t\t\tGit::SVN::Migration Git::SVN::Log Git::SVN\n+\t\t\tGit::SVN::Util),\n \t\t\t__PACKAGE__) {\n \t\t\t*{\"${package}::$_\"} = \\&{\"Git::$_\"};\n \t\t}\n@@ -583,6 +584,17 @@ sub cmd_create_ignore {\n \t});\n }\n \n+sub canonicalize_path {\n+\tmy ($path) = @_;\n+\t# File::Spec->canonpath doesn't collapse x/../y into y (for a\n+\t# good reason), so let's do this manually.\n+\t$path =~ s#/+#/#g;\n+\t$path =~ s#/\\.(?:/|$)#/#g;\n+\t$path =~ s#/[^/]+/\\.\\.##g;\n+\t$path =~ s#/$##g;\n+\treturn $path;\n+}\n+\n # get_svnprops(PATH)\n # ------------------\n # Helper for cmd_propget and cmd_proplist below.\n@@ -600,12 +612,7 @@ sub get_svnprops {\n \n \t# canonicalize the path (otherwise libsvn will abort or fail to\n \t# find the file)\n-\t# File::Spec->canonpath doesn't collapse x/../y into y (for a\n-\t# good reason), so let's do this manually.\n-\t$path =~ s#/+#/#g;\n-\t$path =~ s#/\\.(?:/|$)#/#g;\n-\t$path =~ s#/[^/]+/\\.\\.##g;\n-\t$path =~ s#/$##g;\n+\t$path = canonicalize_path($path);\n \n \tmy $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);\n \tmy $props;\n@@ -1043,6 +1050,27 @@ sub linearize_history {\n \t(\\@linear_refs, \\%parents);\n }\n \n+package Git::SVN::Util;\n+use strict;\n+use warnings;\n+use Digest::MD5;\n+\n+sub md5sum {\n+\tmy $arg = shift;\n+\tmy $ref = ref $arg;\n+\tmy $md5 = Digest::MD5->new();\n+        if ($ref eq 'GLOB' || $ref eq 'IO::File') {\n+\t\t$md5->addfile($arg) or croak $!;\n+\t} elsif ($ref eq 'SCALAR') {\n+\t\t$md5->add($$arg) or croak $!;\n+\t} elsif (!$ref) {\n+\t\t$md5->add($arg) or croak $!;\n+\t} else {\n+\t\t::fatal \"Can't provide MD5 hash for unknown ref type: '\", $ref, \"'\";\n+\t}\n+\treturn $md5->hexdigest();\n+}\n+\n package Git::SVN;\n use strict;\n use warnings;\n@@ -2610,7 +2638,6 @@ use strict;\n use warnings;\n use Carp qw/croak/;\n use IO::File qw//;\n-use Digest::MD5;\n \n # file baton members: path, mode_a, mode_b, pool, fh, blob, base\n sub new {\n@@ -2762,9 +2789,7 @@ sub apply_textdelta {\n \n \t\tif (defined $exp) {\n \t\t\tseek $base, 0, 0 or croak $!;\n-\t\t\tmy $md5 = Digest::MD5->new;\n-\t\t\t$md5->addfile($base);\n-\t\t\tmy $got = $md5->hexdigest;\n+\t\t\tmy $got = Git::SVN::Util::md5sum($base);\n \t\t\tdie \"Checksum mismatch: $fb->{path} $fb->{blob}\\n\",\n \t\t\t    \"expected: $exp\\n\",\n \t\t\t    \"     got: $got\\n\" if ($got ne $exp);\n@@ -2783,9 +2808,7 @@ sub close_file {\n \tif (my $fh = $fb->{fh}) {\n \t\tif (defined $exp) {\n \t\t\tseek($fh, 0, 0) or croak $!;\n-\t\t\tmy $md5 = Digest::MD5->new;\n-\t\t\t$md5->addfile($fh);\n-\t\t\tmy $got = $md5->hexdigest;\n+\t\t\tmy $got = Git::SVN::Util::md5sum($fh);\n \t\t\tif ($got ne $exp) {\n \t\t\t\tdie \"Checksum mismatch: $path\\n\",\n \t\t\t\t    \"expected: $exp\\n    got: $got\\n\";\n@@ -2837,7 +2860,6 @@ use strict;\n use warnings;\n use Carp qw/croak/;\n use IO::File;\n-use Digest::MD5;\n \n sub new {\n \tmy ($class, $opts) = @_;\n@@ -3141,11 +3163,9 @@ sub chg_file {\n \t$fh->flush == 0 or croak $!;\n \tseek $fh, 0, 0 or croak $!;\n \n-\tmy $md5 = Digest::MD5->new;\n-\t$md5->addfile($fh) or croak $!;\n+\tmy $exp = Git::SVN::Util::md5sum($fh);\n \tseek $fh, 0, 0 or croak $!;\n \n-\tmy $exp = $md5->hexdigest;\n \tmy $pool = SVN::Pool->new;\n \tmy $atd = $self->apply_textdelta($fbat, undef, $pool);\n \tmy $got = SVN::TxDelta::send_stream($fh, @$atd, $pool);\n@@ -3859,6 +3879,29 @@ sub run_pager {\n \texec $pager or ::fatal \"Can't run pager: $! ($pager)\";\n }\n \n+sub format_svn_date {\n+\treturn strftime(\"%Y-%m-%d %H:%M:%S %z (%a, %d %b %Y)\", localtime(shift));\n+}\n+\n+sub parse_git_date {\n+\tmy ($t, $tz) = @_;\n+\t# Date::Parse isn't in the standard Perl distro :(\n+\tif ($tz =~ s/^\\+//) {\n+\t\t$t += tz_to_s_offset($tz);\n+\t} elsif ($tz =~ s/^\\-//) {\n+\t\t$t -= tz_to_s_offset($tz);\n+\t}\n+\treturn $t;\n+}\n+\n+sub set_local_timezone {\n+\tif (defined $TZ) {\n+\t\t$ENV{TZ} = $TZ;\n+\t} else {\n+\t\tdelete $ENV{TZ};\n+\t}\n+}\n+\n sub tz_to_s_offset {\n \tmy ($tz) = @_;\n \t$tz =~ s/(\\d\\d)$//;\n@@ -3879,13 +3922,7 @@ sub get_author_info {\n \t$dest->{t} = $t;\n \t$dest->{tz} = $tz;\n \t$dest->{a} = $au;\n-\t# Date::Parse isn't in the standard Perl distro :(\n-\tif ($tz =~ s/^\\+//) {\n-\t\t$t += tz_to_s_offset($tz);\n-\t} elsif ($tz =~ s/^\\-//) {\n-\t\t$t -= tz_to_s_offset($tz);\n-\t}\n-\t$dest->{t_utc} = $t;\n+\t$dest->{t_utc} = parse_git_date($t, $tz);\n }\n \n sub process_commit {\n@@ -3939,8 +3976,7 @@ sub show_commit_normal {\n \tmy ($c) = @_;\n \tprint commit_log_separator, \"r$c->{r} | \";\n \tprint \"$c->{c} | \" if $show_commit;\n-\tprint \"$c->{a} | \", strftime(\"%Y-%m-%d %H:%M:%S %z (%a, %d %b %Y)\",\n-\t\t\t\t localtime($c->{t_utc})), ' | ';\n+\tprint \"$c->{a} | \", format_svn_date($c->{t_utc}), ' | ';\n \tmy $nr_line = 0;\n \n \tif (my $l = $c->{l}) {\n@@ -3980,11 +4016,7 @@ sub cmd_show_log {\n \tmy (@args) = @_;\n \tmy ($r_min, $r_max);\n \tmy $r_last = -1; # prevent dupes\n-\tif (defined $TZ) {\n-\t\t$ENV{TZ} = $TZ;\n-\t} else {\n-\t\tdelete $ENV{TZ};\n-\t}\n+\tset_local_timezone();\n \tif (defined $::_revision) {\n \t\tif ($::_revision =~ /^(\\d+):(\\d+)$/) {\n \t\t\t($r_min, $r_max) = ($1, $2);\n-- \n1.5.3.4\n"},{"id":"60559","messageId":"1195675039-26746-3-git-send-email-ddkilzer@kilzer.net","threadId":"10965","inReplyTo":"1195675039-26746-2-git-send-email-ddkilzer@kilzer.net","subject":"[PATCH 2/3 v3] git-svn info: implement info command","fromName":"David D. Kilzer","fromEmail":"ddkilzer@kilzer.net","sentAt":"2007-11-21T19:57:18Z","receivedAt":"2007-11-21T19:57:18Z","isPatch":true,"sender":{"key":"ddkilzer@kilzer.net","avatar":"https://avatars.githubusercontent.com/u/263571?v=4"},"body":"Implement \"git-svn info\" for files and directories based on the\n\"svn info\" command.  Note that the -r/--revision argument is not\nsupported yet.\n\nAdded 18 tests in t/t9119-git-svn-info.sh.\n\nSigned-off-by: David D. Kilzer <ddkilzer@kilzer.net>\n---\n Documentation/git-svn.txt |    5 +\n git-svn.perl              |  132 ++++++++++++++++++++++\n t/t9119-git-svn-info.sh   |  274 +++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 411 insertions(+), 0 deletions(-)\n create mode 100644 t/t9119-git-svn-info.sh\n\ndiff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt\nindex 488e4b1..c3fc878 100644\n--- a/Documentation/git-svn.txt\n+++ b/Documentation/git-svn.txt\n@@ -193,6 +193,11 @@ Any other arguments are passed directly to `git log'\n \trepository (that has been init-ed with git-svn).\n \tThe -r<revision> option is required for this.\n \n+'info'::\n+\tShows information about a file or directory similar to what\n+\t`svn info' provides.  Does not currently support a -r/--revision\n+\targument.\n+\n --\n \n OPTIONS\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 98c980f..be9290c 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -178,6 +178,10 @@ my %cmd = (\n \t\t\t  'file|F=s' => \\$_file,\n \t\t\t  'revision|r=s' => \\$_revision,\n \t\t\t%cmt_opts } ],\n+\t'info' => [ \\&cmd_info,\n+\t\t    \"Show info about the latest SVN revision\n+\t\t     on the current branch\",\n+\t\t    { } ],\n );\n \n my $cmd;\n@@ -586,12 +590,18 @@ sub cmd_create_ignore {\n \n sub canonicalize_path {\n \tmy ($path) = @_;\n+\tmy $dot_slash_added = 0;\n+\tif (substr($path, 0, 1) ne \"/\") {\n+\t\t$path = \"./\" . $path;\n+\t\t$dot_slash_added = 1;\n+\t}\n \t# File::Spec->canonpath doesn't collapse x/../y into y (for a\n \t# good reason), so let's do this manually.\n \t$path =~ s#/+#/#g;\n \t$path =~ s#/\\.(?:/|$)#/#g;\n \t$path =~ s#/[^/]+/\\.\\.##g;\n \t$path =~ s#/$##g;\n+\t$path =~ s#^\\./## if $dot_slash_added;\n \treturn $path;\n }\n \n@@ -743,6 +753,104 @@ sub cmd_commit_diff {\n \t}\n }\n \n+sub cmd_info {\n+\tmy $path = canonicalize_path(shift or \".\");\n+\tunless (scalar(@_) == 0) {\n+\t\tdie \"Too many arguments specified\\n\";\n+\t}\n+\n+\tmy ($file_type, $diff_status) = find_file_type_and_diff_status($path);\n+\n+\tif (!$file_type && !$diff_status) {\n+\t\tprint STDERR \"$path:  (Not a versioned resource)\\n\\n\";\n+\t\treturn;\n+\t}\n+\n+\tmy ($url, $rev, $uuid, $gs) = working_head_info('HEAD');\n+\tunless ($gs) {\n+\t\tdie \"Unable to determine upstream SVN information from \",\n+\t\t    \"working tree history\\n\";\n+\t}\n+\tmy $full_url = $url . ($path eq \".\" ? \"\" : \"/$path\");\n+\n+\tmy $result = \"Path: $path\\n\";\n+\t$result .= \"Name: \" . basename($path) . \"\\n\" if $file_type ne \"dir\";\n+\t$result .= \"URL: \" . $full_url . \"\\n\";\n+\n+\tmy $repos_root = $gs->ra->{repos_root};\n+\tGit::SVN::remove_username($repos_root);\n+\t$result .= \"Repository Root: $repos_root\\n\";\n+\t$result .= \"Repository UUID: $uuid\\n\" unless $diff_status eq \"A\";\n+\t$result .= \"Revision: \" . ($diff_status eq \"A\" ? 0 : $rev) . \"\\n\";\n+\n+\t$result .= \"Node Kind: \" .\n+\t\t   ($file_type eq \"dir\" ? \"directory\" : \"file\") . \"\\n\";\n+\n+\tmy $schedule = $diff_status eq \"A\"\n+\t\t       ? \"add\"\n+\t\t       : ($diff_status eq \"D\" ? \"delete\" : \"normal\");\n+\t$result .= \"Schedule: $schedule\\n\";\n+\n+\tif ($diff_status eq \"A\") {\n+\t\tprint $result, \"\\n\";\n+\t\treturn;\n+\t}\n+\n+\tmy ($lc_author, $lc_rev, $lc_date_utc);\n+\tmy @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, \"--\", $path);\n+\tmy $log = command_output_pipe(@args);\n+\tmy $esc_color = qr/(?:\\033\\[(?:(?:\\d+;)*\\d*)?m)*/;\n+\twhile (<$log>) {\n+\t\tif (/^${esc_color}author (.+) <[^>]+> (\\d+) ([\\-\\+]?\\d+)$/o) {\n+\t\t\t$lc_author = $1;\n+\t\t\t$lc_date_utc = Git::SVN::Log::parse_git_date($2, $3);\n+\t\t} elsif (/^${esc_color}    (git-svn-id:.+)$/o) {\n+\t\t\t(undef, $lc_rev, undef) = ::extract_metadata($1);\n+\t\t}\n+\t}\n+\tclose $log;\n+\n+\tGit::SVN::Log::set_local_timezone();\n+\n+\t$result .= \"Last Changed Author: $lc_author\\n\";\n+\t$result .= \"Last Changed Rev: $lc_rev\\n\";\n+\t$result .= \"Last Changed Date: \" .\n+\t\t   Git::SVN::Log::format_svn_date($lc_date_utc) . \"\\n\";\n+\n+\tif ($file_type ne \"dir\") {\n+\t\tmy $text_last_updated_date =\n+\t\t    ($diff_status eq \"D\" ? $lc_date_utc : (stat $path)[9]);\n+\t\t$result .=\n+\t\t    \"Text Last Updated: \" .\n+\t\t    Git::SVN::Log::format_svn_date($text_last_updated_date) .\n+\t\t    \"\\n\";\n+\t\tmy $checksum;\n+\t\tif ($diff_status eq \"D\") {\n+\t\t\tmy ($fh, $ctx) =\n+\t\t\t    command_output_pipe(qw(cat-file blob), \"HEAD:$path\");\n+\t\t\tif ($file_type eq \"link\") {\n+\t\t\t\tmy $file_name = <$fh>;\n+\t\t\t\t$checksum = Git::SVN::Util::md5sum(\"link $file_name\");\n+\t\t\t} else {\n+\t\t\t\t$checksum = Git::SVN::Util::md5sum($fh);\n+\t\t\t}\n+\t\t\tcommand_close_pipe($fh, $ctx);\n+\t\t} elsif ($file_type eq \"link\") {\n+\t\t\tmy $file_name =\n+\t\t\t    command(qw(cat-file blob), \"HEAD:$path\");\n+\t\t\t$checksum =\n+\t\t\t    Git::SVN::Util::md5sum(\"link \" . $file_name);\n+\t\t} else {\n+\t\t\topen FILE, \"<\", $path or die $!;\n+\t\t\t$checksum = Git::SVN::Util::md5sum(\\*FILE);\n+\t\t\tclose FILE or die $!;\n+\t\t}\n+\t\t$result .= \"Checksum: \" . $checksum . \"\\n\";\n+\t}\n+\n+\tprint $result, \"\\n\";\n+}\n+\n ########################### utility functions #########################\n \n sub rebase_cmd {\n@@ -1050,6 +1158,30 @@ sub linearize_history {\n \t(\\@linear_refs, \\%parents);\n }\n \n+sub find_file_type_and_diff_status {\n+\tmy ($path) = @_;\n+\n+\tmy $diff_output =\n+\t    command_oneline(qw(diff --cached --name-status --), $path) || \"\";\n+\tmy $diff_status = (split(' ', $diff_output))[0] || \"\";\n+\n+\tmy $ls_tree = command_oneline(qw(ls-tree HEAD), $path) || \"\";\n+\n+\treturn (undef, undef) if !$diff_status && !$ls_tree;\n+\n+\tif ($diff_status eq \"A\") {\n+\t\treturn (\"link\", $diff_status) if -l $path;\n+\t\treturn (\"dir\", $diff_status) if -d $path;\n+\t\treturn (\"file\", $diff_status);\n+\t}\n+\n+\tmy $mode = (split(' ', $ls_tree))[0] || \"\";\n+\n+\treturn (\"link\", $diff_status) if $mode eq \"120000\";\n+\treturn (\"dir\", $diff_status) if $mode eq \"040000\";\n+\treturn (\"file\", $diff_status);\n+}\n+\n package Git::SVN::Util;\n use strict;\n use warnings;\ndiff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh\nnew file mode 100644\nindex 0000000..edd64d6\n--- /dev/null\n+++ b/t/t9119-git-svn-info.sh\n@@ -0,0 +1,274 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2007 David D. Kilzer\n+\n+test_description='git-svn info'\n+\n+. ./lib-git-svn.sh\n+\n+ptouch() {\n+\tperl -w -e '\n+\t\tuse strict;\n+\t\tdie \"ptouch requires exactly 2 arguments\" if @ARGV != 2;\n+\t\tdie \"$ARGV[0] does not exist\" if ! -e $ARGV[0];\n+\t\tmy @s = stat $ARGV[0];\n+\t\tutime $s[8], $s[9], $ARGV[1];\n+\t' \"$1\" \"$2\"\n+}\n+\n+test_expect_success 'setup repository and import' \"\n+\tmkdir info &&\n+\tcd info &&\n+\t\techo one > file &&\n+\t\tln -s file symlink-file &&\n+\t\tmkdir directory &&\n+\t\ttouch directory/.placeholder &&\n+\t\tln -s directory symlink-directory &&\n+\t\tsvn import -m 'initial' . $svnrepo &&\n+\tcd .. &&\n+\tmkdir gitwc &&\n+\tcd gitwc &&\n+\t\tgit-svn init $svnrepo &&\n+\t\tgit-svn fetch &&\n+\tcd .. &&\n+\tsvn co $svnrepo svnwc &&\n+\tptouch svnwc/file gitwc/file &&\n+\tptouch svnwc/directory gitwc/directory &&\n+\tptouch svnwc/symlink-file gitwc/symlink-file &&\n+\tptouch svnwc/symlink-directory gitwc/symlink-directory\n+\t\"\n+\n+test_expect_success 'info' \"\n+\t(cd svnwc; svn info) > expected.info &&\n+\t(cd gitwc; git-svn info) > actual.info &&\n+\tgit-diff expected.info actual.info\n+\t\"\n+\n+test_expect_success 'info .' \"\n+\t(cd svnwc; svn info .) > expected.info-dot &&\n+\t(cd gitwc; git-svn info .) > actual.info-dot &&\n+\tgit-diff expected.info-dot actual.info-dot\n+\t\"\n+\n+test_expect_success 'info file' \"\n+\t(cd svnwc; svn info file) > expected.info-file &&\n+\t(cd gitwc; git-svn info file) > actual.info-file &&\n+\tgit-diff expected.info-file actual.info-file\n+\t\"\n+\n+test_expect_success 'info directory' \"\n+\t(cd svnwc; svn info directory) > expected.info-directory &&\n+\t(cd gitwc; git-svn info directory) > actual.info-directory &&\n+\tgit-diff expected.info-directory actual.info-directory\n+\t\"\n+\n+test_expect_success 'info symlink-file' \"\n+\t(cd svnwc; svn info symlink-file) > expected.info-symlink-file &&\n+\t(cd gitwc; git-svn info symlink-file) > actual.info-symlink-file &&\n+\tgit-diff expected.info-symlink-file actual.info-symlink-file\n+\t\"\n+\n+test_expect_success 'info symlink-directory' \"\n+\t(cd svnwc; svn info symlink-directory) \\\n+\t\t> expected.info-symlink-directory &&\n+\t(cd gitwc; git-svn info symlink-directory) \\\n+\t\t> actual.info-symlink-directory &&\n+\tgit-diff expected.info-symlink-directory actual.info-symlink-directory\n+\t\"\n+\n+test_expect_success 'info added-file' \"\n+\techo two > gitwc/added-file &&\n+\tcd gitwc &&\n+\t\tgit add added-file &&\n+\tcd .. &&\n+\tcp gitwc/added-file svnwc/added-file &&\n+\tptouch gitwc/added-file svnwc/added-file &&\n+\tcd svnwc &&\n+\t\tsvn add added-file > /dev/null &&\n+\tcd .. &&\n+\t(cd svnwc; svn info added-file) > expected.info-added-file &&\n+\t(cd gitwc; git-svn info added-file) > actual.info-added-file &&\n+\tgit-diff expected.info-added-file actual.info-added-file\n+\t\"\n+\n+test_expect_success 'info added-directory' \"\n+\tmkdir gitwc/added-directory svnwc/added-directory &&\n+\tptouch gitwc/added-directory svnwc/added-directory &&\n+\ttouch gitwc/added-directory/.placeholder &&\n+\tcd svnwc &&\n+\t\tsvn add added-directory > /dev/null &&\n+\tcd .. &&\n+\tcd gitwc &&\n+\t\tgit add added-directory &&\n+\tcd .. &&\n+\t(cd svnwc; svn info added-directory) \\\n+\t\t> expected.info-added-directory &&\n+\t(cd gitwc; git-svn info added-directory) \\\n+\t\t> actual.info-added-directory &&\n+\tgit-diff expected.info-added-directory actual.info-added-directory\n+\t\"\n+\n+test_expect_success 'info added-symlink-file' \"\n+\tcd gitwc &&\n+\t\tln -s added-file added-symlink-file &&\n+\t\tgit add added-symlink-file &&\n+\tcd .. &&\n+\tcd svnwc &&\n+\t\tln -s added-file added-symlink-file &&\n+\t\tsvn add added-symlink-file > /dev/null &&\n+\tcd .. &&\n+\tptouch gitwc/added-symlink-file svnwc/added-symlink-file &&\n+\t(cd svnwc; svn info added-symlink-file) \\\n+\t\t> expected.info-added-symlink-file &&\n+\t(cd gitwc; git-svn info added-symlink-file) \\\n+\t\t> actual.info-added-symlink-file &&\n+\tgit-diff expected.info-added-symlink-file \\\n+\t\t actual.info-added-symlink-file\n+\t\"\n+\n+test_expect_success 'info added-symlink-directory' \"\n+\tcd gitwc &&\n+\t\tln -s added-directory added-symlink-directory &&\n+\t\tgit add added-symlink-directory &&\n+\tcd .. &&\n+\tcd svnwc &&\n+\t\tln -s added-directory added-symlink-directory &&\n+\t\tsvn add added-symlink-directory > /dev/null &&\n+\tcd .. &&\n+\tptouch gitwc/added-symlink-directory svnwc/added-symlink-directory &&\n+\t(cd svnwc; svn info added-symlink-directory) \\\n+\t\t> expected.info-added-symlink-directory &&\n+\t(cd gitwc; git-svn info added-symlink-directory) \\\n+\t\t> actual.info-added-symlink-directory &&\n+\tgit-diff expected.info-added-symlink-directory \\\n+\t\t actual.info-added-symlink-directory\n+\t\"\n+\n+# The next few tests replace the \"Text Last Updated\" value with a\n+# placeholder since git doesn't have a way to know the date that a\n+# now-deleted file was last checked out locally.  Internally it\n+# simply reuses the Last Changed Date.\n+\n+test_expect_success 'info deleted-file' \"\n+\tcd gitwc &&\n+\t\tgit rm -f file > /dev/null &&\n+\tcd .. &&\n+\tcd svnwc &&\n+\t\tsvn rm --force file > /dev/null &&\n+\tcd .. &&\n+\t(cd svnwc; svn info file) |\n+\tsed -e 's/^\\(Text Last Updated:\\).*/\\1 TEXT-LAST-UPDATED-STRING/' \\\n+\t\t> expected.info-deleted-file &&\n+\t(cd gitwc; git-svn info file) |\n+\tsed -e 's/^\\(Text Last Updated:\\).*/\\1 TEXT-LAST-UPDATED-STRING/' \\\n+\t\t> actual.info-deleted-file &&\n+\tgit-diff expected.info-deleted-file actual.info-deleted-file\n+\t\"\n+\n+test_expect_success 'info deleted-directory' \"\n+\tcd gitwc &&\n+\t\tgit rm -r -f directory > /dev/null &&\n+\tcd .. &&\n+\tcd svnwc &&\n+\t\tsvn rm --force directory > /dev/null &&\n+\tcd .. &&\n+\t(cd svnwc; svn info directory) |\n+\tsed -e 's/^\\(Text Last Updated:\\).*/\\1 TEXT-LAST-UPDATED-STRING/' \\\n+\t\t> expected.info-deleted-directory &&\n+\t(cd gitwc; git-svn info directory) |\n+\tsed -e 's/^\\(Text Last Updated:\\).*/\\1 TEXT-LAST-UPDATED-STRING/' \\\n+\t\t> actual.info-deleted-directory &&\n+\tgit-diff expected.info-deleted-directory actual.info-deleted-directory\n+\t\"\n+\n+test_expect_success 'info deleted-symlink-file' \"\n+\tcd gitwc &&\n+\t\tgit rm -f symlink-file > /dev/null &&\n+\tcd .. &&\n+\tcd svnwc &&\n+\t\tsvn rm --force symlink-file > /dev/null &&\n+\tcd .. &&\n+\t(cd svnwc; svn info symlink-file) |\n+\tsed -e 's/^\\(Text Last Updated:\\).*/\\1 TEXT-LAST-UPDATED-STRING/' \\\n+\t\t> expected.info-deleted-symlink-file &&\n+\t(cd gitwc; git-svn info symlink-file) |\n+\tsed -e 's/^\\(Text Last Updated:\\).*/\\1 TEXT-LAST-UPDATED-STRING/' \\\n+\t\t> actual.info-deleted-symlink-file &&\n+\tgit-diff expected.info-deleted-symlink-file \\\n+\t\t actual.info-deleted-symlink-file\n+\t\"\n+\n+test_expect_success 'info deleted-symlink-directory' \"\n+\tcd gitwc &&\n+\t\tgit rm -f symlink-directory > /dev/null &&\n+\tcd .. &&\n+\tcd svnwc &&\n+\t\tsvn rm --force symlink-directory > /dev/null &&\n+\tcd .. &&\n+\t(cd svnwc; svn info symlink-directory) |\n+\tsed -e 's/^\\(Text Last Updated:\\).*/\\1 TEXT-LAST-UPDATED-STRING/' \\\n+\t\t > expected.info-deleted-symlink-directory &&\n+\t(cd gitwc; git-svn info symlink-directory) |\n+\tsed -e 's/^\\(Text Last Updated:\\).*/\\1 TEXT-LAST-UPDATED-STRING/' \\\n+\t\t > actual.info-deleted-symlink-directory &&\n+\tgit-diff expected.info-deleted-symlink-directory \\\n+\t\t actual.info-deleted-symlink-directory\n+\t\"\n+\n+# NOTE: git does not have the concept of replaced objects,\n+# so we can't test for files in that state.\n+\n+test_expect_success 'info unknown-file' \"\n+\techo two > gitwc/unknown-file &&\n+\tcp gitwc/unknown-file svnwc/unknown-file &&\n+\tptouch gitwc/unknown-file svnwc/unknown-file &&\n+\t(cd svnwc; svn info unknown-file) 2> expected.info-unknown-file &&\n+\t(cd gitwc; git-svn info unknown-file) 2> actual.info-unknown-file &&\n+\tgit-diff expected.info-unknown-file actual.info-unknown-file\n+\t\"\n+\n+test_expect_success 'info unknown-directory' \"\n+\tmkdir gitwc/unknown-directory svnwc/unknown-directory &&\n+\tptouch gitwc/unknown-directory svnwc/unknown-directory &&\n+\ttouch gitwc/unknown-directory/.placeholder &&\n+\t(cd svnwc; svn info unknown-directory) \\\n+\t\t2> expected.info-unknown-directory &&\n+\t(cd gitwc; git-svn info unknown-directory) \\\n+\t\t2> actual.info-unknown-directory &&\n+\tgit-diff expected.info-unknown-directory actual.info-unknown-directory\n+\t\"\n+\n+test_expect_success 'info unknown-symlink-file' \"\n+\tcd gitwc &&\n+\t\tln -s unknown-file unknown-symlink-file &&\n+\tcd .. &&\n+\tcd svnwc &&\n+\t\tln -s unknown-file unknown-symlink-file &&\n+\tcd .. &&\n+\tptouch gitwc/unknown-symlink-file svnwc/unknown-symlink-file &&\n+\t(cd svnwc; svn info unknown-symlink-file) \\\n+\t\t2> expected.info-unknown-symlink-file &&\n+\t(cd gitwc; git-svn info unknown-symlink-file) \\\n+\t\t2> actual.info-unknown-symlink-file &&\n+\tgit-diff expected.info-unknown-symlink-file \\\n+\t\t actual.info-unknown-symlink-file\n+\t\"\n+\n+test_expect_success 'info unknown-symlink-directory' \"\n+\tcd gitwc &&\n+\t\tln -s unknown-directory unknown-symlink-directory &&\n+\tcd .. &&\n+\tcd svnwc &&\n+\t\tln -s unknown-directory unknown-symlink-directory &&\n+\tcd .. &&\n+\tptouch gitwc/unknown-symlink-directory \\\n+\t       svnwc/unknown-symlink-directory &&\n+\t(cd svnwc; svn info unknown-symlink-directory) \\\n+\t\t2> expected.info-unknown-symlink-directory &&\n+\t(cd gitwc; git-svn info unknown-symlink-directory) \\\n+\t\t2> actual.info-unknown-symlink-directory &&\n+\tgit-diff expected.info-unknown-symlink-directory \\\n+\t\t actual.info-unknown-symlink-directory\n+\t\"\n+\n+test_done\n-- \n1.5.3.4\n"},{"id":"60558","messageId":"1195675039-26746-4-git-send-email-ddkilzer@kilzer.net","threadId":"10965","inReplyTo":"1195675039-26746-3-git-send-email-ddkilzer@kilzer.net","subject":"[PATCH 3/3 v3] git-svn: info --url [path]","fromName":"David D. Kilzer","fromEmail":"ddkilzer@kilzer.net","sentAt":"2007-11-21T19:57:19Z","receivedAt":"2007-11-21T19:57:19Z","isPatch":true,"sender":{"key":"ddkilzer@kilzer.net","avatar":"https://avatars.githubusercontent.com/u/263571?v=4"},"body":"Return the svn URL for the given path, or return the svn\nrepository URL if no path is given.\n\nAdded 18 tests to t/t9119-git-svn-info.sh.\n\nSigned-off-by: David D. Kilzer <ddkilzer@kilzer.net>\n---\n Documentation/git-svn.txt |    3 +-\n git-svn.perl              |    9 +++-\n t/t9119-git-svn-info.sh   |   93 +++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 102 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt\nindex c3fc878..918a992 100644\n--- a/Documentation/git-svn.txt\n+++ b/Documentation/git-svn.txt\n@@ -196,7 +196,8 @@ Any other arguments are passed directly to `git log'\n 'info'::\n \tShows information about a file or directory similar to what\n \t`svn info' provides.  Does not currently support a -r/--revision\n-\targument.\n+\targument.  Use the --url option to output only the value of the\n+\t'URL:' field.\n \n --\n \ndiff --git a/git-svn.perl b/git-svn.perl\nindex be9290c..62801c8 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -65,7 +65,7 @@ my ($_stdin, $_help, $_edit,\n \t$_template, $_shared,\n \t$_version, $_fetch_all, $_no_rebase,\n \t$_merge, $_strategy, $_dry_run, $_local,\n-\t$_prefix, $_no_checkout, $_verbose);\n+\t$_prefix, $_no_checkout, $_url, $_verbose);\n $Git::SVN::_follow_parent = 1;\n my %remote_opts = ( 'username=s' => \\$Git::SVN::Prompt::_username,\n                     'config-dir=s' => \\$Git::SVN::Ra::config_dir,\n@@ -181,7 +181,7 @@ my %cmd = (\n \t'info' => [ \\&cmd_info,\n \t\t    \"Show info about the latest SVN revision\n \t\t     on the current branch\",\n-\t\t    { } ],\n+\t\t    { 'url' => \\$_url, } ],\n );\n \n my $cmd;\n@@ -773,6 +773,11 @@ sub cmd_info {\n \t}\n \tmy $full_url = $url . ($path eq \".\" ? \"\" : \"/$path\");\n \n+\tif ($_url) {\n+\t\tprint $full_url, \"\\n\";\n+\t\treturn;\n+\t}\n+\n \tmy $result = \"Path: $path\\n\";\n \t$result .= \"Name: \" . basename($path) . \"\\n\" if $file_type ne \"dir\";\n \t$result .= \"URL: \" . $full_url . \"\\n\";\ndiff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh\nindex edd64d6..e81457f 100644\n--- a/t/t9119-git-svn-info.sh\n+++ b/t/t9119-git-svn-info.sh\n@@ -44,30 +44,51 @@ test_expect_success 'info' \"\n \tgit-diff expected.info actual.info\n \t\"\n \n+test_expect_success 'info --url' '\n+\ttest $(cd gitwc; git-svn info --url) = $svnrepo\n+\t'\n+\n test_expect_success 'info .' \"\n \t(cd svnwc; svn info .) > expected.info-dot &&\n \t(cd gitwc; git-svn info .) > actual.info-dot &&\n \tgit-diff expected.info-dot actual.info-dot\n \t\"\n \n+test_expect_success 'info --url .' '\n+\ttest $(cd gitwc; git-svn info --url .) = $svnrepo\n+\t'\n+\n test_expect_success 'info file' \"\n \t(cd svnwc; svn info file) > expected.info-file &&\n \t(cd gitwc; git-svn info file) > actual.info-file &&\n \tgit-diff expected.info-file actual.info-file\n \t\"\n \n+test_expect_success 'info --url file' '\n+\ttest $(cd gitwc; git-svn info --url file) = \"$svnrepo/file\"\n+\t'\n+\n test_expect_success 'info directory' \"\n \t(cd svnwc; svn info directory) > expected.info-directory &&\n \t(cd gitwc; git-svn info directory) > actual.info-directory &&\n \tgit-diff expected.info-directory actual.info-directory\n \t\"\n \n+test_expect_success 'info --url directory' '\n+\ttest $(cd gitwc; git-svn info --url directory) = \"$svnrepo/directory\"\n+\t'\n+\n test_expect_success 'info symlink-file' \"\n \t(cd svnwc; svn info symlink-file) > expected.info-symlink-file &&\n \t(cd gitwc; git-svn info symlink-file) > actual.info-symlink-file &&\n \tgit-diff expected.info-symlink-file actual.info-symlink-file\n \t\"\n \n+test_expect_success 'info --url symlink-file' '\n+\ttest $(cd gitwc; git-svn info --url symlink-file) \\\n+\t     = \"$svnrepo/symlink-file\"\n+\t'\n+\n test_expect_success 'info symlink-directory' \"\n \t(cd svnwc; svn info symlink-directory) \\\n \t\t> expected.info-symlink-directory &&\n@@ -76,6 +97,11 @@ test_expect_success 'info symlink-directory' \"\n \tgit-diff expected.info-symlink-directory actual.info-symlink-directory\n \t\"\n \n+test_expect_success 'info --url symlink-directory' '\n+\ttest $(cd gitwc; git-svn info --url symlink-directory) \\\n+\t     = \"$svnrepo/symlink-directory\"\n+\t'\n+\n test_expect_success 'info added-file' \"\n \techo two > gitwc/added-file &&\n \tcd gitwc &&\n@@ -91,6 +117,11 @@ test_expect_success 'info added-file' \"\n \tgit-diff expected.info-added-file actual.info-added-file\n \t\"\n \n+test_expect_success 'info --url added-file' '\n+\ttest $(cd gitwc; git-svn info --url added-file) \\\n+\t     = \"$svnrepo/added-file\"\n+\t'\n+\n test_expect_success 'info added-directory' \"\n \tmkdir gitwc/added-directory svnwc/added-directory &&\n \tptouch gitwc/added-directory svnwc/added-directory &&\n@@ -108,6 +139,11 @@ test_expect_success 'info added-directory' \"\n \tgit-diff expected.info-added-directory actual.info-added-directory\n \t\"\n \n+test_expect_success 'info --url added-directory' '\n+\ttest $(cd gitwc; git-svn info --url added-directory) \\\n+\t     = \"$svnrepo/added-directory\"\n+\t'\n+\n test_expect_success 'info added-symlink-file' \"\n \tcd gitwc &&\n \t\tln -s added-file added-symlink-file &&\n@@ -126,6 +162,11 @@ test_expect_success 'info added-symlink-file' \"\n \t\t actual.info-added-symlink-file\n \t\"\n \n+test_expect_success 'info --url added-symlink-file' '\n+\ttest $(cd gitwc; git-svn info --url added-symlink-file) \\\n+\t     = \"$svnrepo/added-symlink-file\"\n+\t'\n+\n test_expect_success 'info added-symlink-directory' \"\n \tcd gitwc &&\n \t\tln -s added-directory added-symlink-directory &&\n@@ -144,6 +185,11 @@ test_expect_success 'info added-symlink-directory' \"\n \t\t actual.info-added-symlink-directory\n \t\"\n \n+test_expect_success 'info --url added-symlink-directory' '\n+\ttest $(cd gitwc; git-svn info --url added-symlink-directory) \\\n+\t     = \"$svnrepo/added-symlink-directory\"\n+\t'\n+\n # The next few tests replace the \"Text Last Updated\" value with a\n # placeholder since git doesn't have a way to know the date that a\n # now-deleted file was last checked out locally.  Internally it\n@@ -165,6 +211,11 @@ test_expect_success 'info deleted-file' \"\n \tgit-diff expected.info-deleted-file actual.info-deleted-file\n \t\"\n \n+test_expect_success 'info --url file (deleted)' '\n+\ttest $(cd gitwc; git-svn info --url file) \\\n+\t     = \"$svnrepo/file\"\n+\t'\n+\n test_expect_success 'info deleted-directory' \"\n \tcd gitwc &&\n \t\tgit rm -r -f directory > /dev/null &&\n@@ -181,6 +232,11 @@ test_expect_success 'info deleted-directory' \"\n \tgit-diff expected.info-deleted-directory actual.info-deleted-directory\n \t\"\n \n+test_expect_success 'info --url directory (deleted)' '\n+\ttest $(cd gitwc; git-svn info --url directory) \\\n+\t     = \"$svnrepo/directory\"\n+\t'\n+\n test_expect_success 'info deleted-symlink-file' \"\n \tcd gitwc &&\n \t\tgit rm -f symlink-file > /dev/null &&\n@@ -198,6 +254,11 @@ test_expect_success 'info deleted-symlink-file' \"\n \t\t actual.info-deleted-symlink-file\n \t\"\n \n+test_expect_success 'info --url symlink-file (deleted)' '\n+\ttest $(cd gitwc; git-svn info --url symlink-file) \\\n+\t     = \"$svnrepo/symlink-file\"\n+\t'\n+\n test_expect_success 'info deleted-symlink-directory' \"\n \tcd gitwc &&\n \t\tgit rm -f symlink-directory > /dev/null &&\n@@ -215,6 +276,11 @@ test_expect_success 'info deleted-symlink-directory' \"\n \t\t actual.info-deleted-symlink-directory\n \t\"\n \n+test_expect_success 'info --url symlink-directory (deleted)' '\n+\ttest $(cd gitwc; git-svn info --url symlink-directory) \\\n+\t     = \"$svnrepo/symlink-directory\"\n+\t'\n+\n # NOTE: git does not have the concept of replaced objects,\n # so we can't test for files in that state.\n \n@@ -227,6 +293,12 @@ test_expect_success 'info unknown-file' \"\n \tgit-diff expected.info-unknown-file actual.info-unknown-file\n \t\"\n \n+test_expect_success 'info --url unknown-file' '\n+\ttest -z $(cd gitwc; git-svn info --url unknown-file \\\n+\t\t\t2> ../actual.info--url-unknown-file) &&\n+\tgit-diff expected.info-unknown-file actual.info--url-unknown-file\n+\t'\n+\n test_expect_success 'info unknown-directory' \"\n \tmkdir gitwc/unknown-directory svnwc/unknown-directory &&\n \tptouch gitwc/unknown-directory svnwc/unknown-directory &&\n@@ -238,6 +310,13 @@ test_expect_success 'info unknown-directory' \"\n \tgit-diff expected.info-unknown-directory actual.info-unknown-directory\n \t\"\n \n+test_expect_success 'info --url unknown-directory' '\n+\ttest -z $(cd gitwc; git-svn info --url unknown-directory \\\n+\t\t\t2> ../actual.info--url-unknown-directory) &&\n+\tgit-diff expected.info-unknown-directory \\\n+\t\t actual.info--url-unknown-directory\n+\t'\n+\n test_expect_success 'info unknown-symlink-file' \"\n \tcd gitwc &&\n \t\tln -s unknown-file unknown-symlink-file &&\n@@ -254,6 +333,13 @@ test_expect_success 'info unknown-symlink-file' \"\n \t\t actual.info-unknown-symlink-file\n \t\"\n \n+test_expect_success 'info --url unknown-symlink-file' '\n+\ttest -z $(cd gitwc; git-svn info --url unknown-symlink-file \\\n+\t\t\t2> ../actual.info--url-unknown-symlink-file) &&\n+\tgit-diff expected.info-unknown-symlink-file \\\n+\t\t actual.info--url-unknown-symlink-file\n+\t'\n+\n test_expect_success 'info unknown-symlink-directory' \"\n \tcd gitwc &&\n \t\tln -s unknown-directory unknown-symlink-directory &&\n@@ -271,4 +357,11 @@ test_expect_success 'info unknown-symlink-directory' \"\n \t\t actual.info-unknown-symlink-directory\n \t\"\n \n+test_expect_success 'info --url unknown-symlink-directory' '\n+\ttest -z $(cd gitwc; git-svn info --url unknown-symlink-directory \\\n+\t\t\t2> ../actual.info--url-unknown-symlink-directory) &&\n+\tgit-diff expected.info-unknown-symlink-directory \\\n+\t\t actual.info--url-unknown-symlink-directory\n+\t'\n+\n test_done\n-- \n1.5.3.4\n"},{"id":"60591","messageId":"20071122011946.GA30134@soma","threadId":"10965","inReplyTo":"1195675039-26746-2-git-send-email-ddkilzer@kilzer.net","subject":"Re: [PATCH 1/3 v3] git-svn: extract reusable code into utility functions","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2007-11-22T01:19:46Z","receivedAt":"2007-11-22T01:19:46Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"\"David D. Kilzer\" <ddkilzer@kilzer.net> wrote:\n> Extacted canonicalize_path() in the main package.\n> \n> Created new Git::SVN::Util package with an md5sum() function.  A\n> new package was created so that Digest::MD5 did not have to be\n> loaded in the main package.  Replaced code in the SVN::Git::Editor\n> and SVN::Git::Fetcher packages with calls to md5sum().\n> \n> Extracted the format_svn_date(), parse_git_date() and\n> set_local_timezone() functions within the Git::SVN::Log package.\n> \n> Signed-off-by: David D. Kilzer <ddkilzer@kilzer.net>\n\nThanks, this patch is independently useful.\n\nAcked-by: Eric Wong <normalperson@yhbt.net>\n\n\nI'm having a problem with [2/3] currently:\n\n$file_type not being detected correctly when running \"git svn info\"\non the top-level directory with no arguments.  It's opening the\ndirectory and trying to md5 it here:\n\n\t\t} else {\n\t\t\topen FILE, \"<\", $path or die $!;\n\t\t\t$checksum = Git::SVN::Util::md5sum(\\*FILE);\n\t\t\tclose FILE or die $!;\n\t\t}\n\n> ---\n>  git-svn.perl |   96 ++++++++++++++++++++++++++++++++++++++-------------------\n>  1 files changed, 64 insertions(+), 32 deletions(-)\n> \n> diff --git a/git-svn.perl b/git-svn.perl\n> index 5b1deea..98c980f 100755\n> --- a/git-svn.perl\n> +++ b/git-svn.perl\n> @@ -48,7 +48,8 @@ BEGIN {\n>  \tforeach (qw/command command_oneline command_noisy command_output_pipe\n>  \t            command_input_pipe command_close_pipe/) {\n>  \t\tfor my $package ( qw(SVN::Git::Editor SVN::Git::Fetcher\n> -\t\t\tGit::SVN::Migration Git::SVN::Log Git::SVN),\n> +\t\t\tGit::SVN::Migration Git::SVN::Log Git::SVN\n> +\t\t\tGit::SVN::Util),\n>  \t\t\t__PACKAGE__) {\n>  \t\t\t*{\"${package}::$_\"} = \\&{\"Git::$_\"};\n>  \t\t}\n> @@ -583,6 +584,17 @@ sub cmd_create_ignore {\n>  \t});\n>  }\n>  \n> +sub canonicalize_path {\n> +\tmy ($path) = @_;\n> +\t# File::Spec->canonpath doesn't collapse x/../y into y (for a\n> +\t# good reason), so let's do this manually.\n> +\t$path =~ s#/+#/#g;\n> +\t$path =~ s#/\\.(?:/|$)#/#g;\n> +\t$path =~ s#/[^/]+/\\.\\.##g;\n> +\t$path =~ s#/$##g;\n> +\treturn $path;\n> +}\n> +\n>  # get_svnprops(PATH)\n>  # ------------------\n>  # Helper for cmd_propget and cmd_proplist below.\n> @@ -600,12 +612,7 @@ sub get_svnprops {\n>  \n>  \t# canonicalize the path (otherwise libsvn will abort or fail to\n>  \t# find the file)\n> -\t# File::Spec->canonpath doesn't collapse x/../y into y (for a\n> -\t# good reason), so let's do this manually.\n> -\t$path =~ s#/+#/#g;\n> -\t$path =~ s#/\\.(?:/|$)#/#g;\n> -\t$path =~ s#/[^/]+/\\.\\.##g;\n> -\t$path =~ s#/$##g;\n> +\t$path = canonicalize_path($path);\n>  \n>  \tmy $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);\n>  \tmy $props;\n> @@ -1043,6 +1050,27 @@ sub linearize_history {\n>  \t(\\@linear_refs, \\%parents);\n>  }\n>  \n> +package Git::SVN::Util;\n> +use strict;\n> +use warnings;\n> +use Digest::MD5;\n> +\n> +sub md5sum {\n> +\tmy $arg = shift;\n> +\tmy $ref = ref $arg;\n> +\tmy $md5 = Digest::MD5->new();\n> +        if ($ref eq 'GLOB' || $ref eq 'IO::File') {\n> +\t\t$md5->addfile($arg) or croak $!;\n> +\t} elsif ($ref eq 'SCALAR') {\n> +\t\t$md5->add($$arg) or croak $!;\n> +\t} elsif (!$ref) {\n> +\t\t$md5->add($arg) or croak $!;\n> +\t} else {\n> +\t\t::fatal \"Can't provide MD5 hash for unknown ref type: '\", $ref, \"'\";\n> +\t}\n> +\treturn $md5->hexdigest();\n> +}\n> +\n>  package Git::SVN;\n>  use strict;\n>  use warnings;\n> @@ -2610,7 +2638,6 @@ use strict;\n>  use warnings;\n>  use Carp qw/croak/;\n>  use IO::File qw//;\n> -use Digest::MD5;\n>  \n>  # file baton members: path, mode_a, mode_b, pool, fh, blob, base\n>  sub new {\n> @@ -2762,9 +2789,7 @@ sub apply_textdelta {\n>  \n>  \t\tif (defined $exp) {\n>  \t\t\tseek $base, 0, 0 or croak $!;\n> -\t\t\tmy $md5 = Digest::MD5->new;\n> -\t\t\t$md5->addfile($base);\n> -\t\t\tmy $got = $md5->hexdigest;\n> +\t\t\tmy $got = Git::SVN::Util::md5sum($base);\n>  \t\t\tdie \"Checksum mismatch: $fb->{path} $fb->{blob}\\n\",\n>  \t\t\t    \"expected: $exp\\n\",\n>  \t\t\t    \"     got: $got\\n\" if ($got ne $exp);\n> @@ -2783,9 +2808,7 @@ sub close_file {\n>  \tif (my $fh = $fb->{fh}) {\n>  \t\tif (defined $exp) {\n>  \t\t\tseek($fh, 0, 0) or croak $!;\n> -\t\t\tmy $md5 = Digest::MD5->new;\n> -\t\t\t$md5->addfile($fh);\n> -\t\t\tmy $got = $md5->hexdigest;\n> +\t\t\tmy $got = Git::SVN::Util::md5sum($fh);\n>  \t\t\tif ($got ne $exp) {\n>  \t\t\t\tdie \"Checksum mismatch: $path\\n\",\n>  \t\t\t\t    \"expected: $exp\\n    got: $got\\n\";\n> @@ -2837,7 +2860,6 @@ use strict;\n>  use warnings;\n>  use Carp qw/croak/;\n>  use IO::File;\n> -use Digest::MD5;\n>  \n>  sub new {\n>  \tmy ($class, $opts) = @_;\n> @@ -3141,11 +3163,9 @@ sub chg_file {\n>  \t$fh->flush == 0 or croak $!;\n>  \tseek $fh, 0, 0 or croak $!;\n>  \n> -\tmy $md5 = Digest::MD5->new;\n> -\t$md5->addfile($fh) or croak $!;\n> +\tmy $exp = Git::SVN::Util::md5sum($fh);\n>  \tseek $fh, 0, 0 or croak $!;\n>  \n> -\tmy $exp = $md5->hexdigest;\n>  \tmy $pool = SVN::Pool->new;\n>  \tmy $atd = $self->apply_textdelta($fbat, undef, $pool);\n>  \tmy $got = SVN::TxDelta::send_stream($fh, @$atd, $pool);\n> @@ -3859,6 +3879,29 @@ sub run_pager {\n>  \texec $pager or ::fatal \"Can't run pager: $! ($pager)\";\n>  }\n>  \n> +sub format_svn_date {\n> +\treturn strftime(\"%Y-%m-%d %H:%M:%S %z (%a, %d %b %Y)\", localtime(shift));\n> +}\n> +\n> +sub parse_git_date {\n> +\tmy ($t, $tz) = @_;\n> +\t# Date::Parse isn't in the standard Perl distro :(\n> +\tif ($tz =~ s/^\\+//) {\n> +\t\t$t += tz_to_s_offset($tz);\n> +\t} elsif ($tz =~ s/^\\-//) {\n> +\t\t$t -= tz_to_s_offset($tz);\n> +\t}\n> +\treturn $t;\n> +}\n> +\n> +sub set_local_timezone {\n> +\tif (defined $TZ) {\n> +\t\t$ENV{TZ} = $TZ;\n> +\t} else {\n> +\t\tdelete $ENV{TZ};\n> +\t}\n> +}\n> +\n>  sub tz_to_s_offset {\n>  \tmy ($tz) = @_;\n>  \t$tz =~ s/(\\d\\d)$//;\n> @@ -3879,13 +3922,7 @@ sub get_author_info {\n>  \t$dest->{t} = $t;\n>  \t$dest->{tz} = $tz;\n>  \t$dest->{a} = $au;\n> -\t# Date::Parse isn't in the standard Perl distro :(\n> -\tif ($tz =~ s/^\\+//) {\n> -\t\t$t += tz_to_s_offset($tz);\n> -\t} elsif ($tz =~ s/^\\-//) {\n> -\t\t$t -= tz_to_s_offset($tz);\n> -\t}\n> -\t$dest->{t_utc} = $t;\n> +\t$dest->{t_utc} = parse_git_date($t, $tz);\n>  }\n>  \n>  sub process_commit {\n> @@ -3939,8 +3976,7 @@ sub show_commit_normal {\n>  \tmy ($c) = @_;\n>  \tprint commit_log_separator, \"r$c->{r} | \";\n>  \tprint \"$c->{c} | \" if $show_commit;\n> -\tprint \"$c->{a} | \", strftime(\"%Y-%m-%d %H:%M:%S %z (%a, %d %b %Y)\",\n> -\t\t\t\t localtime($c->{t_utc})), ' | ';\n> +\tprint \"$c->{a} | \", format_svn_date($c->{t_utc}), ' | ';\n>  \tmy $nr_line = 0;\n>  \n>  \tif (my $l = $c->{l}) {\n> @@ -3980,11 +4016,7 @@ sub cmd_show_log {\n>  \tmy (@args) = @_;\n>  \tmy ($r_min, $r_max);\n>  \tmy $r_last = -1; # prevent dupes\n> -\tif (defined $TZ) {\n> -\t\t$ENV{TZ} = $TZ;\n> -\t} else {\n> -\t\tdelete $ENV{TZ};\n> -\t}\n> +\tset_local_timezone();\n>  \tif (defined $::_revision) {\n>  \t\tif ($::_revision =~ /^(\\d+):(\\d+)$/) {\n>  \t\t\t($r_min, $r_max) = ($1, $2);\n\n-- \nEric Wong\n"},{"id":"60594","messageId":"20071122014038.GA25341@soma","threadId":"10965","inReplyTo":"1195675039-26746-3-git-send-email-ddkilzer@kilzer.net","subject":"Re: [PATCH 2/3 v3] git-svn info: implement info command","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2007-11-22T01:40:38Z","receivedAt":"2007-11-22T01:40:38Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"\"David D. Kilzer\" <ddkilzer@kilzer.net> wrote:\n> Implement \"git-svn info\" for files and directories based on the\n> \"svn info\" command.  Note that the -r/--revision argument is not\n> supported yet.\n> \n> Added 18 tests in t/t9119-git-svn-info.sh.\n\nEric Wong <normalperson@yhbt.net> wrote:\n> I'm having a problem with [2/3] currently:\n> \n> $file_type not being detected correctly when running \"git svn info\"\n> on the top-level directory with no arguments.  It's opening the\n> directory and trying to md5 it here:\n> \n> \t\t} else {\n> \t\t\topen FILE, \"<\", $path or die $!;\n> \t\t\t$checksum = Git::SVN::Util::md5sum(\\*FILE);\n> \t\t\tclose FILE or die $!;\n> \t\t}\n> \n>\n\nWhen running from a top-level directory with no arguments, the first\nline of git-ls-tree was being read.  This allowed the test case to pass\nbecause ls-tree sorts the output and 'directory' just happened to\nbe up top; so we were getting the 040000 mode from the 'directory'\ntree and not the top-level tree.\n\nThe below test should fix it for the trivial case I have.\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 62801c8..7d86870 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -1165,6 +1165,7 @@ sub linearize_history {\n \n sub find_file_type_and_diff_status {\n \tmy ($path) = @_;\n+\treturn ('dir', '') if $path eq '.';\n \n \tmy $diff_output =\n \t    command_oneline(qw(diff --cached --name-status --), $path) || \"\";\ndiff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh\nindex e81457f..439bd93 100644\n--- a/t/t9119-git-svn-info.sh\n+++ b/t/t9119-git-svn-info.sh\n@@ -19,6 +19,7 @@ ptouch() {\n test_expect_success 'setup repository and import' \"\n \tmkdir info &&\n \tcd info &&\n+\t\techo FIRST > A &&\n \t\techo one > file &&\n \t\tln -s file symlink-file &&\n \t\tmkdir directory &&\n\n-- \nEric Wong\n"},{"id":"60598","messageId":"20071122022343.GA9992@soma","threadId":"10965","inReplyTo":"1195675039-26746-1-git-send-email-ddkilzer@kilzer.net","subject":"[PATCH 4/3] git-svn: allow `info' command to work offline","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2007-11-22T02:23:43Z","receivedAt":"2007-11-22T02:23:43Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Cache the repository root whenever we connect to the repository.\nThis will allow us to notice URL changes if the user changes the\nURL in .git/config, too.\n\nIf the repository is no longer accessible, or if `git svn info'\nis the first and only command run; then '(offline)' will be\ndisplayed for \"Repository Root:\" in the output.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n\n David:\n\n I'll apply this once you've verified my fix to 1/3 is correct behavior,\n too.\n\n git-svn.perl |   26 +++++++++++++++++++++++---\n 1 files changed, 23 insertions(+), 3 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 7d86870..43e1591 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -782,9 +782,14 @@ sub cmd_info {\n \t$result .= \"Name: \" . basename($path) . \"\\n\" if $file_type ne \"dir\";\n \t$result .= \"URL: \" . $full_url . \"\\n\";\n \n-\tmy $repos_root = $gs->ra->{repos_root};\n-\tGit::SVN::remove_username($repos_root);\n-\t$result .= \"Repository Root: $repos_root\\n\";\n+\teval {\n+\t\tmy $repos_root = $gs->repos_root;\n+\t\tGit::SVN::remove_username($repos_root);\n+\t\t$result .= \"Repository Root: $repos_root\\n\";\n+\t};\n+\tif ($@) {\n+\t\t$result .= \"Repository Root: (offline)\\n\";\n+\t}\n \t$result .= \"Repository UUID: $uuid\\n\" unless $diff_status eq \"A\";\n \t$result .= \"Revision: \" . ($diff_status eq \"A\" ? 0 : $rev) . \"\\n\";\n \n@@ -1773,9 +1778,24 @@ sub ra_uuid {\n \t$self->{ra_uuid};\n }\n \n+sub _set_repos_root {\n+\tmy ($self, $repos_root) = @_;\n+\tmy $k = \"svn-remote.$self->{repo_id}.reposRoot\";\n+\t$repos_root ||= $self->ra->{repos_root};\n+\ttmp_config($k, $repos_root);\n+\t$repos_root;\n+}\n+\n+sub repos_root {\n+\tmy ($self) = @_;\n+\tmy $k = \"svn-remote.$self->{repo_id}.reposRoot\";\n+\teval { tmp_config('--get', $k) } || $self->_set_repos_root;\n+}\n+\n sub ra {\n \tmy ($self) = shift;\n \tmy $ra = Git::SVN::Ra->new($self->{url});\n+\t$self->_set_repos_root($ra->{repos_root});\n \tif ($self->use_svm_props && !$self->{svm}) {\n \t\tif ($self->no_metadata) {\n \t\t\tdie \"Can't have both 'noMetadata' and \",\n-- \nEric Wong\n"},{"id":"60600","messageId":"900537.19467.qm@web52411.mail.re2.yahoo.com","threadId":"10965","inReplyTo":"20071122014038.GA25341@soma","subject":"Re: [PATCH 2/3 v3] git-svn info: implement info command","fromName":"David D. Kilzer","fromEmail":"ddkilzer@kilzer.net","sentAt":"2007-11-22T03:16:21Z","receivedAt":"2007-11-22T03:16:21Z","isPatch":true,"sender":{"key":"ddkilzer@kilzer.net","avatar":"https://avatars.githubusercontent.com/u/263571?v=4"},"body":"Eric Wong <normalperson@yhbt.net> wrote:\n> When running from a top-level directory with no arguments, the first\n> line of git-ls-tree was being read.  This allowed the test case to pass\n> because ls-tree sorts the output and 'directory' just happened to\n> be up top; so we were getting the 040000 mode from the 'directory'\n> tree and not the top-level tree.\n> \n> The below test should fix it for the trivial case I have.\n\nAcked-by: David D. Kilzer <ddkilzer@kilzer.net>\n\nLooks good!  Thanks!\n\nDave\n"},{"id":"60601","messageId":"4744F66D.7030007@apple.com","threadId":"10965","inReplyTo":"20071122022343.GA9992@soma","subject":"Re: [PATCH 4/3] git-svn: allow `info' command to work offline","fromName":"Adam Roben","fromEmail":"aroben@apple.com","sentAt":"2007-11-22T03:24:29Z","receivedAt":"2007-11-22T03:24:29Z","isPatch":true,"sender":{"key":"aroben@apple.com","avatar":"https://gravatar.com/avatar/9d3697e1de53890adf241331f4b970bdd2b18962b2ff0b8028ebb00e085807f8?d=mp&s=160"},"body":"Eric Wong wrote:\n> +\tmy $k = \"svn-remote.$self->{repo_id}.reposRoot\";\n>   \n\n\"repoRoot\" seems slightly more intuitive than \"reposRoot\", given that \n\"repository\" is normally abbreviated as \"repo\".\n\n-Adam\n"},{"id":"60603","messageId":"20071122035605.GB30134@soma","threadId":"10965","inReplyTo":"4744F66D.7030007@apple.com","subject":"Re: [PATCH 4/3] git-svn: allow `info' command to work offline","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2007-11-22T03:56:05Z","receivedAt":"2007-11-22T03:56:05Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Adam Roben <aroben@apple.com> wrote:\n> Eric Wong wrote:\n> >+\tmy $k = \"svn-remote.$self->{repo_id}.reposRoot\";\n> >  \n> \n> \"repoRoot\" seems slightly more intuitive than \"reposRoot\", given that \n> \"repository\" is normally abbreviated as \"repo\".\n\n>From a git-only point of view, yes.  But it's repos_root everywhere\ninside git-svn because SVN uses \"*_repos_root\" for their API.\nThis is inside the hidden metadata file that users\nshouldn't have to touch anyways.\n\nOn a side note:\n\nI personally *hate* camelCase names (or worse, alllowercase), but\ngit config doesn't allow underscores in config keys for some\nstrange reason (especially strange since most of the git and Linux\nsource code use snake_case...)\n\n-- \nEric Wong\n"},{"id":"60604","messageId":"20071122041753.GC30134@soma","threadId":"10965","inReplyTo":"900537.19467.qm@web52411.mail.re2.yahoo.com","subject":"Re: [PATCH 2/3 v3] git-svn info: implement info command","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2007-11-22T04:17:53Z","receivedAt":"2007-11-22T04:17:53Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"\"David D. Kilzer\" <ddkilzer@kilzer.net> wrote:\n> Eric Wong <normalperson@yhbt.net> wrote:\n> > When running from a top-level directory with no arguments, the first\n> > line of git-ls-tree was being read.  This allowed the test case to pass\n> > because ls-tree sorts the output and 'directory' just happened to\n> > be up top; so we were getting the 040000 mode from the 'directory'\n> > tree and not the top-level tree.\n> > \n> > The below test should fix it for the trivial case I have.\n> \n> Acked-by: David D. Kilzer <ddkilzer@kilzer.net>\n> \n> Looks good!  Thanks!\n\nOk, I've folded that into your [2/3] and pushed everything (and an\nearlier fix) out to\n\n\tgit://git.bogomips.org/git-svn.git\n\nDavid D. Kilzer (3):\n      git-svn: extract reusable code into utility functions\n      git-svn info: implement info command\n      git-svn: info --url [path]\n\nEric Wong (2):\n      t9106: fix a race condition that caused svn to miss modifications\n      git-svn: allow `info' command to work offline\n\nJunio, please pull, thanks.\n\n-- \nEric Wong\n"}]}