{"thread":{"id":"14532","subject":"PATCH: git-svn -- apply autoprop properties to an upstream svn repository","startedAt":"2008-07-19T07:22:20Z","lastAt":"2008-07-19T07:22:20Z","messageCount":1,"participants":["Paul Talacko"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"83938","messageId":"525224.5527.qm@web27802.mail.ukl.yahoo.com","threadId":"14532","inReplyTo":null,"subject":"PATCH: git-svn -- apply autoprop properties to an upstream svn repository","fromName":"Paul Talacko","fromEmail":"gnuruandstuff@yahoo.co.uk","sentAt":"2008-07-19T07:22:20Z","receivedAt":"2008-07-19T07:22:20Z","isPatch":false,"sender":{"key":"gnuruandstuff@yahoo.co.uk","avatar":null},"body":"Hello,\n\nAs suggested a few days ago, there has been some interest git-svn being able to set properties on upstream svn repositories  This is, for example, necessary for committing new files to subversion repositories hosted on sourceforge where svn:mime-type and svn:eol-style properties have to be set for a commit to succeed.\n\nSo, here's a patch that reads the standard subversion config file and applies the \"auto-props\" to new files being committed to the upstream  repository.  This file is normally in ~/.subversion/config or /etc/subversion/config but this can be overridden with the --config-dir option.\n\nIn this patch, I've decided that to keep it consistent with the svn command line tool, that is that git-svn should read the config file by default, but respect the enable-auto-props config option set in that config file.\n\nAlso, to keep it consistent with the svn command line tool, the patch includes two new command line options --auto-props and --no-auto-props which both override the enable-auto-props config file option.\n\nThe code borrows from SVK::XD, in particular the regexp.  All the SVK code is released under the GPL.\n\nI have also included a test file.\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex a366c89..df06220 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -128,6 +128,8 @@ my %cmd = (\n \t\t\t  'dry-run|n' => \\$_dry_run,\n \t\t\t  'fetch-all|all' => \\$_fetch_all,\n \t\t\t  'no-rebase' => \\$_no_rebase,\n+                          'auto-props' => \\$SVN::Git::Editor::_auto_props,\n+                          'no-auto-props' => \\$SVN::Git::Editor::_no_auto_props,\n \t\t\t%cmt_opts, %fc_opts } ],\n \t'set-tree' => [ \\&cmd_set_tree,\n \t                \"Set an SVN repository to a git tree-ish\",\n@@ -448,8 +450,8 @@ sub cmd_dcommit {\n \t\t\t                log => get_commit_entry($d)->{log},\n \t\t\t                ra => Git::SVN::Ra->new($gs->full_url),\n \t\t\t                config => SVN::Core::config_get_config(\n-\t\t\t                        $Git::SVN::Ra::config_dir\n-\t\t\t                ),\n+\t\t\t\t                $Git::SVN::Ra::config_dir\n+\t\t\t\t\t),\n \t\t\t                tree_a => \"$d~1\",\n \t\t\t                tree_b => $d,\n \t\t\t                editor_cb => sub {\n@@ -3276,7 +3278,7 @@ sub close_edit {\n }\n \n package SVN::Git::Editor;\n-use vars qw/@ISA $_rmdir $_cp_similarity $_find_copies_harder $_rename_limit/;\n+use vars qw/@ISA $_rmdir $_cp_similarity $_find_copies_harder $_rename_limit $_auto_props $_no_auto_props/;\n use strict;\n use warnings;\n use Carp qw/croak/;\n@@ -3309,6 +3311,8 @@ sub new {\n \t$self->{rm} = { };\n \t$self->{path_prefix} = length $self->{svn_path} ?\n \t                       \"$self->{svn_path}/\" : '';\n+\t$self->{config} = $opts->{ra}->{config};\n+        croak \"--auto-props and --no-auto-props are mutually exclusive.\" if $_auto_props && $_no_auto_props;\n \treturn $self;\n }\n \n@@ -3497,6 +3501,86 @@ sub ensure_path {\n \treturn $bat->{$c};\n }\n \n+sub apply_properties {\n+    my ( $self, $fbat, $m ) = @_;\n+    my $config       = $self->{config}->{config}; \n+    my $svn_auto_prop = {};\n+    return if $_no_auto_props;\n+    return if ( ! $_auto_props ) && ( ! $config->get_bool ('miscellany', 'enable-auto-props', 0) );\n+\n+    my $file = $m->{ file_b };\n+\n+    $config->enumerate(\n+        'auto-props',\n+        sub {\n+            $svn_auto_prop->{ compile_apr_fnmatch( $_[0] ) } = $_[1];\n+            1;\n+        }\n+    );\n+    my ( $filebase ) = File::Basename::fileparse( $file );\n+\twhile (my ($pattern, $value) = each %$svn_auto_prop ) {\n+\t    next unless $filebase =~ m/$pattern/;\n+\t    for (split (/\\s*;\\s*/, $value)) {\n+\t\tmy ($propname, $propvalue) = split (/\\s*=\\s*/, $_, 2);\n+\t\t$self->change_file_prop($fbat, $propname, $propvalue); \n+\t    }\n+\t}\n+\n+}\n+\n+\n+## Thanks to SVK::XD and the folks Best Practical Solutions, who in\n+## turn based this on Barrie Slaymaker's Regexp::Shellish\n+sub compile_apr_fnmatch {\n+    my $re = shift;\n+\n+    $re =~ s@\n+             (  \\\\.\n+             |  \\[                       # character class\n+                   [!^]?                 # maybe negation (^ and ! are both supported)\n+                   (?: (?:\\\\.|[^\\\\\\]])   # one item\n+                     (?: -               # possibly followed by a dash and another\n+                       (?:\\\\.|[^\\\\\\]]))? # item\n+                   )*                    # 0 or more entries (zero case will be checked specially below)\n+                (\\]?)                    # if this ] doesn't match, that means we fell off end of string!\n+             |  .\n+            )\n+             @\n+               if ( $1 eq '?' ) {\n+                   '.' ;\n+               } elsif ( $1 eq '*' ) {\n+                   '.*' ;\n+               } elsif ( substr($1, 0, 1) eq '[') {\n+                   if ($1 eq '[]') { # should never match\n+                       '[^\\s\\S]';\n+                   } elsif ($1 eq '[!]' or $1 eq '[^]') { # 0-length match\n+                       '';\n+                   } else {\n+                       my $temp = $1;\n+                       my $failed = $2 eq '';\n+                       if ($failed) {\n+                           '[^\\s\\S]';\n+                       } else {\n+                           $temp =~ s/(\\\\.|.)/$1 eq '-' ? '-' : quotemeta(substr($1, -1))/ges;\n+                           # the previous step puts in backslashes at beginning and end; remove them\n+                           $temp =~ s/^\\\\\\[/[/;\n+                           $temp =~ s/\\\\\\]$/]/;\n+                           # if it started with [^ or [!, it now starts with [\\^ or [\\!; fix.\n+                           $temp =~ s/^\\[     # literal [\n+                                       \\\\     # literal backslash\n+                                       [!^]   # literal ! or ^\n+                                     /[^/x;\n+                           $temp;\n+                       }\n+                   }\n+               } else {\n+                   quotemeta(substr( $1, -1 ) ); # ie, either quote it, or if it's \\x, quote x\n+               }\n+    @gexs ;\n+\n+    return qr/\\A$re\\Z/s;\n+}\n+\n sub A {\n \tmy ($self, $m) = @_;\n \tmy ($dir, $file) = split_path($m->{file_b});\n@@ -3505,6 +3589,7 @@ sub A {\n \t\t\t\t\tundef, -1);\n \tprint \"\\tA\\t$m->{file_b}\\n\" unless $::_q;\n \t$self->chg_file($fbat, $m);\n+\t$self->apply_properties( $fbat, $m );\n \t$self->close_file($fbat,undef,$self->{pool});\n }\n \ndiff --git a/t/t9124-git-svn-autoprops.sh b/t/t9124-git-svn-autoprops.sh\nnew file mode 100644\nindex 0000000..ed78c2d\n--- /dev/null\n+++ b/t/t9124-git-svn-autoprops.sh\n@@ -0,0 +1,123 @@\n+#!/bin/sh\n+#\n+\n+\n+\n+test_description='git-svn dcommit sets autoprops on files'\n+\n+. ./lib-git-svn.sh\n+\n+test_expect_success 'make svn repo' '\n+    mkdir import &&\n+    cd import &&\n+    echo first > firstfile &&\n+    svn import -m \"Import for autoprops test\" . \"$svnrepo\" > /dev/null &&\n+    cd ..  &&\n+    git svn init \"$svnrepo\" &&\n+    git svn fetch\n+'\n+\n+\n+mkdir config\n+cat > config/config <<EOF \n+[miscellany]\n+enable-auto-props = yes\n+[auto-props]\n+*pm =  file-type = perl\n+*html = svn:mime-type = text/html; encoding = special\n+*bar = private = thingy\n+EOF\n+\n+\n+\n+test_expect_success 'set svn properties on files' '\n+        cd \"$gittestrepo\" &&\n+        echo \"blah\" > a.pm &&\n+        echo \"foo\" > b.html &&\n+        echo \"data\" > foobar &&\n+        git add a.pm b.html foobar &&\n+        git commit -m files &&\n+        git svn dcommit --config-dir=config\n+        '\n+\n+test_expect_success 'export our properties to an svn repo' '\n+\n+        mkdir testsvnrepo &&\n+        cd testsvnrepo &&\n+        svn checkout \"$svnrepo\" &&\n+        cd svnrepo\n+        '\n+\n+test_expect_success 'test properties' '\n+        test perl = `svn propget file-type a.pm` &&\n+        test thingy = `svn propget private foobar` &&\n+        test text/html = `svn propget svn:mime-type b.html` &&\n+        test special = `svn propget encoding b.html`\n+\n+        '\n+\n+cd ../..\n+\n+test_expect_success 'no-props overrides config file' '\n+        touch overriden-b.html &&\n+        git add overriden-b.html &&\n+        git commit -m \"overriden-b\" &&\n+        git svn dcommit --no-auto-props --config-dir=config &&\n+        cd testsvnrepo &&\n+        svn checkout \"$svnrepo\" &&\n+        cd svnrepo &&\n+        test -z `svn propget file-type overriden-b.html`\n+'\n+\n+cd ../..\n+\n+cat > config/config <<EOF \n+[miscellany]\n+enable-auto-props = no\n+[auto-props]\n+*pm =  file-type = perl\n+*html = svn:mime-type = text/html; encoding = special\n+*bar = private = thingy\n+EOF\n+\n+\n+test_expect_success 'test when enable-auto-props is no' '\n+        echo \"blah\" > a_no_props.pm &&\n+        echo \"foo\" > b_no_props.html &&\n+        echo \"data\" > foobar_no_props &&\n+        chmod +x foobar_no_props &&\n+        git add a_no_props.pm b_no_props.html foobar_no_props &&\n+        git commit -m \"No props files\" &&\n+        git svn dcommit --config-dir=config &&\n+        cd testsvnrepo &&\n+        svn checkout \"$svnrepo\"  &&\n+        cd svnrepo &&\n+        test -z `svn propget file-type a_no_props.pm` &&\n+        test -z `svn propget private foobar_no_props`  &&\n+        test -z `svn propget svn:mime-type b_no_props.html` &&\n+        test -z `svn propget encoding b_no_props.html`\n+        '\n+\n+cd ../..\n+\n+test_expect_success 'auto-props overrides config file' '\n+        touch overriden-auto.pm &&\n+        git add overriden-auto.pm &&\n+        git commit -m \"overriden-auto\" &&\n+        git svn dcommit --auto-props --config-dir=config &&\n+        cd testsvnrepo &&\n+        svn checkout \"$svnrepo\" &&\n+        cd svnrepo &&\n+        test perl = `svn propget file-type overriden-auto.pm`\n+'\n+cd ../..\n+\n+test_expect_success 'auto-props and no-auto-props are exclusive' '\n+        touch afile &&\n+        git add afile &&\n+        git commit -m afile &&\n+        test_must_fail git svn dcommit --auto-props --no-auto-props\n+'\n+\n+test_done\n+\n\n\n\n      __________________________________________________________\nNot happy with your email address?.\nGet the one you really want - millions of new email addresses available now at Yahoo! http://uk.docs.yahoo.com/ymail/new.html\n"}]}