aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xsetuptools/command/egg_info.py2
-rwxr-xr-xsetuptools/command/sdist.py84
-rw-r--r--setuptools/compat.py2
-rw-r--r--setuptools/svn_utils.py376
-rw-r--r--setuptools/tests/environment.py104
-rw-r--r--setuptools/tests/svn_data/svn13_example.zipbin0 -> 48818 bytes
-rw-r--r--setuptools/tests/svn_data/svn13_ext_list.txt3
-rw-r--r--setuptools/tests/svn_data/svn13_ext_list.xml0
-rw-r--r--setuptools/tests/svn_data/svn13_info.xml121
-rw-r--r--setuptools/tests/svn_data/svn14_example.zipbin0 -> 31077 bytes
-rw-r--r--setuptools/tests/svn_data/svn14_ext_list.txt4
-rw-r--r--setuptools/tests/svn_data/svn14_ext_list.xml0
-rw-r--r--setuptools/tests/svn_data/svn14_info.xml119
-rw-r--r--setuptools/tests/svn_data/svn15_example.zipbin0 -> 31143 bytes
-rw-r--r--setuptools/tests/svn_data/svn15_ext_list.txt4
-rw-r--r--setuptools/tests/svn_data/svn15_ext_list.xml19
-rw-r--r--setuptools/tests/svn_data/svn15_info.xml125
-rw-r--r--setuptools/tests/svn_data/svn16_example.zipbin0 -> 29418 bytes
-rw-r--r--setuptools/tests/svn_data/svn16_ext_list.txt4
-rw-r--r--setuptools/tests/svn_data/svn16_ext_list.xml19
-rw-r--r--setuptools/tests/svn_data/svn16_info.xml125
-rw-r--r--setuptools/tests/svn_data/svn17_example.zipbin0 -> 46954 bytes
-rw-r--r--setuptools/tests/svn_data/svn17_ext_list.txt4
-rw-r--r--setuptools/tests/svn_data/svn17_ext_list.xml19
-rw-r--r--setuptools/tests/svn_data/svn17_info.xml130
-rw-r--r--setuptools/tests/svn_data/svn18_example.zipbin0 -> 47477 bytes
-rw-r--r--setuptools/tests/svn_data/svn18_ext_list.txt4
-rw-r--r--setuptools/tests/svn_data/svn18_ext_list.xml19
-rw-r--r--setuptools/tests/svn_data/svn18_info.xml136
-rw-r--r--setuptools/tests/test_egg_info.py13
-rw-r--r--setuptools/tests/test_sdist.py64
-rw-r--r--setuptools/tests/test_svn.py305
32 files changed, 1528 insertions, 277 deletions
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
index 345ec8ae..31700648 100755
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -217,7 +217,7 @@ class egg_info(Command):
@staticmethod
def get_svn_revision():
- return str(svn_utils.parse_revision(os.curdir))
+ return str(svn_utils.SvnInfo.load(os.curdir).get_revision())
diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py
index 5cc2139b..e1112ff9 100755
--- a/setuptools/command/sdist.py
+++ b/setuptools/command/sdist.py
@@ -8,73 +8,58 @@ from setuptools import svn_utils
READMES = ('README', 'README.rst', 'README.txt')
-entities = [
- ("&lt;","<"), ("&gt;", ">"), ("&quot;", '"'), ("&apos;", "'"),
- ("&amp;", "&")
-]
-def unescape(data):
- for old,new in entities:
- data = data.replace(old,new)
- return data
+def walk_revctrl(dirname=''):
+ """Find all files under revision control"""
+ for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):
+ for item in ep.load()(dirname):
+ yield item
+
+
+#TODO will need test case
+class re_finder(object):
-def re_finder(pattern, postproc=None):
- def find(dirname, filename):
+ def __init__(self, path, pattern, postproc=None):
+ self.pattern = pattern
+ self.postproc = postproc
+ self.path = convert_path(path)
+
+ def _finder(self, dirname, filename):
f = open(filename,'rU')
- data = f.read()
- f.close()
- for match in pattern.finditer(data):
+ try:
+ data = f.read()
+ finally:
+ f.close()
+ for match in self.pattern.finditer(data):
path = match.group(1)
if postproc:
+ #postproc used to be used when the svn finder
+ #was an re_finder for calling unescape
path = postproc(path)
- yield joinpath(dirname,path)
- return find
-
-def joinpath(prefix,suffix):
- if not prefix:
- return suffix
- return os.path.join(prefix,suffix)
-
-
-
+ yield svn_utils.joinpath(dirname,path)
+ def __call__(self, dirname=''):
+ path = svn_utils.joinpath(dirname, self.path)
-
-
-
-
-def walk_revctrl(dirname=''):
- """Find all files under revision control"""
- for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):
- for item in ep.load()(dirname):
- yield item
-
-def _default_revctrl(dirname=''):
- for path, finder in finders:
- path = joinpath(dirname,path)
if os.path.isfile(path):
- for path in finder(dirname,path):
+ for path in self._finder(dirname,path):
if os.path.isfile(path):
yield path
elif os.path.isdir(path):
- for item in _default_revctrl(path):
+ for item in self.find(path):
yield item
-def entries_externals_finder(dirname, filename):
- for record in svn_utils.parse_dir_entries(dirname):
- yield joinpath(dirname, record)
-
- for name in svn_utils.parse_externals(dirname):
- yield joinpath(dirname, name)
+def _default_revctrl(dirname=''):
+ 'Primary svn_cvs entry point'
+ for finder in finders:
+ for item in finder(dirname):
+ yield item
finders = [
- (convert_path('CVS/Entries'),
- re_finder(re.compile(r"^\w?/([^/]+)/", re.M))),
- #combined externals due to common interface
- #combined externals and enteries due to lack of dir_props in 1.7
- (convert_path('.svn/entries'), entries_externals_finder),
+ re_finder('CVS/Entries', re.compile(r"^\w?/([^/]+)/", re.M)),
+ svn_utils.svn_finder,
]
@@ -88,6 +73,7 @@ finders = [
+
class sdist(_sdist):
"""Smart sdist that finds anything supported by revision control"""
diff --git a/setuptools/compat.py b/setuptools/compat.py
index e2f64de2..94fe23e9 100644
--- a/setuptools/compat.py
+++ b/setuptools/compat.py
@@ -26,6 +26,7 @@ if sys.version_info[0] < 3:
reduce = reduce
unichr = unichr
unicode = unicode
+ bytes = str
from urllib import url2pathname
import urllib2
from urllib2 import urlopen, HTTPError, URLError, unquote, splituser
@@ -69,6 +70,7 @@ else:
from functools import reduce
unichr = chr
unicode = str
+ bytes = bytes
from urllib.error import HTTPError, URLError
import urllib.request as urllib2
from urllib.request import urlopen, url2pathname
diff --git a/setuptools/svn_utils.py b/setuptools/svn_utils.py
index a4c53f15..09aa5e25 100644
--- a/setuptools/svn_utils.py
+++ b/setuptools/svn_utils.py
@@ -1,31 +1,22 @@
import os
import re
import sys
-import codecs
from distutils import log
import xml.dom.pulldom
+import shlex
+import locale
+import unicodedata
+from setuptools.compat import unicode, bytes
try:
import urlparse
except ImportError:
import urllib.parse as urlparse
-#requires python >= 2.4
from subprocess import Popen as _Popen, PIPE as _PIPE
-#NOTE: Use of the command line options
-# require SVN 1.3 or newer (December 2005)
-# and SVN 1.3 hsan't been supported by the
-# developers since mid 2008.
-
-
-#svnversion return values (previous implementations return max revision)
-# 4123:4168 mixed revision working copy
-# 4168M modified working copy
-# 4123S switched working copy
-# 4123:4168MS mixed revision, modified, switched working copy
-_SVN_VER_RE = re.compile(r'(?:([\-0-9]+):)?(\d+)([a-z]*)\s*$', re.I)
-
+#NOTE: Use of the command line options require SVN 1.3 or newer (December 2005)
+# and SVN 1.3 hasn't been supported by the developers since mid 2008.
#subprocess is called several times with shell=(sys.platform=='win32')
#see the follow for more information:
@@ -33,27 +24,20 @@ _SVN_VER_RE = re.compile(r'(?:([\-0-9]+):)?(\d+)([a-z]*)\s*$', re.I)
# http://stackoverflow.com/questions/5658622/
# python-subprocess-popen-environment-path
def _run_command(args, stdout=_PIPE, stderr=_PIPE):
- #regarding the shell argument, see: http://bugs.python.org/issue8557
- try:
- proc = _Popen(args, stdout=stdout, stderr=stderr,
- shell=(sys.platform == 'win32'))
-
- data = proc.communicate()[0]
- except OSError:
- return 1, ''
-
- #TODO: this is probably NOT always utf-8
- try:
- data = unicode(data, encoding='utf-8')
- except NameError:
- data = str(data, encoding='utf-8')
+ #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'))
- #communciate calls wait()
- return proc.returncode, data
+ data = proc.communicate()[0]
+ except OSError:
+ return 1, ''
+ data = consoledecode(data)
-def _get_entry_name(entry):
- return entry.getAttribute('path')
+ #communciate calls wait()
+ return proc.returncode, data
def _get_entry_schedule(entry):
@@ -63,105 +47,283 @@ def _get_entry_schedule(entry):
if t.nodeType == t.TEXT_NODE])
-def parse_revision(path):
- code, data = _run_command(['svnversion', '-c', path])
+def _get_target_property(target):
+ property_text = target.getElementsByTagName('property')[0]
+ return "".join([t.nodeValue
+ for t in property_text.childNodes
+ if t.nodeType == t.TEXT_NODE])
- if code:
- log.warn("svnversion failed")
- return 0
+
+def _get_xml_data(decoded_str):
+ if sys.version_info < (3, 0):
+ #old versions want an encoded string
+ data = decoded_str.encode('utf-8')
else:
- log.warn('Version: %s' % data.strip())
+ data = decoded_str
+ return data
- parsed = _SVN_VER_RE.match(data)
- if parsed:
- try:
- #No max needed this command summarizes working copy since 1.0
- return int(parsed.group(2))
- except ValueError:
- #This should only happen if the revision is WAY too big.
- pass
- return 0
-
-#TODO: Need to do this with the -R because only root has .svn in 1.7.x
-def parse_dir_entries(path):
- code, data = _run_command(['svn', 'info',
- '--depth', 'immediates', '--xml', path])
-
- if code:
- log.warn("svn info failed")
- return []
- data = codecs.encode(data, 'UTF-8')
+def joinpath(prefix, suffix):
+ if not prefix or prefix == '.':
+ return 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')
- doc = xml.dom.pulldom.parseString(data)
+ 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 consoledecode(text):
+ encoding = locale.getpreferredencoding()
+ return text.decode(encoding)
+
+
+def parse_dir_entries(decoded_str):
+ '''Parse the entries from a recursive info xml'''
+ doc = xml.dom.pulldom.parseString(_get_xml_data(decoded_str))
entries = list()
+
for event, node in doc:
if event == 'START_ELEMENT' and node.nodeName == 'entry':
doc.expandNode(node)
- entries.append(node)
-
- if entries:
- return [
- _get_entry_name(element)
- for element in entries[1:]
- if _get_entry_schedule(element).lower() != 'deleted'
- ]
- else:
- return []
+ if not _get_entry_schedule(node).startswith('delete'):
+ entries.append((node.getAttribute('path'),
+ node.getAttribute('kind')))
+ return entries[1:] # do not want the root directory
-#--xml wasn't supported until 1.5.x need to do -R
-#TODO: -R looks like directories are seperated by blank lines
-# with dir - prepened to first directory
-# what about directories with spaces?
-# put quotes around them
-# what about the URL's?
-# same
-# convert to UTF-8 and use csv
-# delimiter = space
-#
-#-R without --xml parses a bit funny
-def parse_externals(path):
- try:
- code, lines = _run_command(['svn',
- 'propget', 'svn:externals', path])
- if code:
- log.warn("svn propget failed")
- return []
+def parse_externals_xml(decoded_str, prefix=''):
+ '''Parse a propget svn:externals xml'''
+ prefix = os.path.normpath(prefix)
+
+ doc = xml.dom.pulldom.parseString(_get_xml_data(decoded_str))
+ externals = list()
+
+ for event, node in doc:
+ if event == 'START_ELEMENT' and node.nodeName == 'target':
+ doc.expandNode(node)
+ path = os.path.normpath(node.getAttribute('path'))
+ if os.path.normcase(path).startswith(prefix):
+ path = path[len(prefix)+1:]
- lines = [line for line in lines.splitlines() if line]
- except ValueError:
- lines = []
+ data = _get_target_property(node)
+ for external in parse_external_prop(data):
+ externals.append(joinpath(path, external))
+ return externals # do not want the root directory
+
+
+def parse_external_prop(lines):
+ """
+ Parse the value of a retrieved svn:externals entry.
+
+ possible token setups (with quotng and backscaping in laters versions)
+ URL[@#] EXT_FOLDERNAME
+ [-r#] URL EXT_FOLDERNAME
+ EXT_FOLDERNAME [-r#] URL
+ """
externals = []
- for line in lines:
- line = line.split()
+ for line in lines.splitlines():
+ line = line.lstrip() #there might be a "\ "
if not line:
continue
+ if sys.version_info < (3, 0):
+ #shlex handles NULLs just fine and shlex in 2.7 tries to encode
+ #as ascii automatiically
+ line = line.encode('utf-8')
+ line = shlex.split(line)
+ if sys.version_info < (3, 0):
+ line = [x.decode('utf-8') for x in line]
+
+ #EXT_FOLDERNAME is either the first or last depending on where
+ #the URL falls
if urlparse.urlsplit(line[-1])[0]:
- externals.append(line[0])
+ external = line[0]
else:
- externals.append(line[-1])
+ external = line[-1]
+
+ externals.append(os.path.normpath(external))
return externals
-def get_svn_tool_version():
- _, data = _run_command(['svn', '--version', '--quiet'])
- if data:
- return data.strip()
- else:
- return ''
+class SvnInfo(object):
+ '''
+ Generic svn_info object. No has little knowledge of how to extract
+ information. Use cls.load to instatiate according svn version.
-if __name__ == '__main__':
- def entries_externals_finder(dirname):
- for record in parse_dir_entries(dirname):
- yield os.path.join(dirname, record)
+ Paths are not filesystem encoded.
+ '''
- for name in parse_externals(dirname):
- yield os.path.join(dirname, name)
+ @staticmethod
+ def get_svn_version():
+ code, data = _run_command(['svn', '--version', '--quiet'])
+ if code == 0 and data:
+ return unicode(data).strip()
+ else:
+ return unicode('')
+
+ #svnversion return values (previous implementations return max revision)
+ # 4123:4168 mixed revision working copy
+ # 4168M modified working copy
+ # 4123S switched working copy
+ # 4123:4168MS mixed revision, modified, switched working copy
+ revision_re = re.compile(r'(?:([\-0-9]+):)?(\d+)([a-z]*)\s*$', re.I)
+
+ @classmethod
+ def load(cls, dirname=''):
+ code, data = _run_command(['svn', 'info', os.path.normpath(dirname)])
+ svn_version = tuple(cls.get_svn_version().split('.'))
+ base_svn_version = tuple(int(x) for x in svn_version[:2])
+ if code and base_svn_version:
+ #Not an SVN repository or compatible one
+ return SvnInfo(dirname)
+ elif base_svn_version < (1, 3):
+ log.warn('Insufficent version of SVN found')
+ return SvnInfo(dirname)
+ elif base_svn_version < (1, 5):
+ return Svn13Info(dirname)
+ else:
+ return Svn15Info(dirname)
+
+ def __init__(self, path=''):
+ self.path = path
+ self._entries = None
+ self._externals = None
+
+ def get_revision(self):
+ 'Retrieve the directory revision informatino using svnversion'
+ code, data = _run_command(['svnversion', '-c', self.path])
+ if code:
+ log.warn("svnversion failed")
+ return 0
- for name in entries_externals_finder(sys.argv[1]):
+ parsed = self.revision_re.match(data)
+ if parsed:
+ return int(parsed.group(2))
+ else:
+ return 0
+
+ @property
+ def entries(self):
+ if self._entries is None:
+ self._entries = self.get_entries()
+ return self._entries
+
+ @property
+ def externals(self):
+ if self._externals is None:
+ self._externals = self.get_externals()
+ return self._externals
+
+ def iter_externals(self):
+ '''
+ Iterate over the svn:external references in the repository path.
+ '''
+ for item in self.externals:
+ yield item
+
+ def iter_files(self):
+ '''
+ Iterate over the non-deleted file entries in the repository path
+ '''
+ for item, kind in self.entries:
+ if kind.lower()=='file':
+ yield item
+
+ def iter_dirs(self, include_root=True):
+ '''
+ Iterate over the non-deleted file entries in the repository path
+ '''
+ if include_root:
+ yield self.path
+ for item, kind in self.entries:
+ if kind.lower()=='dir':
+ yield item
+
+ def get_entries(self):
+ return []
+
+ def get_externals(self):
+ return []
+
+class Svn13Info(SvnInfo):
+ def get_entries(self):
+ code, data = _run_command(['svn', 'info', '-R', '--xml', self.path])
+
+ if code:
+ log.debug("svn info failed")
+ return []
+
+ return parse_dir_entries(data)
+
+ def get_externals(self):
+ #Previous to 1.5 --xml was not supported for svn propget and the -R
+ #output format breaks the shlex compatible semantics.
+ cmd = ['svn', 'propget', 'svn:externals']
+ result = []
+ for folder in self.iter_dirs():
+ code, lines = _run_command(cmd + [folder])
+ if code != 0:
+ log.warn("svn propget failed")
+ return []
+ for external in parse_external_prop(lines):
+ if folder:
+ external = os.path.join(folder, external)
+ result.append(os.path.normpath(external))
+
+ return result
+
+
+class Svn15Info(Svn13Info):
+ def get_externals(self):
+ cmd = ['svn', 'propget', 'svn:externals', self.path, '-R', '--xml']
+ code, lines = _run_command(cmd)
+ if code:
+ log.debug("svn propget failed")
+ return []
+ return parse_externals_xml(lines, prefix=os.path.abspath(self.path))
+
+
+def svn_finder(dirname=''):
+ #combined externals due to common interface
+ #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)
+
+ for path in info.iter_externals():
+ sub_info = SvnInfo.load(path)
+ for sub_path in sub_info.iter_files():
+ yield fsencode(sub_path)
+
+if __name__ == '__main__':
+ for name in svn_finder(sys.argv[1]):
print(name) \ No newline at end of file
diff --git a/setuptools/tests/environment.py b/setuptools/tests/environment.py
new file mode 100644
index 00000000..7c754b8e
--- /dev/null
+++ b/setuptools/tests/environment.py
@@ -0,0 +1,104 @@
+import os
+import zipfile
+import sys
+import tempfile
+import unittest
+import shutil
+import stat
+
+
+def _extract(self, member, path=None, pwd=None):
+ """for zipfile py2.5 borrowed from cpython"""
+ if not isinstance(member, zipfile.ZipInfo):
+ member = self.getinfo(member)
+
+ if path is None:
+ path = os.getcwd()
+
+ return _extract_member(self, member, path, pwd)
+
+
+def _extract_from_zip(self, name, dest_path):
+ dest_file = open(dest_path, 'wb')
+ try:
+ dest_file.write(self.read(name))
+ finally:
+ dest_file.close()
+
+def _extract_member(self, member, targetpath, pwd):
+ """for zipfile py2.5 borrowed from cpython"""
+ # build the destination pathname, replacing
+ # forward slashes to platform specific separators.
+ # Strip trailing path separator, unless it represents the root.
+ if (targetpath[-1:] in (os.path.sep, os.path.altsep)
+ and len(os.path.splitdrive(targetpath)[1]) > 1):
+ targetpath = targetpath[:-1]
+
+ # don't include leading "/" from file name if present
+ if member.filename[0] == '/':
+ targetpath = os.path.join(targetpath, member.filename[1:])
+ else:
+ targetpath = os.path.join(targetpath, member.filename)
+
+ targetpath = os.path.normpath(targetpath)
+
+ # Create all upper directories if necessary.
+ upperdirs = os.path.dirname(targetpath)
+ if upperdirs and not os.path.exists(upperdirs):
+ os.makedirs(upperdirs)
+
+ if member.filename[-1] == '/':
+ if not os.path.isdir(targetpath):
+ os.mkdir(targetpath)
+ return targetpath
+
+ _extract_from_zip(self, member.filename, targetpath)
+
+ return targetpath
+
+
+def _remove_dir(target):
+
+ #on windows this seems to a problem
+ for dir_path, dirs, files in os.walk(target):
+ os.chmod(dir_path, stat.S_IWRITE)
+ for filename in files:
+ os.chmod(os.path.join(dir_path, filename), stat.S_IWRITE)
+ shutil.rmtree(target)
+
+
+class ZippedEnvironment(unittest.TestCase):
+
+ datafile = None
+ dataname = None
+ old_cwd = None
+
+ def setUp(self):
+ if not os.path.isfile(self.datafile):
+ self.old_cwd = None
+ return
+
+ self.old_cwd = os.getcwd()
+
+ self.temp_dir = tempfile.mkdtemp()
+ zip_file, source, target = [None, None, None]
+ try:
+ zip_file = zipfile.ZipFile(self.datafile)
+ for files in zip_file.namelist():
+ _extract(zip_file, files, self.temp_dir)
+ finally:
+ if zip_file:
+ zip_file.close()
+ del zip_file
+
+ os.chdir(os.path.join(self.temp_dir, self.dataname))
+
+ def tearDown(self):
+ try:
+ if self.old_cwd:
+ os.chdir(self.old_cwd)
+ _remove_dir(self.temp_dir)
+ except OSError:
+ #sigh?
+ pass
+
diff --git a/setuptools/tests/svn_data/svn13_example.zip b/setuptools/tests/svn_data/svn13_example.zip
new file mode 100644
index 00000000..d85fb84f
--- /dev/null
+++ b/setuptools/tests/svn_data/svn13_example.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/svn13_ext_list.txt b/setuptools/tests/svn_data/svn13_ext_list.txt
new file mode 100644
index 00000000..0bb0f438
--- /dev/null
+++ b/setuptools/tests/svn_data/svn13_ext_list.txt
@@ -0,0 +1,3 @@
+third_party3 file:///C:/development/svn_example/repos/svn13/extra1
+third_party2 -r3 file:///C:/development/svn_example/repos/svn13/extra1
+third_party -r1 file:///C:/development/svn_example/repos/svn13/extra1
diff --git a/setuptools/tests/svn_data/svn13_ext_list.xml b/setuptools/tests/svn_data/svn13_ext_list.xml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/setuptools/tests/svn_data/svn13_ext_list.xml
diff --git a/setuptools/tests/svn_data/svn13_info.xml b/setuptools/tests/svn_data/svn13_info.xml
new file mode 100644
index 00000000..5c96520a
--- /dev/null
+++ b/setuptools/tests/svn_data/svn13_info.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<info>
+<entry
+ kind="dir"
+ path="svn13_example"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn13/main</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn13/main</root>
+<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<prop-updated>2013-07-13T15:33:23.187500Z</prop-updated>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:33:28.359375Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn13_example\a file"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn13/main/a%20file</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn13/main</root>
+<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<text-updated>2013-07-13T15:33:21.109375Z</text-updated>
+<checksum>a6166e5e98a5a503089cde9bc8031293</checksum>
+</wc-info>
+<commit
+ revision="3">
+<author>ptt</author>
+<date>2013-07-13T15:33:21.312500Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn13_example\to_delete"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn13/main/to_delete</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn13/main</root>
+<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
+</repository>
+<wc-info>
+<schedule>delete</schedule>
+<text-updated>2013-07-13T15:33:28.140625Z</text-updated>
+<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:33:28.359375Z</date>
+</commit>
+</entry>
+<entry
+ kind="dir"
+ path="svn13_example\folder"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn13/main/folder</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn13/main</root>
+<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<prop-updated>2013-07-13T15:33:26.187500Z</prop-updated>
+</wc-info>
+<commit
+ revision="5">
+<author>ptt</author>
+<date>2013-07-13T15:33:26.312500Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn13_example\folder\quest.txt"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn13/main/folder/quest.txt</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn13/main</root>
+<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<text-updated>2013-07-13T15:33:20.109375Z</text-updated>
+<checksum>795240c6a830c14f83961e57e07dad12</checksum>
+</wc-info>
+<commit
+ revision="2">
+<author>ptt</author>
+<date>2013-07-13T15:33:20.312500Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn13_example\folder\lalala.txt"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn13/main/folder/lalala.txt</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn13/main</root>
+<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<text-updated>2013-07-13T15:33:19.375000Z</text-updated>
+<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
+</wc-info>
+<commit
+ revision="1">
+<author>ptt</author>
+<date>2013-07-13T15:33:19.609375Z</date>
+</commit>
+</entry>
+</info>
diff --git a/setuptools/tests/svn_data/svn14_example.zip b/setuptools/tests/svn_data/svn14_example.zip
new file mode 100644
index 00000000..57093c0b
--- /dev/null
+++ b/setuptools/tests/svn_data/svn14_example.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/svn14_ext_list.txt b/setuptools/tests/svn_data/svn14_ext_list.txt
new file mode 100644
index 00000000..800a0965
--- /dev/null
+++ b/setuptools/tests/svn_data/svn14_ext_list.txt
@@ -0,0 +1,4 @@
+third_party3 file:///C:/development/svn_example/repos/svn13/extra1
+third_party2 -r3 file:///C:/development/svn_example/repos/svn13/extra1
+third_party -r1 file:///C:/development/svn_example/repos/svn13/extra1
+
diff --git a/setuptools/tests/svn_data/svn14_ext_list.xml b/setuptools/tests/svn_data/svn14_ext_list.xml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/setuptools/tests/svn_data/svn14_ext_list.xml
diff --git a/setuptools/tests/svn_data/svn14_info.xml b/setuptools/tests/svn_data/svn14_info.xml
new file mode 100644
index 00000000..a896a77f
--- /dev/null
+++ b/setuptools/tests/svn_data/svn14_info.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0"?>
+<info>
+<entry
+ kind="dir"
+ path="svn14_example"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn14/main</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn14/main</root>
+<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:34:14.406250Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn14_example\a file"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn14/main/a%20file</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn14/main</root>
+<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<text-updated>2013-07-13T15:34:08.109375Z</text-updated>
+<checksum>a6166e5e98a5a503089cde9bc8031293</checksum>
+</wc-info>
+<commit
+ revision="3">
+<author>ptt</author>
+<date>2013-07-13T15:34:08.390625Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn14_example\to_delete"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn14/main/to_delete</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn14/main</root>
+<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
+</repository>
+<wc-info>
+<schedule>delete</schedule>
+<text-updated>2013-07-13T15:34:14.125000Z</text-updated>
+<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:34:14.406250Z</date>
+</commit>
+</entry>
+<entry
+ kind="dir"
+ path="svn14_example\folder"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn14/main/folder</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn14/main</root>
+<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+</wc-info>
+<commit
+ revision="5">
+<author>ptt</author>
+<date>2013-07-13T15:34:12.390625Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn14_example\folder\quest.txt"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn14/main/folder/quest.txt</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn14/main</root>
+<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<text-updated>2013-07-13T15:34:07.109375Z</text-updated>
+<checksum>795240c6a830c14f83961e57e07dad12</checksum>
+</wc-info>
+<commit
+ revision="2">
+<author>ptt</author>
+<date>2013-07-13T15:34:07.390625Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn14_example\folder\lalala.txt"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn14/main/folder/lalala.txt</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn14/main</root>
+<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<text-updated>2013-07-13T15:34:06.250000Z</text-updated>
+<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
+</wc-info>
+<commit
+ revision="1">
+<author>ptt</author>
+<date>2013-07-13T15:34:06.531250Z</date>
+</commit>
+</entry>
+</info>
diff --git a/setuptools/tests/svn_data/svn15_example.zip b/setuptools/tests/svn_data/svn15_example.zip
new file mode 100644
index 00000000..52a1d45b
--- /dev/null
+++ b/setuptools/tests/svn_data/svn15_example.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/svn15_ext_list.txt b/setuptools/tests/svn_data/svn15_ext_list.txt
new file mode 100644
index 00000000..75fde4e6
--- /dev/null
+++ b/setuptools/tests/svn_data/svn15_ext_list.txt
@@ -0,0 +1,4 @@
+third_party3 file:///C:/development/svn_example/repos/svn15/extra1
+-r3 file:///C:/development/svn_example/repos/svn15/extra1 third_party2
+file:///C:/development/svn_example/repos/svn15/extra1@r1 third_party
+
diff --git a/setuptools/tests/svn_data/svn15_ext_list.xml b/setuptools/tests/svn_data/svn15_ext_list.xml
new file mode 100644
index 00000000..6950b3c5
--- /dev/null
+++ b/setuptools/tests/svn_data/svn15_ext_list.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<properties>
+<target
+ path="C:/development/svn_example/svn15_example/folder">
+<property
+ name="svn:externals">third_party3 file:///C:/development/svn_example/repos/svn15/extra2
+-r3 file:///C:/development/svn_example/repos/svn15/extra2 third_party2
+file:///C:/development/svn_example/repos/svn15/extra2@r1 third_party大介
+</property>
+</target>
+<target
+ path="C:/development/svn_example/svn15_example">
+<property
+ name="svn:externals">third_party3 file:///C:/development/svn_example/repos/svn15/extra1
+-r3 file:///C:/development/svn_example/repos/svn15/extra1 third_party2
+file:///C:/development/svn_example/repos/svn15/extra1@r1 third_party大介
+</property>
+</target>
+</properties>
diff --git a/setuptools/tests/svn_data/svn15_info.xml b/setuptools/tests/svn_data/svn15_info.xml
new file mode 100644
index 00000000..0b3550af
--- /dev/null
+++ b/setuptools/tests/svn_data/svn15_info.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0"?>
+<info>
+<entry
+ kind="dir"
+ path="svn15_example"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn15/main</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn15/main</root>
+<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:34:49.562500Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn15_example\a file"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn15/main/a%20file</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn15/main</root>
+<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:34:43.109375Z</text-updated>
+<checksum>a6166e5e98a5a503089cde9bc8031293</checksum>
+</wc-info>
+<commit
+ revision="3">
+<author>ptt</author>
+<date>2013-07-13T15:34:43.484375Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn15_example\to_delete"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn15/main/to_delete</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn15/main</root>
+<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
+</repository>
+<wc-info>
+<schedule>delete</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:34:49.125000Z</text-updated>
+<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:34:49.562500Z</date>
+</commit>
+</entry>
+<entry
+ kind="dir"
+ path="svn15_example\folder"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn15/main/folder</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn15/main</root>
+<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+</wc-info>
+<commit
+ revision="5">
+<author>ptt</author>
+<date>2013-07-13T15:34:47.515625Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn15_example\folder\quest.txt"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn15/main/folder/quest.txt</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn15/main</root>
+<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:34:42.109375Z</text-updated>
+<checksum>795240c6a830c14f83961e57e07dad12</checksum>
+</wc-info>
+<commit
+ revision="2">
+<author>ptt</author>
+<date>2013-07-13T15:34:42.484375Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn15_example\folder\lalala.txt"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn15/main/folder/lalala.txt</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn15/main</root>
+<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:34:41.375000Z</text-updated>
+<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
+</wc-info>
+<commit
+ revision="1">
+<author>ptt</author>
+<date>2013-07-13T15:34:41.734375Z</date>
+</commit>
+</entry>
+</info>
diff --git a/setuptools/tests/svn_data/svn16_example.zip b/setuptools/tests/svn_data/svn16_example.zip
new file mode 100644
index 00000000..e886b2af
--- /dev/null
+++ b/setuptools/tests/svn_data/svn16_example.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/svn16_ext_list.txt b/setuptools/tests/svn_data/svn16_ext_list.txt
new file mode 100644
index 00000000..3ca54893
--- /dev/null
+++ b/setuptools/tests/svn_data/svn16_ext_list.txt
@@ -0,0 +1,4 @@
+"third party3" file:///C:/development/svn_example/repos/svn16/extra1
+'third party3b' file:///C:/development/svn_example/repos/svn16/extra1
+-r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
+file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party
diff --git a/setuptools/tests/svn_data/svn16_ext_list.xml b/setuptools/tests/svn_data/svn16_ext_list.xml
new file mode 100644
index 00000000..8ddaed0a
--- /dev/null
+++ b/setuptools/tests/svn_data/svn16_ext_list.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<properties>
+<target
+ path="C:/development/svn_example/svn16_example/folder">
+<property
+ name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn16/extra2
+-r3 file:///C:/development/svn_example/repos/svn16/extra2 third\ party2
+file:///C:/development/svn_example/repos/svn16/extra2@r1 third_party大介
+</property>
+</target>
+<target
+ path="C:/development/svn_example/svn16_example">
+<property
+ name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn16/extra1
+-r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
+file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party大介
+</property>
+</target>
+</properties>
diff --git a/setuptools/tests/svn_data/svn16_info.xml b/setuptools/tests/svn_data/svn16_info.xml
new file mode 100644
index 00000000..745469c9
--- /dev/null
+++ b/setuptools/tests/svn_data/svn16_info.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0"?>
+<info>
+<entry
+ kind="dir"
+ path="svn16_example"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn16/main</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn16/main</root>
+<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:35:17.390625Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn16_example\a file"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn16/main/a%20file</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn16/main</root>
+<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:35:14.578125Z</text-updated>
+<checksum>a6166e5e98a5a503089cde9bc8031293</checksum>
+</wc-info>
+<commit
+ revision="3">
+<author>ptt</author>
+<date>2013-07-13T15:35:14.906250Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn16_example\to_delete"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn16/main/to_delete</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn16/main</root>
+<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
+</repository>
+<wc-info>
+<schedule>delete</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:35:17.046875Z</text-updated>
+<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:35:17.390625Z</date>
+</commit>
+</entry>
+<entry
+ kind="dir"
+ path="svn16_example\folder"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn16/main/folder</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn16/main</root>
+<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+</wc-info>
+<commit
+ revision="5">
+<author>ptt</author>
+<date>2013-07-13T15:35:16.406250Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn16_example\folder\quest.txt"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn16/main/folder/quest.txt</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn16/main</root>
+<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:35:14.078125Z</text-updated>
+<checksum>795240c6a830c14f83961e57e07dad12</checksum>
+</wc-info>
+<commit
+ revision="2">
+<author>ptt</author>
+<date>2013-07-13T15:35:14.421875Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn16_example\folder\lalala.txt"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn16/main/folder/lalala.txt</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn16/main</root>
+<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
+</repository>
+<wc-info>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:35:12.171875Z</text-updated>
+<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
+</wc-info>
+<commit
+ revision="1">
+<author>ptt</author>
+<date>2013-07-13T15:35:13.906250Z</date>
+</commit>
+</entry>
+</info>
diff --git a/setuptools/tests/svn_data/svn17_example.zip b/setuptools/tests/svn_data/svn17_example.zip
new file mode 100644
index 00000000..ba0e8823
--- /dev/null
+++ b/setuptools/tests/svn_data/svn17_example.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/svn17_ext_list.txt b/setuptools/tests/svn_data/svn17_ext_list.txt
new file mode 100644
index 00000000..a8b832a8
--- /dev/null
+++ b/setuptools/tests/svn_data/svn17_ext_list.txt
@@ -0,0 +1,4 @@
+"third party3" file:///C:/development/svn_example/repos/svn17/extra1
+'third party3b' file:///C:/development/svn_example/repos/svn17/extra1
+-r3 file:///C:/development/svn_example/repos/svn17/extra1 third\ party2
+file:///C:/development/svn_example/repos/svn17/extra1@r1 third_party
diff --git a/setuptools/tests/svn_data/svn17_ext_list.xml b/setuptools/tests/svn_data/svn17_ext_list.xml
new file mode 100644
index 00000000..2879bb65
--- /dev/null
+++ b/setuptools/tests/svn_data/svn17_ext_list.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<properties>
+<target
+ path="C:/development/svn_example/svn17_example">
+<property
+ name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn16/extra1
+-r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
+file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party大介
+</property>
+</target>
+<target
+ path="C:/development/svn_example/svn17_example/folder">
+<property
+ name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn17/extra2
+-r3 file:///C:/development/svn_example/repos/svn17/extra2 third\ party2
+file:///C:/development/svn_example/repos/svn17/extra2@r1 third_party大介
+</property>
+</target>
+</properties>
diff --git a/setuptools/tests/svn_data/svn17_info.xml b/setuptools/tests/svn_data/svn17_info.xml
new file mode 100644
index 00000000..6cffeffd
--- /dev/null
+++ b/setuptools/tests/svn_data/svn17_info.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<info>
+<entry
+ kind="dir"
+ path="svn17_example"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn17/main</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn17/main</root>
+<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:35:36.171875Z</date>
+</commit>
+</entry>
+<entry
+ path="svn17_example\folder"
+ revision="6"
+ kind="dir">
+<url>file:///C:/development/svn_example/repos/svn17/main/folder</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn17/main</root>
+<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+</wc-info>
+<commit
+ revision="5">
+<author>ptt</author>
+<date>2013-07-13T15:35:34.859375Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn17_example\folder\quest.txt"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn17/main/folder/quest.txt</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn17/main</root>
+<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:35:32.812500Z</text-updated>
+<checksum>bc80eba9e7a10c0a571a4678c520bc9683f3bac2</checksum>
+</wc-info>
+<commit
+ revision="2">
+<author>ptt</author>
+<date>2013-07-13T15:35:33.109375Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn17_example\folder\lalala.txt"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn17/main/folder/lalala.txt</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn17/main</root>
+<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:35:32.343750Z</text-updated>
+<checksum>da39a3ee5e6b4b0d3255bfef95601890afd80709</checksum>
+</wc-info>
+<commit
+ revision="1">
+<author>ptt</author>
+<date>2013-07-13T15:35:32.687500Z</date>
+</commit>
+</entry>
+<entry
+ path="svn17_example\a file"
+ revision="6"
+ kind="file">
+<url>file:///C:/development/svn_example/repos/svn17/main/a%20file</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn17/main</root>
+<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:35:33.187500Z</text-updated>
+<checksum>43785ab4b1816b49f242990883292813cd4f486c</checksum>
+</wc-info>
+<commit
+ revision="3">
+<author>ptt</author>
+<date>2013-07-13T15:35:33.515625Z</date>
+</commit>
+</entry>
+<entry
+ path="svn17_example\to_delete"
+ revision="6"
+ kind="file">
+<url>file:///C:/development/svn_example/repos/svn17/main/to_delete</url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn17/main</root>
+<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
+<schedule>delete</schedule>
+<depth>infinity</depth>
+<checksum>da39a3ee5e6b4b0d3255bfef95601890afd80709</checksum>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:35:36.171875Z</date>
+</commit>
+</entry>
+</info>
diff --git a/setuptools/tests/svn_data/svn18_example.zip b/setuptools/tests/svn_data/svn18_example.zip
new file mode 100644
index 00000000..4362f8e9
--- /dev/null
+++ b/setuptools/tests/svn_data/svn18_example.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/svn18_ext_list.txt b/setuptools/tests/svn_data/svn18_ext_list.txt
new file mode 100644
index 00000000..c90a5f11
--- /dev/null
+++ b/setuptools/tests/svn_data/svn18_ext_list.txt
@@ -0,0 +1,4 @@
+"third party3" file:///C:/development/svn_example/repos/svn18/extra1
+'third party3b' file:///C:/development/svn_example/repos/svn18/extra1
+-r3 file:///C:/development/svn_example/repos/svn18/extra1 third\ party2
+file:///C:/development/svn_example/repos/svn18/extra1@r1 third_party
diff --git a/setuptools/tests/svn_data/svn18_ext_list.xml b/setuptools/tests/svn_data/svn18_ext_list.xml
new file mode 100644
index 00000000..9b5e9e96
--- /dev/null
+++ b/setuptools/tests/svn_data/svn18_ext_list.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<properties>
+<target
+ path="C:/development/svn_example/svn18_example">
+<property
+ name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn16/extra1
+-r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
+file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party大介
+</property>
+</target>
+<target
+ path="C:/development/svn_example/svn18_example/folder">
+<property
+ name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn18/extra2
+-r3 file:///C:/development/svn_example/repos/svn18/extra2 third\ party2
+file:///C:/development/svn_example/repos/svn18/extra2@r1 third_party大介
+</property>
+</target>
+</properties>
diff --git a/setuptools/tests/svn_data/svn18_info.xml b/setuptools/tests/svn_data/svn18_info.xml
new file mode 100644
index 00000000..7ca55995
--- /dev/null
+++ b/setuptools/tests/svn_data/svn18_info.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<info>
+<entry
+ path="svn18_example"
+ revision="6"
+ kind="dir">
+<url>file:///C:/development/svn_example/repos/svn18/main</url>
+<relative-url>^/</relative-url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn18/main</root>
+<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:35:57.796875Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn18_example\a file"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn18/main/a%20file</url>
+<relative-url>^/a%20file</relative-url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn18/main</root>
+<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:35:54.906250Z</text-updated>
+<checksum>43785ab4b1816b49f242990883292813cd4f486c</checksum>
+</wc-info>
+<commit
+ revision="3">
+<author>ptt</author>
+<date>2013-07-13T15:35:55.265625Z</date>
+</commit>
+</entry>
+<entry
+ kind="file"
+ path="svn18_example\to_delete"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn18/main/to_delete</url>
+<relative-url>^/to_delete</relative-url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn18/main</root>
+<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
+<schedule>delete</schedule>
+<depth>infinity</depth>
+<checksum>da39a3ee5e6b4b0d3255bfef95601890afd80709</checksum>
+</wc-info>
+<commit
+ revision="6">
+<author>ptt</author>
+<date>2013-07-13T15:35:57.796875Z</date>
+</commit>
+</entry>
+<entry
+ kind="dir"
+ path="svn18_example\folder"
+ revision="6">
+<url>file:///C:/development/svn_example/repos/svn18/main/folder</url>
+<relative-url>^/folder</relative-url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn18/main</root>
+<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+</wc-info>
+<commit
+ revision="5">
+<author>ptt</author>
+<date>2013-07-13T15:35:56.750000Z</date>
+</commit>
+</entry>
+<entry
+ path="svn18_example\folder\quest.txt"
+ revision="6"
+ kind="file">
+<url>file:///C:/development/svn_example/repos/svn18/main/folder/quest.txt</url>
+<relative-url>^/folder/quest.txt</relative-url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn18/main</root>
+<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:35:54.484375Z</text-updated>
+<checksum>bc80eba9e7a10c0a571a4678c520bc9683f3bac2</checksum>
+</wc-info>
+<commit
+ revision="2">
+<author>ptt</author>
+<date>2013-07-13T15:35:54.843750Z</date>
+</commit>
+</entry>
+<entry
+ path="svn18_example\folder\lalala.txt"
+ revision="6"
+ kind="file">
+<url>file:///C:/development/svn_example/repos/svn18/main/folder/lalala.txt</url>
+<relative-url>^/folder/lalala.txt</relative-url>
+<repository>
+<root>file:///C:/development/svn_example/repos/svn18/main</root>
+<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
+</repository>
+<wc-info>
+<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
+<schedule>normal</schedule>
+<depth>infinity</depth>
+<text-updated>2013-07-13T15:35:54.015625Z</text-updated>
+<checksum>da39a3ee5e6b4b0d3255bfef95601890afd80709</checksum>
+</wc-info>
+<commit
+ revision="1">
+<author>ptt</author>
+<date>2013-07-13T15:35:54.375000Z</date>
+</commit>
+</entry>
+</info>
diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py
index f26a1f51..95667b69 100644
--- a/setuptools/tests/test_egg_info.py
+++ b/setuptools/tests/test_egg_info.py
@@ -1,10 +1,12 @@
import os
+import sys
import tempfile
import shutil
import unittest
import pkg_resources
from setuptools.command import egg_info
+from setuptools import svn_utils
ENTRIES_V10 = pkg_resources.resource_string(__name__, 'entries-v10')
"An entries file generated with svn 1.6.17 against the legacy Setuptools repo"
@@ -31,6 +33,17 @@ class TestEggInfo(unittest.TestCase):
def test_version_10_format(self):
"""
"""
+ #keeping this set for 1.6 is a good check on the get_svn_revision
+ #to ensure I return using svnversion what would had been returned
+ version_str = svn_utils.SvnInfo.get_svn_version()
+ version = [int(x) for x in version_str.split('.')[:2]]
+ if version != [1,6]:
+ if hasattr(self, 'skipTest'):
+ self.skipTest('')
+ else:
+ sys.stderr.write('\n Skipping due to SVN Version\n')
+ return
+
self._write_entries(ENTRIES_V10)
rev = egg_info.egg_info.get_svn_revision()
self.assertEqual(rev, '89000')
diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py
index 438f7ced..8d6aff19 100644
--- a/setuptools/tests/test_sdist.py
+++ b/setuptools/tests/test_sdist.py
@@ -8,12 +8,14 @@ import sys
import tempfile
import unittest
import unicodedata
+from setuptools.tests import environment
from setuptools.compat import StringIO, unicode
-from setuptools.command.sdist import sdist
+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',
@@ -395,6 +397,64 @@ class TestSdistTest(unittest.TestCase):
self.assertTrue(filename in cmd.filelist.files)
+class TestSvn(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 = "svn%i%i_example" % self.base_version
+ self.datafile = os.path.join('setuptools', 'tests',
+ 'svn_data', self.dataname + ".zip")
+ super(TestSvn, self).setUp()
+
+ def test_walksvn(self):
+ if self.base_version >= (1,6):
+ folder2 = 'third party2'
+ folder3 = 'third party3'
+ else:
+ folder2 = 'third_party2'
+ folder3 = 'third_party3'
+
+ #TODO is this right
+ expected = set([
+ os.path.join('a file'),
+ os.path.join(folder2, 'Changes.txt'),
+ os.path.join(folder2, 'MD5SUMS'),
+ os.path.join(folder2, 'README.txt'),
+ os.path.join(folder3, 'Changes.txt'),
+ os.path.join(folder3, 'MD5SUMS'),
+ os.path.join(folder3, 'README.txt'),
+ os.path.join(folder3, 'TODO.txt'),
+ os.path.join(folder3, 'fin'),
+ os.path.join('third_party', 'README.txt'),
+ os.path.join('folder', folder2, 'Changes.txt'),
+ os.path.join('folder', folder2, 'MD5SUMS'),
+ os.path.join('folder', folder2, 'WatashiNiYomimasu.txt'),
+ os.path.join( 'folder', folder3, 'Changes.txt'),
+ os.path.join('folder', folder3, 'fin'),
+ os.path.join('folder', folder3, 'MD5SUMS'),
+ os.path.join('folder', folder3, 'oops'),
+ os.path.join('folder', folder3, 'WatashiNiYomimasu.txt'),
+ os.path.join('folder', folder3, 'ZuMachen.txt'),
+ os.path.join('folder', 'third_party', 'WatashiNiYomimasu.txt'),
+ os.path.join('folder', 'lalala.txt'),
+ 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__)
diff --git a/setuptools/tests/test_svn.py b/setuptools/tests/test_svn.py
index 6036f85c..4a6e7eff 100644
--- a/setuptools/tests/test_svn.py
+++ b/setuptools/tests/test_svn.py
@@ -3,77 +3,20 @@
import os
-import zipfile
import sys
-import tempfile
import unittest
-import shutil
-import stat
+import codecs
+from setuptools.tests import environment
+from setuptools.svn_utils import fsencode
+from setuptools.compat import unicode, unichr
from setuptools import svn_utils
-from setuptools.command import egg_info
-from setuptools.command import sdist
#requires python >= 2.4
from subprocess import call as _call
-def _extract(self, member, path=None, pwd=None):
- """for zipfile py2.5 borrowed from cpython"""
- if not isinstance(member, zipfile.ZipInfo):
- member = self.getinfo(member)
+from distutils import log
- if path is None:
- path = os.getcwd()
-
- return _extract_member(self, member, path, pwd)
-
-def _extract_from_zip(self, name, dest_path):
- dest_file = open(dest_path, 'wb')
- try:
- dest_file.write(self.read(name))
- finally:
- dest_file.close()
-
-def _extract_member(self, member, targetpath, pwd):
- """for zipfile py2.5 borrowed from cpython"""
- # build the destination pathname, replacing
- # forward slashes to platform specific separators.
- # Strip trailing path separator, unless it represents the root.
- if (targetpath[-1:] in (os.path.sep, os.path.altsep)
- and len(os.path.splitdrive(targetpath)[1]) > 1):
- targetpath = targetpath[:-1]
-
- # don't include leading "/" from file name if present
- if member.filename[0] == '/':
- targetpath = os.path.join(targetpath, member.filename[1:])
- else:
- targetpath = os.path.join(targetpath, member.filename)
-
- targetpath = os.path.normpath(targetpath)
-
- # Create all upper directories if necessary.
- upperdirs = os.path.dirname(targetpath)
- if upperdirs and not os.path.exists(upperdirs):
- os.makedirs(upperdirs)
-
- if member.filename[-1] == '/':
- if not os.path.isdir(targetpath):
- os.mkdir(targetpath)
- return targetpath
-
- _extract_from_zip(self, member.filename, targetpath)
-
- return targetpath
-
-
-def _remove_dir(target):
-
- #on windows this seems to a problem
- for dir_path, dirs, files in os.walk(target):
- os.chmod(dir_path, stat.S_IWRITE)
- for filename in files:
- os.chmod(os.path.join(dir_path, filename), stat.S_IWRITE)
- shutil.rmtree(target)
class TestSvnVersion(unittest.TestCase):
@@ -90,81 +33,207 @@ class TestSvnVersion(unittest.TestCase):
old_path = os.environ[path_variable]
os.environ[path_variable] = ''
try:
- version = svn_utils.get_svn_tool_version()
+ version = svn_utils.SvnInfo.get_svn_version()
self.assertEqual(version, '')
finally:
os.environ[path_variable] = old_path
def test_svn_should_exist(self):
- version = svn_utils.get_svn_tool_version()
+ version = svn_utils.SvnInfo.get_svn_version()
self.assertNotEqual(version, '')
+def _read_utf8_file(path):
+ fileobj = None
+ try:
+ fileobj = codecs.open(path, 'r', 'utf-8')
+ data = fileobj.read()
+ return data
+ finally:
+ if fileobj:
+ fileobj.close()
-class TestSvn_1_7(unittest.TestCase):
- def setUp(self):
- version = svn_utils.get_svn_tool_version()
- ver_list = [int(x) for x in version.split('.')]
- if ver_list < [1,7,0]:
- self.version_err = 'Insufficent Subversion (%s)' % version
+class ParserInfoXML(unittest.TestCase):
+
+ def parse_tester(self, svn_name, ext_spaces):
+ path = os.path.join('setuptools', 'tests',
+ 'svn_data', svn_name + '_info.xml')
+ #Remember these are pre-generated to test XML parsing
+ # so these paths might not valid on your system
+ example_base = "%s_example" % svn_name
+
+ data = _read_utf8_file(path)
+
+ if ext_spaces:
+ folder2 = 'third party2'
+ folder3 = 'third party3'
else:
- self.version_err = None
+ folder2 = 'third_party2'
+ folder3 = 'third_party3'
+ expected = set([
+ ("\\".join((example_base, 'a file')), 'file'),
+ ("\\".join((example_base, 'folder')), 'dir'),
+ ("\\".join((example_base, 'folder', 'lalala.txt')), 'file'),
+ ("\\".join((example_base, 'folder', 'quest.txt')), 'file'),
+ ])
+ self.assertEqual(set(x for x in svn_utils.parse_dir_entries(data)),
+ expected)
- self.temp_dir = tempfile.mkdtemp()
- zip_file, source, target = [None, None, None]
- try:
- zip_file = zipfile.ZipFile(os.path.join('setuptools', 'tests',
- 'svn17_example.zip'))
- for files in zip_file.namelist():
- _extract(zip_file, files, self.temp_dir)
- finally:
- if zip_file:
- zip_file.close()
- del zip_file
+ def test_svn13(self):
+ self.parse_tester('svn13', False)
- self.old_cwd = os.getcwd()
- os.chdir(os.path.join(self.temp_dir, 'svn17_example'))
+ def test_svn14(self):
+ self.parse_tester('svn14', False)
- def tearDown(self):
- try:
- os.chdir(self.old_cwd)
- _remove_dir(self.temp_dir)
- except OSError:
- #sigh?
- pass
-
- def _chk_skip(self):
- if self.version_err is not None:
- if hasattr(self, 'skipTest'):
- self.skipTest(self.version_err)
- else:
- sys.stderr.write(self.version_error + "\n")
- return True
- return False
-
- def test_egg_info(self):
- if self._chk_skip:
- return
-
- rev = egg_info.egg_info.get_svn_revision()
- self.assertEqual(rev, '4')
-
- def test_iterator(self):
- if self._chk_skip:
- return
+ def test_svn15(self):
+ self.parse_tester('svn15', False)
+
+ def test_svn16(self):
+ self.parse_tester('svn16', True)
+
+ def test_svn17(self):
+ self.parse_tester('svn17', True)
+
+ def test_svn18(self):
+ self.parse_tester('svn18', True)
+
+class ParserExternalXML(unittest.TestCase):
+
+ def parse_tester(self, svn_name, ext_spaces):
+ path = os.path.join('setuptools', 'tests',
+ 'svn_data', svn_name + '_ext_list.xml')
+ example_base = svn_name + '_example'
+ data = _read_utf8_file(path)
+
+ if ext_spaces:
+ folder2 = 'third party2'
+ folder3 = 'third party3'
+ else:
+ folder2 = 'third_party2'
+ folder3 = 'third_party3'
expected = set([
- os.path.join('.', 'readme.txt'),
- os.path.join('.', 'other'),
- os.path.join('.', 'third_party'),
- os.path.join('.', 'third_party2'),
- os.path.join('.', 'third_party3'),
+ "\\".join((example_base, folder2)),
+ "\\".join((example_base, folder3)),
+ #third_party大介
+ "\\".join((example_base,
+ unicode('third_party') +
+ unichr(0x5927) + unichr(0x4ecb))),
+ "\\".join((example_base, 'folder', folder2)),
+ "\\".join((example_base, 'folder', folder3)),
+ "\\".join((example_base, 'folder',
+ unicode('third_party') +
+ unichr(0x5927) + unichr(0x4ecb))),
])
- self.assertEqual(set(x for x
- in sdist.entries_externals_finder('.', '')),
+
+ dir_base = r'c:\development\svn_example'
+ self.assertEqual(set(x for x \
+ in svn_utils.parse_externals_xml(data, dir_base)), expected)
+
+ def test_svn15(self):
+ self.parse_tester('svn15', False)
+
+ def test_svn16(self):
+ self.parse_tester('svn16', True)
+
+ def test_svn17(self):
+ self.parse_tester('svn17', True)
+
+ def test_svn18(self):
+ self.parse_tester('svn18', True)
+
+
+class ParseExternal(unittest.TestCase):
+
+ def parse_tester(self, svn_name, ext_spaces):
+ path = os.path.join('setuptools', 'tests',
+ 'svn_data', svn_name + '_ext_list.txt')
+ example_base = svn_name + '_example'
+ data = _read_utf8_file(path)
+
+ if ext_spaces:
+ expected = set(['third party2', 'third party3',
+ 'third party3b', 'third_party'])
+ else:
+ expected = set(['third_party2', 'third_party3', 'third_party'])
+
+ self.assertEqual(set(x for x in svn_utils.parse_external_prop(data)),
expected)
+ def test_svn13(self):
+ self.parse_tester('svn13', False)
+
+ def test_svn14(self):
+ self.parse_tester('svn14', False)
+
+ def test_svn15(self):
+ self.parse_tester('svn15', False)
+
+ def test_svn16(self):
+ self.parse_tester('svn16', True)
+
+ def test_svn17(self):
+ self.parse_tester('svn17', True)
+
+ def test_svn18(self):
+ self.parse_tester('svn18', True)
+
+
+class TestSvn(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 = "svn%i%i_example" % self.base_version
+ self.datafile = os.path.join('setuptools', 'tests',
+ 'svn_data', self.dataname + ".zip")
+ super(TestSvn, self).setUp()
+
+ def test_revision(self):
+ rev = svn_utils.SvnInfo.load('.').get_revision()
+ self.assertEqual(rev, 6)
+
+ def test_entries(self):
+ expected = set([
+ (os.path.join('a file'), 'file'),
+ (os.path.join('folder'), 'dir'),
+ (os.path.join('folder', 'lalala.txt'), 'file'),
+ (os.path.join('folder', 'quest.txt'), 'file'),
+ #The example will have a deleted file (or should)
+ #but shouldn't return it
+ ])
+ info = svn_utils.SvnInfo.load('.')
+ self.assertEqual(set(x for x in info.entries), expected)
+
+ def test_externals(self):
+ if self.base_version >= (1,6):
+ folder2 = 'third party2'
+ folder3 = 'third party3'
+ else:
+ folder2 = 'third_party2'
+ folder3 = 'third_party3'
+
+ expected = set([
+ os.path.join(folder2),
+ os.path.join(folder3),
+ os.path.join('third_party'),
+ os.path.join('folder', folder2),
+ os.path.join('folder', folder3),
+ os.path.join('folder', 'third_party'),
+ ])
+ info = svn_utils.SvnInfo.load('.')
+ self.assertEqual(set([x for x in info.externals]), expected)
+
def test_suite():
return unittest.defaultTestLoader.loadTestsFromName(__name__)