diff options
| -rw-r--r-- | setuptools/svn_utils.py | 97 | ||||
| -rw-r--r-- | setuptools/tests/svn_data/dummy13.zip | bin | 0 -> 9243 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy14.zip | bin | 0 -> 7496 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy15.zip | bin | 0 -> 7506 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy16.zip | bin | 0 -> 7155 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy17.zip | bin | 0 -> 7512 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy18.zip | bin | 0 -> 7639 bytes | |||
| -rw-r--r-- | setuptools/tests/test_sdist.py | 82 |
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 Binary files differnew file mode 100644 index 00000000..47764342 --- /dev/null +++ b/setuptools/tests/svn_data/dummy13.zip diff --git a/setuptools/tests/svn_data/dummy14.zip b/setuptools/tests/svn_data/dummy14.zip Binary files differnew file mode 100644 index 00000000..02ed8cf0 --- /dev/null +++ b/setuptools/tests/svn_data/dummy14.zip diff --git a/setuptools/tests/svn_data/dummy15.zip b/setuptools/tests/svn_data/dummy15.zip Binary files differnew file mode 100644 index 00000000..ed8daeeb --- /dev/null +++ b/setuptools/tests/svn_data/dummy15.zip diff --git a/setuptools/tests/svn_data/dummy16.zip b/setuptools/tests/svn_data/dummy16.zip Binary files differnew file mode 100644 index 00000000..b6e98d6c --- /dev/null +++ b/setuptools/tests/svn_data/dummy16.zip diff --git a/setuptools/tests/svn_data/dummy17.zip b/setuptools/tests/svn_data/dummy17.zip Binary files differnew file mode 100644 index 00000000..d96e1513 --- /dev/null +++ b/setuptools/tests/svn_data/dummy17.zip diff --git a/setuptools/tests/svn_data/dummy18.zip b/setuptools/tests/svn_data/dummy18.zip Binary files differnew file mode 100644 index 00000000..a7267838 --- /dev/null +++ b/setuptools/tests/svn_data/dummy18.zip 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__) |
