aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilip Thiem <ptthiem@gmail.com>2013-09-28 12:14:12 -0500
committerPhilip Thiem <ptthiem@gmail.com>2013-09-28 12:14:12 -0500
commit30bb58f069cf1624f35cfbdb725e8e443ff64330 (patch)
tree394bf476bc9618fd89edab8249c5f945caaf3617
parent8c645eb0c310e8ff4efe73849279ea391d25bced (diff)
downloadexternal_python_setuptools-30bb58f069cf1624f35cfbdb725e8e443ff64330.tar.gz
external_python_setuptools-30bb58f069cf1624f35cfbdb725e8e443ff64330.tar.bz2
external_python_setuptools-30bb58f069cf1624f35cfbdb725e8e443ff64330.zip
Added a legacy fallback test
Added in code to after a deprecation warning parse the .svn files Should also parse externals. --HG-- extra : rebase_source : 9dd3bcf22cb56eb0826051f9e477f155e47cdbf6
-rw-r--r--setuptools.egg-info/entry_points.txt124
-rw-r--r--setuptools.egg-info/requires.txt8
-rw-r--r--setuptools/svn_utils.py240
-rw-r--r--setuptools/tests/test_egg_info.py21
4 files changed, 310 insertions, 83 deletions
diff --git a/setuptools.egg-info/entry_points.txt b/setuptools.egg-info/entry_points.txt
index d64b3c28..478fac7d 100644
--- a/setuptools.egg-info/entry_points.txt
+++ b/setuptools.egg-info/entry_points.txt
@@ -1,62 +1,62 @@
-[setuptools.installation]
-eggsecutable = setuptools.command.easy_install:bootstrap
-
-[console_scripts]
-easy_install = setuptools.command.easy_install:main
-easy_install-3.3 = setuptools.command.easy_install:main
-
-[distutils.setup_keywords]
-use_2to3 = setuptools.dist:assert_bool
-namespace_packages = setuptools.dist:check_nsp
-package_data = setuptools.dist:check_package_data
-use_2to3_exclude_fixers = setuptools.dist:assert_string_list
-dependency_links = setuptools.dist:assert_string_list
-use_2to3_fixers = setuptools.dist:assert_string_list
-test_suite = setuptools.dist:check_test_suite
-exclude_package_data = setuptools.dist:check_package_data
-extras_require = setuptools.dist:check_extras
-install_requires = setuptools.dist:check_requirements
-eager_resources = setuptools.dist:assert_string_list
-include_package_data = setuptools.dist:assert_bool
-packages = setuptools.dist:check_packages
-entry_points = setuptools.dist:check_entry_points
-zip_safe = setuptools.dist:assert_bool
-tests_require = setuptools.dist:check_requirements
-convert_2to3_doctests = setuptools.dist:assert_string_list
-test_loader = setuptools.dist:check_importable
-
-[setuptools.file_finders]
-svn_cvs = setuptools.command.sdist:_default_revctrl
-
-[egg_info.writers]
-top_level.txt = setuptools.command.egg_info:write_toplevel_names
-PKG-INFO = setuptools.command.egg_info:write_pkg_info
-eager_resources.txt = setuptools.command.egg_info:overwrite_arg
-namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
-depends.txt = setuptools.command.egg_info:warn_depends_obsolete
-dependency_links.txt = setuptools.command.egg_info:overwrite_arg
-entry_points.txt = setuptools.command.egg_info:write_entries
-requires.txt = setuptools.command.egg_info:write_requirements
-
-[distutils.commands]
-test = setuptools.command.test:test
-bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
-alias = setuptools.command.alias:alias
-sdist = setuptools.command.sdist:sdist
-develop = setuptools.command.develop:develop
-bdist_egg = setuptools.command.bdist_egg:bdist_egg
-setopt = setuptools.command.setopt:setopt
-egg_info = setuptools.command.egg_info:egg_info
-build_ext = setuptools.command.build_ext:build_ext
-upload_docs = setuptools.command.upload_docs:upload_docs
-easy_install = setuptools.command.easy_install:easy_install
-install = setuptools.command.install:install
-install_egg_info = setuptools.command.install_egg_info:install_egg_info
-bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
-install_lib = setuptools.command.install_lib:install_lib
-rotate = setuptools.command.rotate:rotate
-saveopts = setuptools.command.saveopts:saveopts
-install_scripts = setuptools.command.install_scripts:install_scripts
-build_py = setuptools.command.build_py:build_py
-register = setuptools.command.register:register
-
+[setuptools.installation]
+eggsecutable = setuptools.command.easy_install:bootstrap
+
+[console_scripts]
+easy_install = setuptools.command.easy_install:main
+easy_install-3.3 = setuptools.command.easy_install:main
+
+[distutils.setup_keywords]
+use_2to3 = setuptools.dist:assert_bool
+namespace_packages = setuptools.dist:check_nsp
+package_data = setuptools.dist:check_package_data
+use_2to3_exclude_fixers = setuptools.dist:assert_string_list
+dependency_links = setuptools.dist:assert_string_list
+use_2to3_fixers = setuptools.dist:assert_string_list
+test_suite = setuptools.dist:check_test_suite
+exclude_package_data = setuptools.dist:check_package_data
+extras_require = setuptools.dist:check_extras
+install_requires = setuptools.dist:check_requirements
+eager_resources = setuptools.dist:assert_string_list
+include_package_data = setuptools.dist:assert_bool
+packages = setuptools.dist:check_packages
+entry_points = setuptools.dist:check_entry_points
+zip_safe = setuptools.dist:assert_bool
+tests_require = setuptools.dist:check_requirements
+convert_2to3_doctests = setuptools.dist:assert_string_list
+test_loader = setuptools.dist:check_importable
+
+[setuptools.file_finders]
+svn_cvs = setuptools.command.sdist:_default_revctrl
+
+[egg_info.writers]
+top_level.txt = setuptools.command.egg_info:write_toplevel_names
+PKG-INFO = setuptools.command.egg_info:write_pkg_info
+eager_resources.txt = setuptools.command.egg_info:overwrite_arg
+namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
+depends.txt = setuptools.command.egg_info:warn_depends_obsolete
+dependency_links.txt = setuptools.command.egg_info:overwrite_arg
+entry_points.txt = setuptools.command.egg_info:write_entries
+requires.txt = setuptools.command.egg_info:write_requirements
+
+[distutils.commands]
+test = setuptools.command.test:test
+bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
+alias = setuptools.command.alias:alias
+sdist = setuptools.command.sdist:sdist
+develop = setuptools.command.develop:develop
+bdist_egg = setuptools.command.bdist_egg:bdist_egg
+setopt = setuptools.command.setopt:setopt
+egg_info = setuptools.command.egg_info:egg_info
+build_ext = setuptools.command.build_ext:build_ext
+upload_docs = setuptools.command.upload_docs:upload_docs
+easy_install = setuptools.command.easy_install:easy_install
+install = setuptools.command.install:install
+install_egg_info = setuptools.command.install_egg_info:install_egg_info
+bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
+install_lib = setuptools.command.install_lib:install_lib
+rotate = setuptools.command.rotate:rotate
+saveopts = setuptools.command.saveopts:saveopts
+install_scripts = setuptools.command.install_scripts:install_scripts
+build_py = setuptools.command.build_py:build_py
+register = setuptools.command.register:register
+
diff --git a/setuptools.egg-info/requires.txt b/setuptools.egg-info/requires.txt
index 91d84d9c..221040f8 100644
--- a/setuptools.egg-info/requires.txt
+++ b/setuptools.egg-info/requires.txt
@@ -1,7 +1,7 @@
-[ssl:sys_platform=='win32']
-wincertstore==0.1
+[ssl:python_version in '2.4, 2.5']
+ssl==1.16
[ssl:sys_platform=='win32' and python_version=='2.4']
ctypes==1.0.2
@@ -9,5 +9,5 @@ ctypes==1.0.2
[certs]
certifi==0.0.8
-[ssl:python_version in '2.4, 2.5']
-ssl==1.16 \ No newline at end of file
+[ssl:sys_platform=='win32']
+wincertstore==0.1 \ No newline at end of file
diff --git a/setuptools/svn_utils.py b/setuptools/svn_utils.py
index 17b211d7..22b45cd7 100644
--- a/setuptools/svn_utils.py
+++ b/setuptools/svn_utils.py
@@ -6,7 +6,9 @@ import xml.dom.pulldom
import shlex
import locale
import unicodedata
+import warnings
from setuptools.compat import unicode, bytes
+from xml.sax.saxutils import unescape
try:
import urlparse
@@ -23,6 +25,8 @@ from subprocess import Popen as _Popen, PIPE as _PIPE
# http://bugs.python.org/issue8557
# 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:
@@ -63,10 +67,10 @@ def _get_xml_data(decoded_str):
return data
-def joinpath(prefix, suffix):
+def joinpath(prefix, *suffix):
if not prefix or prefix == '.':
- return suffix
- return os.path.join(prefix, suffix)
+ return os.path.join(*suffix)
+ return os.path.join(prefix, *suffix)
def fsencode(path):
@@ -87,6 +91,7 @@ def fsencode(path):
return path
+
def fsdecode(path):
"Path must be unicode or in file system encoding already"
encoding = sys.getfilesystemencoding()
@@ -98,6 +103,7 @@ def fsdecode(path):
return unicodedata.normalize('NFC', path)
+
def consoledecode(text):
encoding = locale.getpreferredencoding()
return text.decode(encoding)
@@ -130,9 +136,7 @@ def parse_externals_xml(decoded_str, prefix=''):
if event == 'START_ELEMENT' and node.nodeName == 'target':
doc.expandNode(node)
path = os.path.normpath(node.getAttribute('path'))
- log.warn('')
- log.warn('PRE: %s' % prefix)
- log.warn('PTH: %s' % path)
+
if os.path.normcase(path).startswith(prefix):
path = path[len(prefix)+1:]
@@ -154,7 +158,7 @@ def parse_external_prop(lines):
"""
externals = []
for line in lines.splitlines():
- line = line.lstrip() #there might be a "\ "
+ line = line.lstrip() # there might be a "\ "
if not line:
continue
@@ -178,6 +182,26 @@ def parse_external_prop(lines):
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
@@ -203,14 +227,24 @@ class SvnInfo(object):
@classmethod
def load(cls, dirname=''):
- code, data = _run_command(['svn', 'info', os.path.normpath(dirname)])
+ normdir = os.path.normpath(dirname)
+ code, data = _run_command(['svn', 'info', normdir])
+ has_svn = os.path.isdir(os.path.join(normdir, '.svn'))
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')
+
+ try:
+ base_svn_version = tuple(int(x) for x in svn_version[:2])
+ except ValueError:
+ base_svn_version = tuple()
+
+ if has_svn and (code or not base_svn_version
+ or base_svn_version < (1, 3)):
+ log.warn('Fallback onto .svn parsing')
+ warnings.warn(("No SVN 1.3+ command found: falling back "
+ "on pre 1.7 .svn parsing"), DeprecationWarning)
+ return SvnFileInfo(dirname)
+ elif not has_svn:
+ log.warn('Not SVN Repository')
return SvnInfo(dirname)
elif base_svn_version < (1, 5):
return Svn13Info(dirname)
@@ -259,7 +293,7 @@ class SvnInfo(object):
Iterate over the non-deleted file entries in the repository path
'''
for item, kind in self.entries:
- if kind.lower()=='file':
+ if kind.lower() == 'file':
yield item
def iter_dirs(self, include_root=True):
@@ -269,7 +303,7 @@ class SvnInfo(object):
if include_root:
yield self.path
for item, kind in self.entries:
- if kind.lower()=='dir':
+ if kind.lower() == 'dir':
yield item
def get_entries(self):
@@ -278,6 +312,7 @@ class SvnInfo(object):
def get_externals(self):
return []
+
class Svn13Info(SvnInfo):
def get_entries(self):
code, data = _run_command(['svn', 'info', '-R', '--xml', self.path])
@@ -316,6 +351,73 @@ class Svn15Info(Svn13Info):
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 = 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):
+ dirs = list()
+ files = list()
+ rev = 0
+ for path, isfile, dir_rev in self._walk_svn(self.path):
+ if isfile:
+ files.append(path)
+ else:
+ dirs.append(path)
+ rev = max(rev, dir_rev)
+
+ self._directories = dirs
+ self._entries = files
+ 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):
+ if self._directories is None:
+ self._build_entries()
+
+ prop_files = [['.svn', 'dir-prop-base'],
+ ['.svn', 'dir-props']]
+ externals = []
+
+ for dirname in self._directories:
+ 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')
+ 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
@@ -328,6 +430,110 @@ def svn_finder(dirname=''):
for sub_path in sub_info.iter_files():
yield fsencode(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) \ No newline at end of file
+ print(name)
diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py
index 95667b69..7abafd71 100644
--- a/setuptools/tests/test_egg_info.py
+++ b/setuptools/tests/test_egg_info.py
@@ -48,6 +48,27 @@ class TestEggInfo(unittest.TestCase):
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 is None:
+ self.skipTest('Cannot figure out how to modify path')
+
+ old_path = os.environ[path_variable]
+ os.environ[path_variable] = ''
+ try:
+ self._write_entries(ENTRIES_V10)
+ rev = egg_info.egg_info.get_svn_revision()
+ finally:
+ os.environ[path_variable] = old_path
+
+ self.assertEqual(rev, '89000')
+
def test_suite():
return unittest.defaultTestLoader.loadTestsFromName(__name__)