Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Message from discussion Honor SVN auto-props (solves issue #186)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Ronny Voelker  
View profile  
 More options May 14 2012, 3:14 pm
From: Ronny Voelker <ronny.voel...@googlemail.com>
Date: Mon, 14 May 2012 21:14:51 +0200
Local: Mon, May 14 2012 3:14 pm
Subject: [PATCH] Honor SVN auto-props (solves issue #186)
# HG changeset patch
# User Ronny Voelker <ronny.voel...@googlemail.com>
# Date 1325429955 -3600
# Node ID 3587420f3d1633c269585889b7647ecf8d9faa79
# Parent  bd12a4da0f35b5d04ed7cffe262d6298a5169c5d
Honor SVN auto-props (solves issue #186)

The implementation completely ignores the subversion bindings,
because the current bindings provide little support for this functionality.

diff -r bd12a4da0f35 -r 3587420f3d16 hgsubversion/pushmod.py
--- a/hgsubversion/pushmod.py   Sun May 13 15:28:50 2012 +0200
+++ b/hgsubversion/pushmod.py   Sun Jan 01 15:59:15 2012 +0100
@@ -133,6 +133,9 @@
                     # this kind of renames: a -> b, b -> c
                     copies[file] = renamed[0]
                     base_data = parent[renamed[0]].data()
+                else:
+                    props.setdefault(file, {}).update(
+                        svn.autoprops_config.properties(file))

                 action = 'add'
                 dirname = '/'.join(file.split('/')[:-1] + [''])
diff -r bd12a4da0f35 -r 3587420f3d16 hgsubversion/svnwrap/common.py
--- a/hgsubversion/svnwrap/common.py    Sun May 13 15:28:50 2012 +0200
+++ b/hgsubversion/svnwrap/common.py    Sun Jan 01 15:59:15 2012 +0100
@@ -8,6 +8,10 @@
 import urlparse
 import urllib
 import collections
+import fnmatch
+import ConfigParser
+import sys
+import os

 class SubversionRepoCanNotReplay(Exception):
     """Exception raised when the svn server is too old to have replay.
@@ -78,3 +82,72 @@

     def __str__(self):
         return 'r%d by %s' % (self.revnum, self.author)
+
+
+svn_config_dir = None
+
+
+def set_svn_config_dir(path):
+    global svn_config_dir
+    svn_config_dir = path
+
+
+def get_svn_config_dir():
+    return svn_config_dir
+
+
+class AutoPropsConfig(object):
+    """Provides the subversion auto-props functionality
+       when pushing new files.
+    """
+    def __init__(self, config_dir=None):
+        config_file = config_file_path(config_dir)
+        self.config = ConfigParser.RawConfigParser()
+        self.config.read([config_file])
+
+    def properties(self, file):
+        """Returns a dictionary of the auto-props applicable for file.
+           Takes enable-auto-props into account.
+        """
+        properties = {}
+        if self.autoprops_enabled():
+            for pattern,prop_list in self.config.items('auto-props'):
+                if fnmatch.fnmatchcase(os.path.basename(file), pattern):
+                    properties.update(parse_autoprops(prop_list))
+        return properties
+
+    def autoprops_enabled(self):
+        return (self.config.has_option('miscellany', 'enable-auto-props')
+        and self.config.getboolean( 'miscellany', 'enable-auto-props')
+        and self.config.has_section('auto-props'))
+
+
+def config_file_path(config_dir):
+    if config_dir == None:
+        if sys.platform == 'win32':
+            config_dir = os.environ['APPDATA'] + '/Subversion'
+        else:
+            config_dir = os.environ['HOME'] + '/.subversion'
+    return config_dir + '/config'
+
+
+def parse_autoprops(prop_list):
+    """Parses a string of autoprops and returns a dictionary of
+       the results.
+       Emulates the parsing of core.auto_props_enumerator.
+    """
+    def unquote(s):
+        if len(s)>1 and s[0] in ['"', "'"] and s[0]==s[-1]:
+            return s[1:-1]
+        return s
+
+    properties = {}
+    for prop in prop_list.split(';'):
+        if '=' in prop:
+            prop, value = prop.split('=',1)
+            value = unquote(value.strip())
+        else:
+            value = ''
+        properties[prop.strip()] = value
+    return properties
+
diff -r bd12a4da0f35 -r 3587420f3d16 hgsubversion/svnwrap/subvertpy_wrapper.py
--- a/hgsubversion/svnwrap/subvertpy_wrapper.py Sun May 13 15:28:50 2012 +0200
+++ b/hgsubversion/svnwrap/subvertpy_wrapper.py Sun Jan 01 15:59:15 2012 +0100
@@ -191,6 +191,7 @@
         # expects unquoted paths
         self.subdir = urllib.unquote(self.subdir)
         self.hasdiff3 = True
+        self.autoprops_config = common.AutoPropsConfig(common.svn_config_dir)

     def init_ra_and_client(self):
         """
diff -r bd12a4da0f35 -r 3587420f3d16 hgsubversion/svnwrap/svn_swig_wrapper.py
--- a/hgsubversion/svnwrap/svn_swig_wrapper.py  Sun May 13 15:28:50 2012 +0200
+++ b/hgsubversion/svnwrap/svn_swig_wrapper.py  Sun Jan 01 15:59:15 2012 +0100
@@ -184,6 +184,7 @@
         # expects unquoted paths
         self.subdir = urllib.unquote(self.subdir)
         self.hasdiff3 = True
+        self.autoprops_config = common.AutoPropsConfig(common.svn_config_dir)

     def init_ra_and_client(self):
         """Initializes the RA and client layers, because sometimes getting
diff -r bd12a4da0f35 -r 3587420f3d16 tests/run.py
--- a/tests/run.py      Sun May 13 15:28:50 2012 +0200
+++ b/tests/run.py      Sun Jan 01 15:59:15 2012 +0100
@@ -23,6 +23,7 @@
     import test_push_renames
     import test_push_dirs
     import test_push_eol
+    import test_push_autoprops
     import test_rebuildmeta
     import test_single_dir_clone
     import test_svnwrap
diff -r bd12a4da0f35 -r 3587420f3d16 tests/test_push_autoprops.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_push_autoprops.py      Sun Jan 01 15:59:15 2012 +0100
@@ -0,0 +1,124 @@
+import subprocess
+import sys
+import unittest
+import os
+
+import test_util
+
+from hgsubversion import svnwrap
+
+class PushAutoPropsTests(test_util.TestBase):
+    def setUp(self):
+        test_util.TestBase.setUp(self)
+        self.config_dir = self.tmpdir
+        svnwrap.set_svn_config_dir(self.config_dir)
+        self.setup_svn_config('')
+        repo, self.repo_path = self.load_and_fetch('emptyrepo.svndump')
+
+    def test_push_honors_svn_autoprops(self):
+        self.setup_svn_config(
+            "[miscellany]\n"
+            "enable-auto-props = yes\n"
+            "[auto-props]\n"
+            "*.py = test:prop=success\n")
+        changes = [('test.py', 'test.py', 'echo hallo')]
+        self.commitchanges(changes)
+        self.pushrevisions(True)
+        prop_val = test_util.svnpropget(
+            self.repo_path, "trunk/test.py", 'test:prop')
+        self.assertEqual('success', prop_val)
+
+    def setup_svn_config(self, config):
+        with open(self.config_dir + '/config', 'w') as c:
+            c.write(config)
+
+    def tearDown(self):
+        test_util.TestBase.tearDown(self)
+        svnwrap.set_svn_config_dir(None)
+
+
+class AutoPropsConfigTest(test_util.TestBase):
+    def setUp(self):
+        test_util.TestBase.setUp(self)
+        self.config_dir = self.tmpdir
+
+    def test_use_autoprops_for_matching_file_when_enabled(self):
+        self.setup_svn_config(
+            "[miscellany]\n"
+            "enable-auto-props = yes\n"
+            "[auto-props]\n"
+            "*.py = test:prop=success\n")
+        props = self.new_autoprops_config().properties('xxx/test.py')
+        self.assertEqual({ 'test:prop': 'success'}, props)
+
+    def setup_svn_config(self, config):
+        with open(self.config_dir + '/config', 'w') as c:
+            c.write(config)
+
+    def new_autoprops_config(self):
+        return svnwrap.AutoPropsConfig(self.config_dir)
+
+    def test_ignore_nonexisting_config(self):
+        self.assertTrue(not os.path.exists(self.config_dir + '/config'))
+        props = self.new_autoprops_config().properties('xxx/test.py')
+        self.assertEqual({}, props)
+
+    def test_ignore_autoprops_when_file_doesnt_match(self):
+        self.setup_svn_config(
+            "[miscellany]\n"
+            "enable-auto-props = yes\n"
+            "[auto-props]\n"
+            "*.py = test:prop=success\n")
+        props = self.new_autoprops_config().properties('xxx/test.sh')
+        self.assertEqual({}, props)
+
+    def test_ignore_autoprops_when_disabled(self):
+        self.setup_svn_config(
+            "[miscellany]\n"
+            "#enable-auto-props = yes\n"
+            "[auto-props]\n"
+            "*.py = test:prop=success\n")
+        props = self.new_autoprops_config().properties('xxx/test.py')
+        self.assertEqual({}, props)
+
+    def test_combine_properties_of_multiple_matches(self):
+        self.setup_svn_config(
+            "[miscellany]\n"
+            "enable-auto-props = yes\n"
+            "[auto-props]\n"
+            "*.py = test:prop=success\n"
+            "test.* = test:prop2=success\n")
+        props = self.new_autoprops_config().properties('xxx/test.py')
+        self.assertEqual({
+            'test:prop': 'success', 'test:prop2': 'success'}, props)
+
+
+class ParseAutoPropsTests(test_util.TestBase):
+    def test_property_value_is_optional(self):
+        props = svnwrap.parse_autoprops("svn:executable")
+        self.assertEqual({'svn:executable': ''}, props)
+        props = svnwrap.parse_autoprops("svn:executable=")
+        self.assertEqual({'svn:executable': ''}, props)
+
+    def test_property_value_may_be_quoted(self):
+        props = svnwrap.parse_autoprops("svn:eol-style=\" native \"")
+        self.assertEqual({'svn:eol-style': ' native '}, props)
+        props = svnwrap.parse_autoprops("svn:eol-style=' native '")
+        self.assertEqual({'svn:eol-style': ' native '}, props)
+
+    def test_surrounding_whitespaces_are_ignored(self):
+        props = svnwrap.parse_autoprops(" svn:eol-style = native ")
+        self.assertEqual({'svn:eol-style': 'native'}, props)
+
+    def test_multiple_properties_are_separated_by_semicolon(self):
+        props = svnwrap.parse_autoprops(
+            "svn:eol-style=native;svn:executable=true\n")
+        self.assertEqual({
+            'svn:eol-style': 'native',
+            'svn:executable': 'true'},
+            props)
+
+
+def suite():
+    return unittest.findTestCases(sys.modules[__name__])
+


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.