{"thread":{"id":"10309","subject":"Re: [PATCH 1/5] Add a generic tree traversal to fetch SVN properties.","startedAt":"2007-10-15T15:35:02Z","lastAt":"2007-10-16T09:55:03Z","messageCount":8,"participants":["Eric Wong","Benoit SIGOURE","Benoit Sigoure"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"56046","messageId":"1192462506-3783-1-git-send-email-tsuna@lrde.epita.fr","threadId":"10309","inReplyTo":null,"subject":"[PATCH 1/5] Add a generic tree traversal to fetch SVN properties.","fromName":"Benoit Sigoure","fromEmail":"tsuna@lrde.epita.fr","sentAt":"2007-10-15T15:35:02Z","receivedAt":"2007-10-15T15:35:02Z","isPatch":true,"sender":{"key":"tsunanet@gmail.com","avatar":"https://avatars.githubusercontent.com/u/128281?v=4"},"body":"\t* git-svn.perl (&traverse_ignore): Remove.\n\t(&prop_walk): New.\n\t(&cmd_show_ignore): Use prop_walk.\n\nSigned-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>\n---\n git-svn.perl |   66 ++++++++++++++++++++++++++++++++++++++++-----------------\n 1 files changed, 46 insertions(+), 20 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 777e436..abc83ec 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -488,7 +488,15 @@ sub cmd_show_ignore {\n \tmy ($url, $rev, $uuid, $gs) = working_head_info('HEAD');\n \t$gs ||= Git::SVN->new;\n \tmy $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);\n-\t$gs->traverse_ignore(\\*STDOUT, $gs->{path}, $r);\n+\t$gs->prop_walk($gs->{path}, $r, sub {\n+\t\tmy ($gs, $path, $props) = @_;\n+\t\tprint STDOUT \"\\n# $path\\n\";\n+\t\tmy $s = $props->{'svn:ignore'} or return;\n+\t\t$s =~ s/[\\r\\n]+/\\n/g;\n+\t\tchomp $s;\n+\t\t$s =~ s#^#$path#gm;\n+\t\tprint STDOUT \"$s\\n\";\n+\t});\n }\n \n sub cmd_multi_init {\n@@ -1480,28 +1488,46 @@ sub rel_path {\n \t$url;\n }\n \n-sub traverse_ignore {\n-\tmy ($self, $fh, $path, $r) = @_;\n-\t$path =~ s#^/+##g;\n-\tmy $ra = $self->ra;\n-\tmy ($dirent, undef, $props) = $ra->get_dir($path, $r);\n+# prop_walk(PATH, REV, SUB)\n+# -------------------------\n+# Recursively traverse PATH at revision REV and invoke SUB for each\n+# directory that contains a SVN property.  SUB will be invoked as\n+# follows:  &SUB(gs, path, props);  where `gs' is this instance of\n+# Git::SVN, `path' the path to the directory where the properties\n+# `props' were found.  The `path' will be relative to point of checkout,\n+# that is, if url://repo/trunk is the current Git branch, and that\n+# directory contains a sub-directory `d', SUB will be invoked with `/d/'\n+# as `path' (note the trailing `/').\n+sub prop_walk {\n+\tmy ($self, $path, $rev, $sub) = @_;\n+\n+\tmy ($dirent, undef, $props) = $self->ra->get_dir($path, $rev);\n+\t$path =~ s#^/*#/#g;\n \tmy $p = $path;\n-\t$p =~ s#^\\Q$self->{path}\\E(/|$)##;\n-\tprint $fh length $p ? \"\\n# $p\\n\" : \"\\n# /\\n\";\n-\tif (my $s = $props->{'svn:ignore'}) {\n-\t\t$s =~ s/[\\r\\n]+/\\n/g;\n-\t\tchomp $s;\n-\t\tif (length $p == 0) {\n-\t\t\t$s =~ s#\\n#\\n/$p#g;\n-\t\t\tprint $fh \"/$s\\n\";\n-\t\t} else {\n-\t\t\t$s =~ s#\\n#\\n/$p/#g;\n-\t\t\tprint $fh \"/$p/$s\\n\";\n-\t\t}\n-\t}\n+\t# Strip the irrelevant part of the path.\n+\t$p =~ s#^/+\\Q$self->{path}\\E(/|$)#/#;\n+\t# Ensure the path is terminated by a `/'.\n+\t$p =~ s#/*$#/#;\n+\n+\t# The properties contain all the internal SVN stuff nobody\n+\t# (usually) cares about.\n+\tmy $interesting_props = 0;\n+\tforeach(keys %{$props})\n+\t{\n+\t\t# If it doesn't start with `svn:', it must be a\n+\t\t# user-defined property.\n+\t\t++$interesting_props and next if $_ !~ /^svn:/;\n+\t\t# FIXME: Fragile, if SVN adds new public properties,\n+\t\t# this needs to be updated.\n+\t\t++$interesting_props if /^svn:(?:ignore|keywords|executable\n+\t\t                                 |eol-style|mime-type\n+\t\t\t\t\t\t |externals|needs-lock)$/x;\n+\t}\n+\t&$sub($self, $p, $props) if $interesting_props;\n+\n \tforeach (sort keys %$dirent) {\n \t\tnext if $dirent->{$_}->{kind} != $SVN::Node::dir;\n-\t\t$self->traverse_ignore($fh, \"$path/$_\", $r);\n+\t\t$self->prop_walk($path . '/' . $_, $rev, $sub);\n \t}\n }\n \n-- \n1.5.3.4.214.g6f43\n"},{"id":"56044","messageId":"1192462506-3783-2-git-send-email-tsuna@lrde.epita.fr","threadId":"10309","inReplyTo":"1192462506-3783-1-git-send-email-tsuna@lrde.epita.fr","subject":"[PATCH 2/5] Implement git svn create-ignore.","fromName":"Benoit Sigoure","fromEmail":"tsuna@lrde.epita.fr","sentAt":"2007-10-15T15:35:03Z","receivedAt":"2007-10-15T15:35:03Z","isPatch":true,"sender":{"key":"tsunanet@gmail.com","avatar":"https://avatars.githubusercontent.com/u/128281?v=4"},"body":"\t* git-svn.perl (%cmd): Add the new command `create-ignore'.\n\t(&cmd_create_ignore): New.\n\t* t/t9101-git-svn-props.sh: Adjust the test-case for show-ignore and\n\tadd a test case for create-ignore.\n\nSigned-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>\n---\n git-svn.perl             |   27 +++++++++++++++++++++++++++\n t/t9101-git-svn-props.sh |   28 +++++++++++++++++++++++++---\n 2 files changed, 52 insertions(+), 3 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex abc83ec..94091ea 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -123,6 +123,10 @@ my %cmd = (\n \t'set-tree' => [ \\&cmd_set_tree,\n \t                \"Set an SVN repository to a git tree-ish\",\n \t\t\t{ 'stdin|' => \\$_stdin, %cmt_opts, %fc_opts, } ],\n+\t'create-ignore' => [ \\&cmd_create_ignore,\n+\t\t\t     'Create a .gitignore per svn:ignore',\n+\t\t\t     { 'revision|r=i' => \\$_revision\n+\t\t\t     } ],\n \t'show-ignore' => [ \\&cmd_show_ignore, \"Show svn:ignore listings\",\n \t\t\t{ 'revision|r=i' => \\$_revision\n \t\t\t} ],\n@@ -499,6 +503,29 @@ sub cmd_show_ignore {\n \t});\n }\n \n+sub cmd_create_ignore {\n+\tmy ($url, $rev, $uuid, $gs) = working_head_info('HEAD');\n+\t$gs ||= Git::SVN->new;\n+\tmy $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);\n+\t$gs->prop_walk($gs->{path}, $r, sub {\n+\t\tmy ($gs, $path, $props) = @_;\n+\t\t# $path is of the form /path/to/dir/\n+\t\tmy $ignore = '.' . $path . '.gitignore';\n+\t\tmy $s = $props->{'svn:ignore'} or return;\n+\t\topen(GITIGNORE, '>', $ignore)\n+\t\t  or fatal(\"Failed to open `$ignore' for writing: $!\\n\");\n+\t\t$s =~ s/[\\r\\n]+/\\n/g;\n+\t\tchomp $s;\n+\t\t# Prefix all patterns so that the ignore doesn't apply\n+\t\t# to sub-directories.\n+\t\t$s =~ s#^#/#gm;\n+\t\tprint GITIGNORE \"$s\\n\";\n+\t\tclose(GITIGNORE)\n+\t\t  or fatal(\"Failed to close `$ignore': $!\\n\");\n+\t\tcommand_noisy('add', $ignore);\n+\t});\n+}\n+\n sub cmd_multi_init {\n \tmy $url = shift;\n \tunless (defined $_trunk || defined $_branches || defined $_tags) {\ndiff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh\nindex 5aac644..796d80e 100755\n--- a/t/t9101-git-svn-props.sh\n+++ b/t/t9101-git-svn-props.sh\n@@ -126,19 +126,20 @@ cat > show-ignore.expect <<\\EOF\n # /\n /no-such-file*\n \n-# deeply\n+# /deeply/\n /deeply/no-such-file*\n \n-# deeply/nested\n+# /deeply/nested/\n /deeply/nested/no-such-file*\n \n-# deeply/nested/directory\n+# /deeply/nested/directory/\n /deeply/nested/directory/no-such-file*\n EOF\n \n test_expect_success 'test show-ignore' \"\n \tcd test_wc &&\n \tmkdir -p deeply/nested/directory &&\n+\ttouch deeply/nested/directory/.keep &&\n \tsvn add deeply &&\n \tsvn up &&\n \tsvn propset -R svn:ignore 'no-such-file*' .\n@@ -148,4 +149,25 @@ test_expect_success 'test show-ignore' \"\n \tcmp show-ignore.expect show-ignore.got\n \t\"\n \n+cat >create-ignore.expect <<\\EOF\n+/no-such-file*\n+EOF\n+\n+cat >create-ignore-index.expect <<\\EOF\n+100644 8c52e5dfcd0a8b6b6bcfe6b41b89bcbf493718a5 0\t.gitignore\n+100644 8c52e5dfcd0a8b6b6bcfe6b41b89bcbf493718a5 0\tdeeply/.gitignore\n+100644 8c52e5dfcd0a8b6b6bcfe6b41b89bcbf493718a5 0\tdeeply/nested/.gitignore\n+100644 8c52e5dfcd0a8b6b6bcfe6b41b89bcbf493718a5 0\tdeeply/nested/directory/.gitignore\n+EOF\n+\n+test_expect_success 'test create-ignore' \"\n+\tgit-svn fetch && git pull . remotes/git-svn &&\n+\tgit-svn create-ignore &&\n+\tcmp ./.gitignore create-ignore.expect &&\n+\tcmp ./deeply/.gitignore create-ignore.expect &&\n+\tcmp ./deeply/nested/.gitignore create-ignore.expect &&\n+\tcmp ./deeply/nested/directory/.gitignore create-ignore.expect &&\n+\tgit ls-files -s | grep gitignore | cmp - create-ignore-index.expect\n+\t\"\n+\n test_done\n-- \n1.5.3.4.214.g6f43\n"},{"id":"56048","messageId":"1192462506-3783-3-git-send-email-tsuna@lrde.epita.fr","threadId":"10309","inReplyTo":"1192462506-3783-2-git-send-email-tsuna@lrde.epita.fr","subject":"[PATCH 3/5] Add git svn propget.","fromName":"Benoit Sigoure","fromEmail":"tsuna@lrde.epita.fr","sentAt":"2007-10-15T15:35:04Z","receivedAt":"2007-10-15T15:35:04Z","isPatch":true,"sender":{"key":"tsunanet@gmail.com","avatar":"https://avatars.githubusercontent.com/u/128281?v=4"},"body":"\t* git-svn.perl (%cmd): Add the new command `propget'.\n\t($cmd_dir_prefix): New global.\n\t(&get_svnprops): New helper.\n\t(&cmd_propget): New.  Use &get_svnprops.\n\t* t/t9101-git-svn-props.sh: Add a test case for propget.\n\nSigned-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>\n---\n git-svn.perl             |   57 ++++++++++++++++++++++++++++++++++++++++++++++\n t/t9101-git-svn-props.sh |   23 ++++++++++++++++++\n 2 files changed, 80 insertions(+), 0 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 94091ea..e58ff38 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -9,6 +9,8 @@ use vars qw/\t$AUTHOR $VERSION\n $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';\n $VERSION = '@@GIT_VERSION@@';\n \n+# From which subdir have we been invoked?\n+my $cmd_dir_prefix = command_oneline(qw/rev-parse --show-prefix/) || '';\n my $git_dir_user_set = 1 if defined $ENV{GIT_DIR};\n $ENV{GIT_DIR} ||= '.git';\n $Git::SVN::default_repo_id = 'svn';\n@@ -127,6 +129,9 @@ my %cmd = (\n \t\t\t     'Create a .gitignore per svn:ignore',\n \t\t\t     { 'revision|r=i' => \\$_revision\n \t\t\t     } ],\n+        'propget' => [ \\&cmd_propget,\n+\t\t       'Print the value of a property on a file or directory',\n+\t\t       { 'revision|r=i' => \\$_revision } ],\n \t'show-ignore' => [ \\&cmd_show_ignore, \"Show svn:ignore listings\",\n \t\t\t{ 'revision|r=i' => \\$_revision\n \t\t\t} ],\n@@ -526,6 +531,58 @@ sub cmd_create_ignore {\n \t});\n }\n \n+# get_svnprops(PATH)\n+# ------------------\n+# Helper for cmd_propget below.\n+sub get_svnprops {\n+\tmy $path = shift;\n+\tmy ($url, $rev, $uuid, $gs) = working_head_info('HEAD');\n+\t$gs ||= Git::SVN->new;\n+\n+\t# prefix THE PATH by the sub-directory from which the user\n+\t# invoked us.\n+\t$path = $cmd_dir_prefix . $path;\n+\tfatal(\"No such file or directory: $path\\n\") unless -e $path;\n+\tmy $is_dir = -d $path ? 1 : 0;\n+\t$path = $gs->{path} . '/' . $path;\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+\n+\tmy $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);\n+\tmy $props;\n+\tif ($is_dir)\n+\t{\n+\t\t(undef, undef, $props) = $gs->ra->get_dir($path, $r);\n+\t}\n+\telse\n+\t{\n+\t\t(undef, $props) = $gs->ra->get_file($path, $r, undef);\n+\t}\n+\treturn $props;\n+}\n+\n+# cmd_propget (PROP, PATH)\n+# ------------------------\n+# Print the SVN property PROP for PATH.\n+sub cmd_propget {\n+\tmy ($prop, $path) = @_;\n+\t$path = '.' if not defined $path;\n+\tusage(1) if not defined $prop;\n+\tmy $props = get_svnprops($path);\n+\tif (not defined $props->{$prop})\n+\t{\n+\t\tfatal(\"`$path' does not have a `$prop' SVN property.\\n\");\n+\t}\n+\tprint $props->{$prop} . \"\\n\";\n+}\n+\n sub cmd_multi_init {\n \tmy $url = shift;\n \tunless (defined $_trunk || defined $_branches || defined $_tags) {\ndiff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh\nindex 796d80e..61c8799 100755\n--- a/t/t9101-git-svn-props.sh\n+++ b/t/t9101-git-svn-props.sh\n@@ -170,4 +170,27 @@ test_expect_success 'test create-ignore' \"\n \tgit ls-files -s | grep gitignore | cmp - create-ignore-index.expect\n \t\"\n \n+cat >prop.expect <<\\EOF\n+no-such-file*\n+\n+EOF\n+cat >prop2.expect <<\\EOF\n+8\n+EOF\n+\n+# This test can be improved: since all the svn:ignore contain the same\n+# pattern, it can pass even though the propget did not execute on the\n+# right directory.\n+test_expect_success 'test propget' \"\n+\tgit-svn propget svn:ignore . | cmp - prop.expect &&\n+\tcd deeply &&\n+\tgit-svn propget svn:ignore . | cmp - ../prop.expect &&\n+\tgit-svn propget svn:entry:committed-rev nested/directory/.keep \\\n+\t  | cmp - ../prop2.expect &&\n+\tgit-svn propget svn:ignore .. | cmp - ../prop.expect &&\n+\tgit-svn propget svn:ignore nested/ | cmp - ../prop.expect &&\n+\tgit-svn propget svn:ignore ./nested | cmp - ../prop.expect &&\n+\tgit-svn propget svn:ignore .././deeply/nested | cmp - ../prop.expect\n+\t\"\n+\n test_done\n-- \n1.5.3.4.214.g6f43\n"},{"id":"56047","messageId":"1192462506-3783-4-git-send-email-tsuna@lrde.epita.fr","threadId":"10309","inReplyTo":"1192462506-3783-3-git-send-email-tsuna@lrde.epita.fr","subject":"[PATCH 4/5] Add git svn proplist.","fromName":"Benoit Sigoure","fromEmail":"tsuna@lrde.epita.fr","sentAt":"2007-10-15T15:35:05Z","receivedAt":"2007-10-15T15:35:05Z","isPatch":true,"sender":{"key":"tsunanet@gmail.com","avatar":"https://avatars.githubusercontent.com/u/128281?v=4"},"body":"\t* git-svn.perl (%cmd): Add the command `proplist'.\n\t(&cmd_proplist): New.\n\t* t/t9101-git-svn-props.sh: Test git svn proplist.\n\nSigned-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>\n---\n git-svn.perl             |   17 +++++++++++++++++\n t/t9101-git-svn-props.sh |   21 +++++++++++++++++++++\n 2 files changed, 38 insertions(+), 0 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex e58ff38..466fdd3 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -132,6 +132,9 @@ my %cmd = (\n         'propget' => [ \\&cmd_propget,\n \t\t       'Print the value of a property on a file or directory',\n \t\t       { 'revision|r=i' => \\$_revision } ],\n+        'proplist' => [ \\&cmd_proplist,\n+\t\t       'List all properties of a file or directory',\n+\t\t       { 'revision|r=i' => \\$_revision } ],\n \t'show-ignore' => [ \\&cmd_show_ignore, \"Show svn:ignore listings\",\n \t\t\t{ 'revision|r=i' => \\$_revision\n \t\t\t} ],\n@@ -583,6 +586,20 @@ sub cmd_propget {\n \tprint $props->{$prop} . \"\\n\";\n }\n \n+# cmd_proplist (PATH)\n+# -------------------\n+# Print the list of SVN properties for PATH.\n+sub cmd_proplist {\n+\tmy $path = shift;\n+\t$path = '.' if not defined $path;\n+\tmy $props = get_svnprops($path);\n+\tprint \"Properties on '$path':\\n\";\n+\tforeach (sort keys %{$props})\n+\t{\n+\t\tprint \"  $_\\n\";\n+\t}\n+}\n+\n sub cmd_multi_init {\n \tmy $url = shift;\n \tunless (defined $_trunk || defined $_branches || defined $_tags) {\ndiff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh\nindex 61c8799..3c83127 100755\n--- a/t/t9101-git-svn-props.sh\n+++ b/t/t9101-git-svn-props.sh\n@@ -193,4 +193,25 @@ test_expect_success 'test propget' \"\n \tgit-svn propget svn:ignore .././deeply/nested | cmp - ../prop.expect\n \t\"\n \n+cat >prop.expect <<\\EOF\n+Properties on '.':\n+  svn:entry:committed-date\n+  svn:entry:committed-rev\n+  svn:entry:last-author\n+  svn:entry:uuid\n+  svn:ignore\n+EOF\n+cat >prop2.expect <<\\EOF\n+Properties on 'nested/directory/.keep':\n+  svn:entry:committed-date\n+  svn:entry:committed-rev\n+  svn:entry:last-author\n+  svn:entry:uuid\n+EOF\n+\n+test_expect_success 'test proplist' \"\n+\tgit-svn proplist . | cmp - prop.expect &&\n+\tgit-svn proplist nested/directory/.keep | cmp - prop2.expect\n+\t\"\n+\n test_done\n-- \n1.5.3.4.214.g6f43\n"},{"id":"56045","messageId":"1192462506-3783-5-git-send-email-tsuna@lrde.epita.fr","threadId":"10309","inReplyTo":"1192462506-3783-4-git-send-email-tsuna@lrde.epita.fr","subject":"[PATCH 5/5] Simplify the handling of fatal errors.","fromName":"Benoit Sigoure","fromEmail":"tsuna@lrde.epita.fr","sentAt":"2007-10-15T15:35:06Z","receivedAt":"2007-10-15T15:35:06Z","isPatch":true,"sender":{"key":"tsunanet@gmail.com","avatar":"https://avatars.githubusercontent.com/u/128281?v=4"},"body":"\t* git-svn.perl (&fatal): Append the newline at the end of the error\n\tmessage.\n\tAdjust all callers.\n\nSigned-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>\n---\n git-svn.perl |   42 +++++++++++++++++++++---------------------\n 1 files changed, 21 insertions(+), 21 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 466fdd3..1a6aa14 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -21,12 +21,12 @@ $Git::SVN::Log::TZ = $ENV{TZ};\n $ENV{TZ} = 'UTC';\n $| = 1; # unbuffer STDOUT\n \n-sub fatal (@) { print STDERR @_; exit 1 }\n+sub fatal (@) { print STDERR \"@_\\n\"; exit 1 }\n require SVN::Core; # use()-ing this causes segfaults for me... *shrug*\n require SVN::Ra;\n require SVN::Delta;\n if ($SVN::Core::VERSION lt '1.1.0') {\n-\tfatal \"Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)\\n\";\n+\tfatal \"Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)\";\n }\n push @Git::SVN::Ra::ISA, 'SVN::Ra';\n push @SVN::Git::Editor::ISA, 'SVN::Delta::Editor';\n@@ -369,7 +369,7 @@ sub cmd_set_tree {\n \t\t} elsif (scalar @tmp > 1) {\n \t\t\tpush @revs, reverse(command('rev-list',@tmp));\n \t\t} else {\n-\t\t\tfatal \"Failed to rev-parse $c\\n\";\n+\t\t\tfatal \"Failed to rev-parse $c\";\n \t\t}\n \t}\n \tmy $gs = Git::SVN->new;\n@@ -379,7 +379,7 @@ sub cmd_set_tree {\n \t\tfatal \"There are new revisions that were fetched \",\n \t\t      \"and need to be merged (or acknowledged) \",\n \t\t      \"before committing.\\nlast rev: $r_last\\n\",\n-\t\t      \" current: $gs->{last_rev}\\n\";\n+\t\t      \" current: $gs->{last_rev}\";\n \t}\n \t$gs->set_tree($_) foreach @revs;\n \tprint \"Done committing \",scalar @revs,\" revisions to SVN\\n\";\n@@ -408,7 +408,7 @@ sub cmd_dcommit {\n \t\t\t(undef, $last_rev, undef) = cmt_metadata(\"$d~1\");\n \t\t\tunless (defined $last_rev) {\n \t\t\t\tfatal \"Unable to extract revision information \",\n-\t\t\t\t      \"from commit $d~1\\n\";\n+\t\t\t\t      \"from commit $d~1\";\n \t\t\t}\n \t\t}\n \t\tif ($_dry_run) {\n@@ -521,7 +521,7 @@ sub cmd_create_ignore {\n \t\tmy $ignore = '.' . $path . '.gitignore';\n \t\tmy $s = $props->{'svn:ignore'} or return;\n \t\topen(GITIGNORE, '>', $ignore)\n-\t\t  or fatal(\"Failed to open `$ignore' for writing: $!\\n\");\n+\t\t  or fatal(\"Failed to open `$ignore' for writing: $!\");\n \t\t$s =~ s/[\\r\\n]+/\\n/g;\n \t\tchomp $s;\n \t\t# Prefix all patterns so that the ignore doesn't apply\n@@ -529,7 +529,7 @@ sub cmd_create_ignore {\n \t\t$s =~ s#^#/#gm;\n \t\tprint GITIGNORE \"$s\\n\";\n \t\tclose(GITIGNORE)\n-\t\t  or fatal(\"Failed to close `$ignore': $!\\n\");\n+\t\t  or fatal(\"Failed to close `$ignore': $!\");\n \t\tcommand_noisy('add', $ignore);\n \t});\n }\n@@ -545,7 +545,7 @@ sub get_svnprops {\n \t# prefix THE PATH by the sub-directory from which the user\n \t# invoked us.\n \t$path = $cmd_dir_prefix . $path;\n-\tfatal(\"No such file or directory: $path\\n\") unless -e $path;\n+\tfatal(\"No such file or directory: $path\") unless -e $path;\n \tmy $is_dir = -d $path ? 1 : 0;\n \t$path = $gs->{path} . '/' . $path;\n \n@@ -581,7 +581,7 @@ sub cmd_propget {\n \tmy $props = get_svnprops($path);\n \tif (not defined $props->{$prop})\n \t{\n-\t\tfatal(\"`$path' does not have a `$prop' SVN property.\\n\");\n+\t\tfatal(\"`$path' does not have a `$prop' SVN property.\");\n \t}\n \tprint $props->{$prop} . \"\\n\";\n }\n@@ -646,7 +646,7 @@ sub cmd_multi_fetch {\n sub cmd_commit_diff {\n \tmy ($ta, $tb, $url) = @_;\n \tmy $usage = \"Usage: $0 commit-diff -r<revision> \".\n-\t            \"<tree-ish> <tree-ish> [<URL>]\\n\";\n+\t            \"<tree-ish> <tree-ish> [<URL>]\";\n \tfatal($usage) if (!defined $ta || !defined $tb);\n \tmy $svn_path;\n \tif (!defined $url) {\n@@ -664,7 +664,7 @@ sub cmd_commit_diff {\n \tif (defined $_message && defined $_file) {\n \t\tfatal(\"Both --message/-m and --file/-F specified \",\n \t\t      \"for the commit message.\\n\",\n-\t\t      \"I have no idea what you mean\\n\");\n+\t\t      \"I have no idea what you mean\");\n \t}\n \tif (defined $_file) {\n \t\t$_message = file_to_s($_file);\n@@ -727,7 +727,7 @@ sub complete_svn_url {\n \tif ($path !~ m#^[a-z\\+]+://#) {\n \t\tif (!defined $url || $url !~ m#^[a-z\\+]+://#) {\n \t\t\tfatal(\"E: '$path' is not a complete URL \",\n-\t\t\t      \"and a separate URL is not specified\\n\");\n+\t\t\t      \"and a separate URL is not specified\");\n \t\t}\n \t\treturn ($url, $path);\n \t}\n@@ -748,7 +748,7 @@ sub complete_url_ls_init {\n \t\t$repo_path =~ s#^/+##;\n \t\tunless ($ra) {\n \t\t\tfatal(\"E: '$repo_path' is not a complete URL \",\n-\t\t\t      \"and a separate URL is not specified\\n\");\n+\t\t\t      \"and a separate URL is not specified\");\n \t\t}\n \t}\n \tmy $url = $ra->{url};\n@@ -1755,7 +1755,7 @@ sub assert_index_clean {\n \t\t$x = command_oneline('write-tree');\n \t\tif ($y ne $x) {\n \t\t\t::fatal \"trees ($treeish) $y != $x\\n\",\n-\t\t\t        \"Something is seriously wrong...\\n\";\n+\t\t\t        \"Something is seriously wrong...\";\n \t\t}\n \t});\n }\n@@ -2181,7 +2181,7 @@ sub set_tree {\n \tmy ($self, $tree) = (shift, shift);\n \tmy $log_entry = ::get_commit_entry($tree);\n \tunless ($self->{last_rev}) {\n-\t\tfatal(\"Must have an existing revision to commit\\n\");\n+\t\tfatal(\"Must have an existing revision to commit\");\n \t}\n \tmy %ed_opts = ( r => $self->{last_rev},\n \t                log => $log_entry->{log},\n@@ -3131,7 +3131,7 @@ sub apply_diff {\n \t\tif (defined $o{$f}) {\n \t\t\t$self->$f($m);\n \t\t} else {\n-\t\t\tfatal(\"Invalid change type: $f\\n\");\n+\t\t\tfatal(\"Invalid change type: $f\");\n \t\t}\n \t}\n \t$self->rmdirs if $_rmdir;\n@@ -3739,15 +3739,15 @@ sub config_pager {\n sub run_pager {\n \treturn unless -t *STDOUT && defined $pager;\n \tpipe my $rfd, my $wfd or return;\n-\tdefined(my $pid = fork) or ::fatal \"Can't fork: $!\\n\";\n+\tdefined(my $pid = fork) or ::fatal \"Can't fork: $!\";\n \tif (!$pid) {\n \t\topen STDOUT, '>&', $wfd or\n-\t\t                     ::fatal \"Can't redirect to stdout: $!\\n\";\n+\t\t                     ::fatal \"Can't redirect to stdout: $!\";\n \t\treturn;\n \t}\n-\topen STDIN, '<&', $rfd or ::fatal \"Can't redirect stdin: $!\\n\";\n+\topen STDIN, '<&', $rfd or ::fatal \"Can't redirect stdin: $!\";\n \t$ENV{LESS} ||= 'FRSX';\n-\texec $pager or ::fatal \"Can't run pager: $! ($pager)\\n\";\n+\texec $pager or ::fatal \"Can't run pager: $! ($pager)\";\n }\n \n sub tz_to_s_offset {\n@@ -3883,7 +3883,7 @@ sub cmd_show_log {\n \t\t\t$r_min = $r_max = $::_revision;\n \t\t} else {\n \t\t\t::fatal \"-r$::_revision is not supported, use \",\n-\t\t\t\t\"standard \\'git log\\' arguments instead\\n\";\n+\t\t\t\t\"standard 'git log' arguments instead\";\n \t\t}\n \t}\n \n-- \n1.5.3.4.214.g6f43\n"},{"id":"55973","messageId":"20071016074310.GA32254@soma","threadId":"10309","inReplyTo":"1192462506-3783-1-git-send-email-tsuna@lrde.epita.fr","subject":"Re: [PATCH 1/5] Add a generic tree traversal to fetch SVN properties.","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2007-10-16T07:43:10Z","receivedAt":"2007-10-16T07:43:10Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Benoit Sigoure <tsuna@lrde.epita.fr> wrote:\n> \t* git-svn.perl (&traverse_ignore): Remove.\n> \t(&prop_walk): New.\n> \t(&cmd_show_ignore): Use prop_walk.\n> \n> Signed-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>\n\nAlthough I myself have never needed this functionality, this series\nlooks pretty good in general.\n\nThanks.\n\nOne comment below about property selection (whitelist vs blacklist).\n\n\nIt would be possible to get identical information out of unhandled.log,\nbut older repositories may not have complete information...  Maybe some\nlocal option would be good for people with complete unhandled.log files;\nbut it could be really incomplete/insufficient.\n\n\nI'm not sure about 5/5, it's purely a style issue, however I don't\nreally feel strongly about a trailing \"\\n\" either way...  Nevertheless,\nit is definitely not part of this series and should be treated\nindependently.\n\n\nCoding style\n\nOther than that, I prefer to keep braces on the same line as foreach,\nif, else statements.  I generally follow the git and Linux coding\nstyle for C in my Perl code.\n\nOne exception that I make for Perl (but not C) is that I keep the \"{\"\nfor subs on the same line (since subs can be nested and anonymous ones\npassed as arguments and such); unlike their C counterparts[1]\n\n[1] - well, nesting functions is allowed in C99 or GNU C, I can't\n      remember which or both...\n\n> ---\n>  git-svn.perl |   66 ++++++++++++++++++++++++++++++++++++++++-----------------\n>  1 files changed, 46 insertions(+), 20 deletions(-)\n> \n> diff --git a/git-svn.perl b/git-svn.perl\n> index 777e436..abc83ec 100755\n> --- a/git-svn.perl\n> +++ b/git-svn.perl\n> @@ -488,7 +488,15 @@ sub cmd_show_ignore {\n>  \tmy ($url, $rev, $uuid, $gs) = working_head_info('HEAD');\n>  \t$gs ||= Git::SVN->new;\n>  \tmy $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);\n> -\t$gs->traverse_ignore(\\*STDOUT, $gs->{path}, $r);\n> +\t$gs->prop_walk($gs->{path}, $r, sub {\n> +\t\tmy ($gs, $path, $props) = @_;\n> +\t\tprint STDOUT \"\\n# $path\\n\";\n> +\t\tmy $s = $props->{'svn:ignore'} or return;\n> +\t\t$s =~ s/[\\r\\n]+/\\n/g;\n> +\t\tchomp $s;\n> +\t\t$s =~ s#^#$path#gm;\n> +\t\tprint STDOUT \"$s\\n\";\n> +\t});\n>  }\n>  \n>  sub cmd_multi_init {\n> @@ -1480,28 +1488,46 @@ sub rel_path {\n>  \t$url;\n>  }\n>  \n> -sub traverse_ignore {\n> -\tmy ($self, $fh, $path, $r) = @_;\n> -\t$path =~ s#^/+##g;\n> -\tmy $ra = $self->ra;\n> -\tmy ($dirent, undef, $props) = $ra->get_dir($path, $r);\n> +# prop_walk(PATH, REV, SUB)\n> +# -------------------------\n> +# Recursively traverse PATH at revision REV and invoke SUB for each\n> +# directory that contains a SVN property.  SUB will be invoked as\n> +# follows:  &SUB(gs, path, props);  where `gs' is this instance of\n> +# Git::SVN, `path' the path to the directory where the properties\n> +# `props' were found.  The `path' will be relative to point of checkout,\n> +# that is, if url://repo/trunk is the current Git branch, and that\n> +# directory contains a sub-directory `d', SUB will be invoked with `/d/'\n> +# as `path' (note the trailing `/').\n> +sub prop_walk {\n> +\tmy ($self, $path, $rev, $sub) = @_;\n> +\n> +\tmy ($dirent, undef, $props) = $self->ra->get_dir($path, $rev);\n> +\t$path =~ s#^/*#/#g;\n>  \tmy $p = $path;\n> -\t$p =~ s#^\\Q$self->{path}\\E(/|$)##;\n> -\tprint $fh length $p ? \"\\n# $p\\n\" : \"\\n# /\\n\";\n> -\tif (my $s = $props->{'svn:ignore'}) {\n> -\t\t$s =~ s/[\\r\\n]+/\\n/g;\n> -\t\tchomp $s;\n> -\t\tif (length $p == 0) {\n> -\t\t\t$s =~ s#\\n#\\n/$p#g;\n> -\t\t\tprint $fh \"/$s\\n\";\n> -\t\t} else {\n> -\t\t\t$s =~ s#\\n#\\n/$p/#g;\n> -\t\t\tprint $fh \"/$p/$s\\n\";\n> -\t\t}\n> -\t}\n> +\t# Strip the irrelevant part of the path.\n> +\t$p =~ s#^/+\\Q$self->{path}\\E(/|$)#/#;\n> +\t# Ensure the path is terminated by a `/'.\n> +\t$p =~ s#/*$#/#;\n> +\n> +\t# The properties contain all the internal SVN stuff nobody\n> +\t# (usually) cares about.\n\nHow about having a blacklist (for the author, date, log, uuid?) instead\nof a whitelist?  I can't remember all of them that should be blacklisted,\n but maybe it's just author, date and log)..\n\n> +\tmy $interesting_props = 0;\n> +\tforeach(keys %{$props})\n> +\t{\n> +\t\t# If it doesn't start with `svn:', it must be a\n> +\t\t# user-defined property.\n> +\t\t++$interesting_props and next if $_ !~ /^svn:/;\n> +\t\t# FIXME: Fragile, if SVN adds new public properties,\n> +\t\t# this needs to be updated.\n> +\t\t++$interesting_props if /^svn:(?:ignore|keywords|executable\n> +\t\t                                 |eol-style|mime-type\n> +\t\t\t\t\t\t |externals|needs-lock)$/x;\n> +\t}\n> +\t&$sub($self, $p, $props) if $interesting_props;\n> +\n>  \tforeach (sort keys %$dirent) {\n>  \t\tnext if $dirent->{$_}->{kind} != $SVN::Node::dir;\n> -\t\t$self->traverse_ignore($fh, \"$path/$_\", $r);\n> +\t\t$self->prop_walk($path . '/' . $_, $rev, $sub);\n>  \t}\n>  }\n\n-- \nEric Wong\n"},{"id":"55997","messageId":"07B09A42-73DD-4565-975F-A4E40BF862AC@lrde.epita.fr","threadId":"10309","inReplyTo":"20071016074310.GA32254@soma","subject":"Re: [PATCH 1/5] Add a generic tree traversal to fetch SVN properties.","fromName":"Benoit SIGOURE","fromEmail":"tsuna@lrde.epita.fr","sentAt":"2007-10-16T09:35:09Z","receivedAt":"2007-10-16T09:35:09Z","isPatch":true,"sender":{"key":"tsunanet@gmail.com","avatar":"https://avatars.githubusercontent.com/u/128281?v=4"},"body":"On Oct 16, 2007, at 9:43 AM, Eric Wong wrote:\n\n> Benoit Sigoure <tsuna@lrde.epita.fr> wrote:\n>> \t* git-svn.perl (&traverse_ignore): Remove.\n>> \t(&prop_walk): New.\n>> \t(&cmd_show_ignore): Use prop_walk.\n>>\n>> Signed-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>\n>\n> Although I myself have never needed this functionality, this series\n> looks pretty good in general.\n\nI heavily script Git with my own wrappers and having this sort if  \nfunctionality does enhance the scriptability of git-svn.\n\n>\n> Thanks.\n\nYou're welcome :)\n\n>\n> One comment below about property selection (whitelist vs blacklist).\n>\n>\n> It would be possible to get identical information out of  \n> unhandled.log,\n> but older repositories may not have complete information...  Maybe  \n> some\n> local option would be good for people with complete unhandled.log  \n> files;\n> but it could be really incomplete/insufficient.\n>\n\nIn order to avoid using SVN::Ra and avoid access to the SVN repo?   \nHmm, clever, I didn't think about this.  Maybe we can provide both,  \nthe default would check unhandled.log and an option would enable  \ndirect access to the SVN repo?\n\n>\n> I'm not sure about 5/5, it's purely a style issue, however I don't\n> really feel strongly about a trailing \"\\n\" either way...   \n> Nevertheless,\n> it is definitely not part of this series and should be treated\n> independently.\n>\n\nIndeed.\n\n>\n> Coding style\n>\n> Other than that, I prefer to keep braces on the same line as foreach,\n> if, else statements.  I generally follow the git and Linux coding\n> style for C in my Perl code.\n>\n> One exception that I make for Perl (but not C) is that I keep the \"{\"\n> for subs on the same line (since subs can be nested and anonymous ones\n> passed as arguments and such); unlike their C counterparts[1]\n\nIndeed, sorry, I started correctly but then completely forgot to  \nfollow the existing Coding Style.  The CS I use daily is totally  \ndifferent, sorry ;)\nShall I resend the patch series with corrected CS?\n\n>\n> [1] - well, nesting functions is allowed in C99 or GNU C, I can't\n>       remember which or both...\n>\n\nGNU C, AFAIR.\n\n>> ---\n>>  git-svn.perl |   66 +++++++++++++++++++++++++++++++++++++++ \n>> +-----------------\n>>  1 files changed, 46 insertions(+), 20 deletions(-)\n>>\n>> diff --git a/git-svn.perl b/git-svn.perl\n>> index 777e436..abc83ec 100755\n>> --- a/git-svn.perl\n>> +++ b/git-svn.perl\n[...]\n>\n> How about having a blacklist (for the author, date, log, uuid?)  \n> instead\n> of a whitelist?  I can't remember all of them that should be  \n> blacklisted,\n>  but maybe it's just author, date and log)..\n>\n>> +\tmy $interesting_props = 0;\n>> +\tforeach(keys %{$props})\n>> +\t{\n>> +\t\t# If it doesn't start with `svn:', it must be a\n>> +\t\t# user-defined property.\n>> +\t\t++$interesting_props and next if $_ !~ /^svn:/;\n>> +\t\t# FIXME: Fragile, if SVN adds new public properties,\n>> +\t\t# this needs to be updated.\n>> +\t\t++$interesting_props if /^svn:(?:ignore|keywords|executable\n>> +\t\t                                 |eol-style|mime-type\n>> +\t\t\t\t\t\t |externals|needs-lock)$/x;\n>> +\t}\n\nWhy not.  I thought that the SVN internals were more subject to  \nchange than the public \"interface\", hence the check.\n\n>> +\t&$sub($self, $p, $props) if $interesting_props;\n>> +\n\nPS: For some reason, the introduction message didn't make its way to  \nthe ML.  I made a mistake when sending it because I first ran git  \nsend-email --compose, then noticed that it sent only one mail, and  \nran git send-email *.patch afterwards.  Weird.\n\nCheers,\n\n-- \nBenoit Sigoure aka Tsuna\nEPITA Research and Development Laboratory\n\n\n"},{"id":"56000","messageId":"20071016095503.GB30503@soma","threadId":"10309","inReplyTo":"07B09A42-73DD-4565-975F-A4E40BF862AC@lrde.epita.fr","subject":"Re: [PATCH 1/5] Add a generic tree traversal to fetch SVN properties.","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2007-10-16T09:55:03Z","receivedAt":"2007-10-16T09:55:03Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Benoit SIGOURE <tsuna@lrde.epita.fr> wrote:\n> On Oct 16, 2007, at 9:43 AM, Eric Wong wrote:\n> \n> >Benoit Sigoure <tsuna@lrde.epita.fr> wrote:\n> >>\t* git-svn.perl (&traverse_ignore): Remove.\n> >>\t(&prop_walk): New.\n> >>\t(&cmd_show_ignore): Use prop_walk.\n> >>\n> >>Signed-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>\n> >\n> >Although I myself have never needed this functionality, this series\n> >looks pretty good in general.\n> \n> I heavily script Git with my own wrappers and having this sort if  \n> functionality does enhance the scriptability of git-svn.\n\nAh.  I've actually wanted something like `svn info` or `git-svn\nrev-parse` myself for a while, but haven't gotten to implementing it\nmyself, either.  Something that could easily give me the current URL of\na repo, or the URL of any path in a repo\n\n\t$ git svn info --remote-url local/path.c\n\t=> https://example.com/svn/trunk/local/path.c\n\n\t$ git svn info --url\n\t=> https://example.com/svn/trunk\n\nI think there was other functionality that I've wanted in the past\nbut have forgotten at the moment.  I need to sleep, badly :x\n\n> >Thanks.\n> \n> You're welcome :)\n> \n> >\n> >One comment below about property selection (whitelist vs blacklist).\n> >\n> >\n> >It would be possible to get identical information out of  \n> >unhandled.log,\n> >but older repositories may not have complete information...  Maybe  \n> >some\n> >local option would be good for people with complete unhandled.log  \n> >files;\n> >but it could be really incomplete/insufficient.\n> >\n> \n> In order to avoid using SVN::Ra and avoid access to the SVN repo?   \n> Hmm, clever, I didn't think about this.  Maybe we can provide both,  \n> the default would check unhandled.log and an option would enable  \n> direct access to the SVN repo?\n\nYes.  I'm alright with the direct SVN repo code for now, and we can do\nunhandled.log later since it's more things to do.\n\n> >Coding style\n> >\n> >Other than that, I prefer to keep braces on the same line as foreach,\n> >if, else statements.  I generally follow the git and Linux coding\n> >style for C in my Perl code.\n> >\n> >One exception that I make for Perl (but not C) is that I keep the \"{\"\n> >for subs on the same line (since subs can be nested and anonymous ones\n> >passed as arguments and such); unlike their C counterparts[1]\n> \n> Indeed, sorry, I started correctly but then completely forgot to  \n> follow the existing Coding Style.  The CS I use daily is totally  \n> different, sorry ;)\n> Shall I resend the patch series with corrected CS?\n\nYes, please.  Thanks.\n\n-- \nEric Wong\n"}]}