Commit a7e5648b authored by Jason R. Coombs's avatar Jason R. Coombs

Removed svn support from setuptools. Ref #313.

parent 21f75391
......@@ -172,9 +172,6 @@ setup_params = dict(
],
"console_scripts": console_scripts,
"setuptools.file_finders":
["svn_cvs = setuptools.command.sdist:_default_revctrl"],
"setuptools.installation":
['eggsecutable = setuptools.command.easy_install:bootstrap'],
},
......
......@@ -11,10 +11,14 @@ import os
import re
import sys
try:
from setuptools_svn import svn_utils
except ImportError:
pass
from setuptools import Command
from setuptools.command.sdist import sdist
from setuptools.compat import basestring, PY3, StringIO
from setuptools import svn_utils
from setuptools.command.sdist import walk_revctrl
from pkg_resources import (
parse_requirements, safe_name, parse_version,
......@@ -190,6 +194,8 @@ class egg_info(Command):
@staticmethod
def get_svn_revision():
if 'svn_utils' not in globals():
return "0"
return str(svn_utils.SvnInfo.load(os.curdir).get_revision())
def find_sources(self):
......
from glob import glob
from distutils.util import convert_path
from distutils import log
import distutils.command.sdist as orig
import os
import re
import sys
from setuptools import svn_utils
from setuptools.compat import PY3
from setuptools.utils import cs_path_exists
......@@ -22,60 +19,6 @@ def walk_revctrl(dirname=''):
yield item
# TODO will need test case
class re_finder(object):
"""
Finder that locates files based on entries in a file matched by a
regular expression.
"""
def __init__(self, path, pattern, postproc=lambda x: x):
self.pattern = pattern
self.postproc = postproc
self.entries_path = convert_path(path)
def _finder(self, dirname, filename):
f = open(filename, 'rU')
try:
data = f.read()
finally:
f.close()
for match in self.pattern.finditer(data):
path = match.group(1)
# postproc was formerly used when the svn finder
# was an re_finder for calling unescape
path = self.postproc(path)
yield svn_utils.joinpath(dirname, path)
def find(self, dirname=''):
path = svn_utils.joinpath(dirname, self.entries_path)
if not os.path.isfile(path):
# entries file doesn't exist
return
for path in self._finder(dirname, path):
if os.path.isfile(path):
yield path
elif os.path.isdir(path):
for item in self.find(path):
yield item
__call__ = find
def _default_revctrl(dirname=''):
'Primary svn_cvs entry point'
for finder in finders:
for item in finder(dirname):
yield item
finders = [
re_finder('CVS/Entries', re.compile(r"^\w?/([^/]+)/", re.M)),
svn_utils.svn_finder,
]
class sdist(orig.sdist):
"""Smart sdist that finds anything supported by revision control"""
......
from __future__ import absolute_import
import os
import re
import sys
from distutils import log
import xml.dom.pulldom
import shlex
import locale
import codecs
import unicodedata
import warnings
from setuptools.compat import unicode, PY2
from setuptools.py31compat import TemporaryDirectory
from xml.sax.saxutils import unescape
try:
import urlparse
except ImportError:
import urllib.parse as urlparse
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 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:
# http://bugs.python.org/issue8557
# http://stackoverflow.com/questions/5658622/
# python-subprocess-popen-environment-path
def _run_command(args, stdout=_PIPE, stderr=_PIPE, encoding=None, stream=0):
#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()[stream]
except OSError:
return 1, ''
#doubled checked and
data = decode_as_string(data, encoding)
#communciate calls wait()
return proc.returncode, data
def _get_entry_schedule(entry):
schedule = entry.getElementsByTagName('schedule')[0]
return "".join([t.nodeValue
for t in schedule.childNodes
if t.nodeType == t.TEXT_NODE])
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])
def _get_xml_data(decoded_str):
if PY2:
#old versions want an encoded string
data = decoded_str.encode('utf-8')
else:
data = decoded_str
return data
def joinpath(prefix, *suffix):
if not prefix or prefix == '.':
return os.path.join(*suffix)
return os.path.join(prefix, *suffix)
def determine_console_encoding():
try:
#try for the preferred encoding
encoding = locale.getpreferredencoding()
#see if the locale.getdefaultlocale returns null
#some versions of python\platforms return US-ASCII
#when it cannot determine an encoding
if not encoding or encoding == "US-ASCII":
encoding = locale.getdefaultlocale()[1]
if encoding:
codecs.lookup(encoding) # make sure a lookup error is not made
except (locale.Error, LookupError):
encoding = None
is_osx = sys.platform == "darwin"
if not encoding:
return ["US-ASCII", "utf-8"][is_osx]
elif encoding.startswith("mac-") and is_osx:
#certain versions of python would return mac-roman as default
#OSX as a left over of earlier mac versions.
return "utf-8"
else:
return encoding
_console_encoding = determine_console_encoding()
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 = _console_encoding
if not isinstance(text, unicode):
text = text.decode(encoding)
text = unicodedata.normalize('NFC', text)
return text
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)
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
def parse_externals_xml(decoded_str, prefix=''):
'''Parse a propget svn:externals xml'''
prefix = os.path.normpath(prefix)
prefix = os.path.normcase(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:]
data = _get_target_property(node)
#data should be decoded already
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.splitlines():
line = line.lstrip() # there might be a "\ "
if not line:
continue
if PY2:
#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 PY2:
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]:
external = line[0]
else:
external = line[-1]
external = decode_as_string(external, encoding="utf-8")
externals.append(os.path.normpath(external))
return externals
def parse_prop_file(filename, key):
found = False
f = open(filename, 'rt')
data = ''
try:
for line in iter(f.readline, ''): # can't use direct iter!
parts = line.split()
if len(parts) == 2:
kind, length = parts
data = f.read(int(length))
if kind == 'K' and data == key:
found = True
elif kind == 'V' and found:
break
finally:
f.close()
return data
class SvnInfo(object):
'''
Generic svn_info object. No has little knowledge of how to extract
information. Use cls.load to instatiate according svn version.
Paths are not filesystem encoded.
'''
@staticmethod
def get_svn_version():
# Temp config directory should be enough to check for repository
# This is needed because .svn always creates .subversion and
# some operating systems do not handle dot directory correctly.
# Real queries in real svn repos with be concerned with it creation
with TemporaryDirectory() as tempdir:
code, data = _run_command(['svn',
'--config-dir', tempdir,
'--version',
'--quiet'])
if code == 0 and data:
return data.strip()
else:
return ''
#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=''):
normdir = os.path.normpath(dirname)
# Temp config directory should be enough to check for repository
# This is needed because .svn always creates .subversion and
# some operating systems do not handle dot directory correctly.
# Real queries in real svn repos with be concerned with it creation
with TemporaryDirectory() as tempdir:
code, data = _run_command(['svn',
'--config-dir', tempdir,
'info', normdir])
# Must check for some contents, as some use empty directories
# in testcases, however only enteries is needed also the info
# command above MUST have worked
svn_dir = os.path.join(normdir, '.svn')
is_svn_wd = (not code or
os.path.isfile(os.path.join(svn_dir, 'entries')))
svn_version = tuple(cls.get_svn_version().split('.'))
try:
base_svn_version = tuple(int(x) for x in svn_version[:2])
except ValueError:
base_svn_version = tuple()
if not is_svn_wd:
#return an instance of this NO-OP class
return SvnInfo(dirname)
if code or not base_svn_version or base_svn_version < (1, 3):
warnings.warn(("No SVN 1.3+ command found: falling back "
"on pre 1.7 .svn parsing"), DeprecationWarning)
return SvnFileInfo(dirname)
if base_svn_version < (1, 5):
return Svn13Info(dirname)
return Svn15Info(dirname)
def __init__(self, path=''):
self.path = path
self._entries = None
self._externals = None
def get_revision(self):
'Retrieve the directory revision information using svnversion'
code, data = _run_command(['svnversion', '-c', self.path])
if code:
log.warn("svnversion failed")
return 0
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],
encoding="utf-8")
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], 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)
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, encoding="utf-8")
if code:
log.debug("svn propget failed")
return []
return parse_externals_xml(lines, prefix=os.path.abspath(self.path))
class SvnFileInfo(SvnInfo):
def __init__(self, path=''):
super(SvnFileInfo, self).__init__(path)
self._directories = None
self._revision = None
def _walk_svn(self, base):
entry_file = joinpath(base, '.svn', 'entries')
if os.path.isfile(entry_file):
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)
elif os.path.isdir(path):
for item in self._walk_svn(path):
yield item
def _build_entries(self):
entries = list()
rev = 0
for path, isfile, dir_rev in self._walk_svn(self.path):
if isfile:
entries.append((path, 'file'))
else:
entries.append((path, 'dir'))
rev = max(rev, dir_rev)
self._entries = entries
self._revision = rev
def get_entries(self):
if self._entries is None:
self._build_entries()
return self._entries
def get_revision(self):
if self._revision is None:
self._build_entries()
return self._revision
def get_externals(self):
prop_files = [['.svn', 'dir-prop-base'],
['.svn', 'dir-props']]
externals = []
for dirname in self.iter_dirs():
prop_file = None
for rel_parts in prop_files:
filename = joinpath(dirname, *rel_parts)
if os.path.isfile(filename):
prop_file = filename
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
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 path
for path in info.iter_externals():
sub_info = SvnInfo.load(path)
for sub_path in sub_info.iter_files():
yield sub_path
class SVNEntriesFile(object):
def __init__(self, data):
self.data = data
@classmethod
def load(class_, base):
filename = os.path.join(base, '.svn', 'entries')
f = open(filename)
try:
result = SVNEntriesFile.read(f)
finally:
f.close()
return result
@classmethod
def read(class_, fileobj):
data = fileobj.read()
is_xml = data.startswith('<?xml')
class_ = [SVNEntriesFileText, SVNEntriesFileXML][is_xml]
return class_(data)
def parse_revision(self):
all_revs = self.parse_revision_numbers() + [0]
return max(all_revs)
class SVNEntriesFileText(SVNEntriesFile):
known_svn_versions = {
'1.4.x': 8,
'1.5.x': 9,
'1.6.x': 10,
}
def __get_cached_sections(self):
return self.sections
def get_sections(self):
SECTION_DIVIDER = '\f\n'
sections = self.data.split(SECTION_DIVIDER)
sections = [x for x in map(str.splitlines, sections)]
try:
# remove the SVN version number from the first line
svn_version = int(sections[0].pop(0))
if not svn_version in self.known_svn_versions.values():
log.warn("Unknown subversion verson %d", svn_version)
except ValueError:
return
self.sections = sections
self.get_sections = self.__get_cached_sections
return self.sections
def is_valid(self):
return bool(self.get_sections())
def get_url(self):
return self.get_sections()[0][4]
def parse_revision_numbers(self):
revision_line_number = 9
rev_numbers = [
int(section[revision_line_number])
for section in self.get_sections()
if (len(section) > revision_line_number
and section[revision_line_number])
]
return rev_numbers
def get_undeleted_records(self):
undeleted = lambda s: s and s[0] and (len(s) < 6 or s[5] != 'delete')
result = [
section[0]
for section in self.get_sections()
if undeleted(section)
]
return result
class SVNEntriesFileXML(SVNEntriesFile):
def is_valid(self):
return True
def get_url(self):
"Get repository URL"
urlre = re.compile('url="([^"]+)"')
return urlre.search(self.data).group(1)
def parse_revision_numbers(self):
revre = re.compile(r'committed-rev="(\d+)"')
return [
int(m.group(1))
for m in revre.finditer(self.data)
]
def get_undeleted_records(self):
entries_pattern = \
re.compile(r'name="([^"]+)"(?![^>]+deleted="true")', re.I)
results = [
unescape(match.group(1))
for match in entries_pattern.finditer(self.data)
]
return results
if __name__ == '__main__':
for name in svn_finder(sys.argv[1]):
print(name)
import os
import zipfile
import sys
import tempfile
import unittest
import shutil
import stat
import unicodedata
from subprocess import Popen as _Popen, PIPE as _PIPE
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 self.datafile is None or self.dataname is None:
return
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():
zip_file.extract(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):
#Assume setUp was never completed
if self.dataname is None or self.datafile is None:
return
try:
if self.old_cwd:
os.chdir(self.old_cwd)
_remove_dir(self.temp_dir)
except OSError:
#sigh?
pass
def _which_dirs(cmd):
result = set()
for path in os.environ.get('PATH', '').split(os.pathsep):
......
import distutils.core
import os
import sys
import tempfile
import shutil
import stat
import unittest
import pkg_resources
import warnings
from setuptools.command import egg_info
from setuptools import svn_utils
from setuptools.tests import environment, test_svn
from setuptools.tests.py26compat import skipIf
ENTRIES_V10 = pkg_resources.resource_string(__name__, 'entries-v10')
"An entries file generated with svn 1.6.17 against the legacy Setuptools repo"
from . import environment
class TestEggInfo(unittest.TestCase):
def setUp(self):
self.test_dir = tempfile.mkdtemp()
os.mkdir(os.path.join(self.test_dir, '.svn'))
self.old_cwd = os.getcwd()
os.chdir(self.test_dir)
......@@ -31,12 +19,6 @@ class TestEggInfo(unittest.TestCase):
os.chdir(self.old_cwd)
shutil.rmtree(self.test_dir)
def _write_entries(self, entries):
fn = os.path.join(self.test_dir, '.svn', 'entries')
entries_f = open(fn, 'wb')
entries_f.write(entries)
entries_f.close()
def _create_project(self):
with open('setup.py', 'w') as f:
f.write('from setuptools import setup\n')
......@@ -51,52 +33,6 @@ class TestEggInfo(unittest.TestCase):
f.write('def run():\n')
f.write(" print('hello')\n")
@skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
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')
def test_version_10_format_legacy_parser(self):
"""
"""
path_variable = None
for env in os.environ:
if env.lower() == 'path':
path_variable = env
if path_variable:
old_path = os.environ[path_variable]
os.environ[path_variable] = ''
#catch_warnings not available until py26
warning_filters = warnings.filters
warnings.filters = warning_filters[:]
try:
warnings.simplefilter("ignore", DeprecationWarning)
self._write_entries(ENTRIES_V10)
rev = egg_info.egg_info.get_svn_revision()
finally:
#restore the warning filters
warnings.filters = warning_filters
#restore the os path
if path_variable:
os.environ[path_variable] = old_path
self.assertEqual(rev, '89000')
def test_egg_base_installed_egg_info(self):
self._create_project()
temp_dir = tempfile.mkdtemp(prefix='setuptools-test.')
......@@ -139,130 +75,5 @@ class TestEggInfo(unittest.TestCase):
shutil.rmtree(temp_dir)
DUMMY_SOURCE_TXT = """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"""
class TestSvnDummy(environment.ZippedEnvironment):
def setUp(self):
version = svn_utils.SvnInfo.get_svn_version()
if not version: # None or Empty
return None
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()
@skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
def test_sources(self):
code, data = environment.run_setup_py(["sdist"],
pypath=self.old_cwd,
data_stream=1)
if code:
raise AssertionError(data)
sources = os.path.join('dummy.egg-info', 'SOURCES.txt')
infile = open(sources, 'r')
try:
read_contents = infile.read()
finally:
infile.close()
del infile
self.assertEqual(DUMMY_SOURCE_TXT, read_contents)
return data
@skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
def test_svn_tags(self):
code, data = environment.run_setup_py(["egg_info",
"--tag-svn-revision"],
pypath=self.old_cwd,
data_stream=1)
if code:
raise AssertionError(data)
pkginfo = os.path.join('dummy.egg-info', 'PKG-INFO')
infile = open(pkginfo, 'r')
try:
read_contents = infile.readlines()
finally:
infile.close()
del infile
self.assertTrue("Version: 0.1.1.post1\n" in read_contents)
@skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
def test_no_tags(self):
code, data = environment.run_setup_py(["egg_info"],
pypath=self.old_cwd,
data_stream=1)
if code:
raise AssertionError(data)
pkginfo = os.path.join('dummy.egg-info', 'PKG-INFO')
infile = open(pkginfo, 'r')
try:
read_contents = infile.readlines()
finally:
infile.close()
del infile
self.assertTrue("Version: 0.1.1\n" in read_contents)
class TestSvnDummyLegacy(environment.ZippedEnvironment):
def setUp(self):
self.base_version = (1, 6)
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 test_sources(self):
code, data = environment.run_setup_py(["sdist"],
pypath=self.old_cwd,
path="",
data_stream=1)
if code:
raise AssertionError(data)
sources = os.path.join('dummy.egg-info', 'SOURCES.txt')
infile = open(sources, 'r')
try:
read_contents = infile.read()
finally:
infile.close()
del infile
self.assertEqual(DUMMY_SOURCE_TXT, read_contents)
return data
def test_suite():
return unittest.defaultTestLoader.loadTestsFromName(__name__)
......@@ -8,16 +8,13 @@ import sys
import tempfile
import unittest
import unicodedata
import re
import contextlib
from setuptools.tests import environment, test_svn
from setuptools.tests.py26compat import skipIf
from setuptools.compat import StringIO, unicode, PY3, PY2
from setuptools.command.sdist import sdist, walk_revctrl
from setuptools.command.sdist import sdist
from setuptools.command.egg_info import manifest_maker
from setuptools.dist import Distribution
from setuptools import svn_utils
SETUP_ATTRS = {
'name': 'sdist_test',
......@@ -418,135 +415,6 @@ class TestSdistTest(unittest.TestCase):
except UnicodeDecodeError:
self.assertFalse(filename in cmd.filelist.files)
class TestDummyOutput(environment.ZippedEnvironment):
def setUp(self):
self.datafile = os.path.join('setuptools', 'tests',
'svn_data', "dummy.zip")
self.dataname = "dummy"
super(TestDummyOutput, self).setUp()
def _run(self):
code, data = environment.run_setup_py(["sdist"],
pypath=self.old_cwd,
data_stream=0)
if code:
info = "DIR: " + os.path.abspath('.')
info += "\n SDIST RETURNED: %i\n\n" % code
info += data
raise AssertionError(info)
datalines = data.splitlines()
possible = (
"running sdist",
"running egg_info",
"creating dummy\.egg-info",
"writing dummy\.egg-info",
"writing top-level names to dummy\.egg-info",
"writing dependency_links to dummy\.egg-info",
"writing manifest file 'dummy\.egg-info",
"reading manifest file 'dummy\.egg-info",
"reading manifest template 'MANIFEST\.in'",
"writing manifest file 'dummy\.egg-info",
"creating dummy-0.1.1",
"making hard links in dummy-0\.1\.1",
"copying files to dummy-0\.1\.1",
"copying \S+ -> dummy-0\.1\.1",
"copying dummy",
"copying dummy\.egg-info",
"hard linking \S+ -> dummy-0\.1\.1",
"hard linking dummy",
"hard linking dummy\.egg-info",
"Writing dummy-0\.1\.1",
"creating dist",
"creating 'dist",
"Creating tar archive",
"running check",
"adding 'dummy-0\.1\.1",
"tar .+ dist/dummy-0\.1\.1\.tar dummy-0\.1\.1",
"gzip .+ dist/dummy-0\.1\.1\.tar",
"removing 'dummy-0\.1\.1' \\(and everything under it\\)",
)
print(" DIR: " + os.path.abspath('.'))
for line in datalines:
found = False
for pattern in possible:
if re.match(pattern, line):
print(" READ: " + line)
found = True
break
if not found:
raise AssertionError("Unexpexected: %s\n-in-\n%s"
% (line, data))
return data
def test_sources(self):
self._run()
class TestSvn(environment.ZippedEnvironment):
def setUp(self):
version = svn_utils.SvnInfo.get_svn_version()
if not version: # None or Empty
return
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()
@skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
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
])
self.assertEqual(set(x for x in walk_revctrl()), expected)
def test_suite():
return unittest.defaultTestLoader.loadTestsFromName(__name__)
# -*- coding: utf-8 -*-
"""svn tests"""
import io
import os
import subprocess
import sys
import unittest
from setuptools.tests import environment
from setuptools.compat import unicode, unichr
from setuptools import svn_utils
from setuptools.tests.py26compat import skipIf
def _do_svn_check():
try:
subprocess.check_call(["svn", "--version"],
shell=(sys.platform == 'win32'))
return True
except (OSError, subprocess.CalledProcessError):
return False
_svn_check = _do_svn_check()
class TestSvnVersion(unittest.TestCase):
def test_no_svn_found(self):
path_variable = None
for env in os.environ:
if env.lower() == 'path':
path_variable = env
if path_variable is None:
try:
self.skipTest('Cannot figure out how to modify path')
except AttributeError: # PY26 doesn't have this
return
old_path = os.environ[path_variable]
os.environ[path_variable] = ''
try:
version = svn_utils.SvnInfo.get_svn_version()
self.assertEqual(version, '')
finally:
os.environ[path_variable] = old_path
@skipIf(not _svn_check, "No SVN to text, in the first place")
def test_svn_should_exist(self):
version = svn_utils.SvnInfo.get_svn_version()
self.assertNotEqual(version, '')
def _read_utf8_file(path):
fileobj = None
try:
fileobj = io.open(path, 'r', encoding='utf-8')
data = fileobj.read()
return data
finally:
if fileobj:
fileobj.close()
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)
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)
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 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.sep.join((example_base, folder2)),
os.sep.join((example_base, folder3)),
# folder is third_party大介
os.sep.join((example_base,
unicode('third_party') +
unichr(0x5927) + unichr(0x4ecb))),
os.sep.join((example_base, 'folder', folder2)),
os.sep.join((example_base, 'folder', folder3)),
os.sep.join((example_base, 'folder',
unicode('third_party') +
unichr(0x5927) + unichr(0x4ecb))),
])
expected = set(os.path.normpath(x) for x in expected)
dir_base = os.sep.join(('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')
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()
if not version: # empty or null
self.dataname = None
self.datafile = None
return
self.base_version = tuple([int(x) for x in version.split('.')[:2]])
if 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()
@skipIf(not _svn_check, "No SVN to text, in the first place")
def test_revision(self):
rev = svn_utils.SvnInfo.load('.').get_revision()
self.assertEqual(rev, 6)
@skipIf(not _svn_check, "No SVN to text, in the first place")
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)
@skipIf(not _svn_check, "No SVN to text, in the first place")
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__)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment