summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--setuptools/svn_utils.py97
-rw-r--r--setuptools/tests/svn_data/dummy13.zipbin0 -> 9243 bytes
-rw-r--r--setuptools/tests/svn_data/dummy14.zipbin0 -> 7496 bytes
-rw-r--r--setuptools/tests/svn_data/dummy15.zipbin0 -> 7506 bytes
-rw-r--r--setuptools/tests/svn_data/dummy16.zipbin0 -> 7155 bytes
-rw-r--r--setuptools/tests/svn_data/dummy17.zipbin0 -> 7512 bytes
-rw-r--r--setuptools/tests/svn_data/dummy18.zipbin0 -> 7639 bytes
-rw-r--r--setuptools/tests/test_sdist.py82
8 files changed, 123 insertions, 56 deletions
diff --git a/setuptools/svn_utils.py b/setuptools/svn_utils.py
index 55dbb74d..6ac31a24 100644
--- a/setuptools/svn_utils.py
+++ b/setuptools/svn_utils.py
@@ -27,18 +27,18 @@ from subprocess import Popen as _Popen, PIPE as _PIPE
# python-subprocess-popen-environment-path
-def _run_command(args, stdout=_PIPE, stderr=_PIPE):
+def _run_command(args, stdout=_PIPE, stderr=_PIPE, encoding=None, stream=0):
#regarding the shell argument, see: http://bugs.python.org/issue8557
try:
- args = [fsdecode(x) for x in args]
proc = _Popen(args, stdout=stdout, stderr=stderr,
shell=(sys.platform == 'win32'))
- data = proc.communicate()[0]
+ data = proc.communicate()[stream]
except OSError:
return 1, ''
- data = consoledecode(data)
+ #doubled checked and
+ data = decode_as_string(data, encoding)
#communciate calls wait()
return proc.returncode, data
@@ -73,40 +73,28 @@ def joinpath(prefix, *suffix):
return os.path.join(prefix, *suffix)
-def fsencode(path):
- "Path must be unicode or in file system encoding already"
- encoding = sys.getfilesystemencoding()
-
- if isinstance(path, unicode):
- path = path.encode()
- elif not isinstance(path, bytes):
- raise TypeError('%s is not a string or byte type'
- % type(path).__name__)
-
- #getfilessystemencoding doesn't have the mac-roman issue
- if encoding == 'utf-8' and sys.platform == 'darwin':
- path = path.decode('utf-8')
- path = unicodedata.normalize('NFD', path)
- path = path.encode('utf-8')
-
- return path
-
-
-def fsdecode(path):
- "Path must be unicode or in file system encoding already"
- encoding = sys.getfilesystemencoding()
- if isinstance(path, bytes):
- path = path.decode(encoding)
- elif not isinstance(path, unicode):
- raise TypeError('%s is not a byte type'
- % type(path).__name__)
-
- return unicodedata.normalize('NFC', path)
+def decode_as_string(text, encoding=None):
+ """
+ Decode the console or file output explicitly using getpreferredencoding.
+ The text paraemeter should be a encoded string, if not no decode occurs
+ If no encoding is given, getpreferredencoding is used. If encoding is
+ specified, that is used instead. This would be needed for SVN --xml
+ output. Unicode is explicitly put in composed NFC form.
+
+ --xml should be UTF-8 (SVN Issue 2938) the discussion on the Subversion
+ DEV List from 2007 seems to indicate the same.
+ """
+ #text should be a byte string
+ if encoding is None:
+ encoding = locale.getpreferredencoding()
-def consoledecode(text):
- encoding = locale.getpreferredencoding()
- return text.decode(encoding)
+ if not isinstance(text, unicode):
+ text = text.decode(encoding)
+
+ text = unicodedata.normalize('NFC', text)
+
+ return text
def parse_dir_entries(decoded_str):
@@ -141,6 +129,7 @@ def parse_externals_xml(decoded_str, prefix=''):
path = path[len(prefix)+1:]
data = _get_target_property(node)
+ #data should be decoded already
for external in parse_external_prop(data):
externals.append(joinpath(path, external))
@@ -177,6 +166,7 @@ def parse_external_prop(lines):
else:
external = line[-1]
+ external = decode_as_string(external, encoding="utf-8")
externals.append(os.path.normpath(external))
return externals
@@ -214,9 +204,9 @@ class SvnInfo(object):
def get_svn_version():
code, data = _run_command(['svn', '--version', '--quiet'])
if code == 0 and data:
- return unicode(data).strip()
+ return data.strip()
else:
- return unicode('')
+ return ''
#svnversion return values (previous implementations return max revision)
# 4123:4168 mixed revision working copy
@@ -314,7 +304,8 @@ class SvnInfo(object):
class Svn13Info(SvnInfo):
def get_entries(self):
- code, data = _run_command(['svn', 'info', '-R', '--xml', self.path])
+ code, data = _run_command(['svn', 'info', '-R', '--xml', self.path],
+ encoding="utf-8")
if code:
log.debug("svn info failed")
@@ -328,10 +319,11 @@ class Svn13Info(SvnInfo):
cmd = ['svn', 'propget', 'svn:externals']
result = []
for folder in self.iter_dirs():
- code, lines = _run_command(cmd + [folder])
+ code, lines = _run_command(cmd + [folder], encoding="utf-8")
if code != 0:
log.warn("svn propget failed")
return []
+ #lines should a str
for external in parse_external_prop(lines):
if folder:
external = os.path.join(folder, external)
@@ -343,7 +335,7 @@ class Svn13Info(SvnInfo):
class Svn15Info(Svn13Info):
def get_externals(self):
cmd = ['svn', 'propget', 'svn:externals', self.path, '-R', '--xml']
- code, lines = _run_command(cmd)
+ code, lines = _run_command(cmd, encoding="utf-8")
if code:
log.debug("svn propget failed")
return []
@@ -363,6 +355,7 @@ class SvnFileInfo(SvnInfo):
entries = SVNEntriesFile.load(base)
yield (base, False, entries.parse_revision())
for path in entries.get_undeleted_records():
+ path = decode_as_string(path)
path = joinpath(base, path)
if os.path.isfile(path):
yield (path, True, None)
@@ -371,18 +364,17 @@ class SvnFileInfo(SvnInfo):
yield item
def _build_entries(self):
- dirs = list()
- files = list()
+ entries = list()
+
rev = 0
for path, isfile, dir_rev in self._walk_svn(self.path):
if isfile:
- files.append(path)
+ entries.append((path, 'file'))
else:
- dirs.append(path)
+ entries.append((path, 'dir'))
rev = max(rev, dir_rev)
- self._directories = dirs
- self._entries = files
+ self._entries = entries
self._revision = rev
def get_entries(self):
@@ -396,14 +388,11 @@ class SvnFileInfo(SvnInfo):
return self._revision
def get_externals(self):
- if self._directories is None:
- self._build_entries()
-
prop_files = [['.svn', 'dir-prop-base'],
['.svn', 'dir-props']]
externals = []
- for dirname in self._directories:
+ for dirname in self.iter_dirs():
prop_file = None
for rel_parts in prop_files:
filename = joinpath(dirname, *rel_parts)
@@ -412,6 +401,8 @@ class SvnFileInfo(SvnInfo):
if prop_file is not None:
ext_prop = parse_prop_file(prop_file, 'svn:externals')
+ #ext_prop should be utf-8 coming from svn:externals
+ ext_prop = decode_as_string(ext_prop, encoding="utf-8")
externals.extend(parse_external_prop(ext_prop))
return externals
@@ -422,12 +413,12 @@ def svn_finder(dirname=''):
#combined externals and entries due to lack of dir_props in 1.7
info = SvnInfo.load(dirname)
for path in info.iter_files():
- yield fsencode(path)
+ yield path
for path in info.iter_externals():
sub_info = SvnInfo.load(path)
for sub_path in sub_info.iter_files():
- yield fsencode(sub_path)
+ yield sub_path
class SVNEntriesFile(object):
diff --git a/setuptools/tests/svn_data/dummy13.zip b/setuptools/tests/svn_data/dummy13.zip
new file mode 100644
index 00000000..47764342
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy13.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy14.zip b/setuptools/tests/svn_data/dummy14.zip
new file mode 100644
index 00000000..02ed8cf0
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy14.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy15.zip b/setuptools/tests/svn_data/dummy15.zip
new file mode 100644
index 00000000..ed8daeeb
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy15.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy16.zip b/setuptools/tests/svn_data/dummy16.zip
new file mode 100644
index 00000000..b6e98d6c
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy16.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy17.zip b/setuptools/tests/svn_data/dummy17.zip
new file mode 100644
index 00000000..d96e1513
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy17.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy18.zip b/setuptools/tests/svn_data/dummy18.zip
new file mode 100644
index 00000000..a7267838
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy18.zip
Binary files differ
diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py
index 65a9f0b3..716893dc 100644
--- a/setuptools/tests/test_sdist.py
+++ b/setuptools/tests/test_sdist.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
"""sdist tests"""
+from __future__ import with_statement
import locale
import os
import shutil
@@ -8,6 +9,7 @@ import sys
import tempfile
import unittest
import unicodedata
+import re
from setuptools.tests import environment
from setuptools.compat import StringIO, unicode
@@ -16,7 +18,6 @@ from setuptools.command.sdist import sdist, walk_revctrl
from setuptools.command.egg_info import manifest_maker
from setuptools.dist import Distribution
from setuptools import svn_utils
-from setuptools.svn_utils import fsencode
SETUP_ATTRS = {
'name': 'sdist_test',
@@ -400,6 +401,83 @@ class TestSdistTest(unittest.TestCase):
self.assertTrue(filename in cmd.filelist.files)
+def soruce_test(self):
+ code, data = svn_utils._run_command([sys.executable, "setup.py", "egg_info"], stream=1)
+
+ if code:
+ raise AssertionError(data)
+
+ sources = os.path.join('dummy.egg-info', 'SOURCES.txt')
+ contents = """CHANGES.txt
+CONTRIBUTORS.txt
+HISTORY.txt
+LICENSE
+MANIFEST.in
+README.txt
+setup.py
+dummy/__init__.py
+dummy/test.txt
+dummy.egg-info/PKG-INFO
+dummy.egg-info/SOURCES.txt
+dummy.egg-info/dependency_links.txt
+dummy.egg-info/top_level.txt"""
+
+ with open(sources, 'r') as infile:
+ read_contents = infile.read()
+
+ self.assertEqual(contents, read_contents)
+
+
+class TestSvnDummy(environment.ZippedEnvironment):
+
+ def setUp(self):
+ version = svn_utils.SvnInfo.get_svn_version()
+ self.base_version = tuple([int(x) for x in version.split('.')][:2])
+
+ if not self.base_version:
+ raise ValueError('No SVN tools installed')
+ elif self.base_version < (1,3):
+ raise ValueError('Insufficient SVN Version %s' % version)
+ elif self.base_version >= (1,9):
+ #trying the latest version
+ self.base_version = (1,8)
+
+ self.dataname = "dummy%i%i" % self.base_version
+ self.datafile = os.path.join('setuptools', 'tests',
+ 'svn_data', self.dataname + ".zip")
+ super(TestSvnDummy, self).setUp()
+
+ def test_sources(self):
+ soruce_test(self)
+
+
+class TestSvnDummyLegacy(environment.ZippedEnvironment):
+
+ def setUp(self):
+ self.base_version = (1,6)
+ self.path_variable = None
+ for env in os.environ:
+ if env.lower() == 'path':
+ self.path_variable = env
+ self.old_path = os.environ[self.path_variable]
+ os.environ[self.path_variable] = ''
+
+ if self.path_variable is None:
+ self.skipTest('Cannot figure out how to modify path')
+
+ self.dataname = "dummy%i%i" % self.base_version
+ self.datafile = os.path.join('setuptools', 'tests',
+ 'svn_data', self.dataname + ".zip")
+ super(TestSvnDummyLegacy, self).setUp()
+
+ def tearDown(self):
+ os.environ[self.path_variable] = self.old_path
+ super(TestSvnDummyLegacy, self).tearDown()
+
+ def test_sources(self):
+ soruce_test(self)
+
+
class TestSvn(environment.ZippedEnvironment):
def setUp(self):
@@ -453,11 +531,9 @@ class TestSvn(environment.ZippedEnvironment):
os.path.join('folder', 'quest.txt'),
#The example will have a deleted file (or should) but shouldn't return it
])
- expected = set(fsencode(x) for x in expected)
self.assertEqual(set(x for x in walk_revctrl()), expected)
-
def test_suite():
return unittest.defaultTestLoader.loadTestsFromName(__name__)