Commit 8d389a37 authored by Philip Thiem's avatar Philip Thiem

Added SVNTextEntries for the moment as a fallback for no SVN/Rev8-10

Added Externals processing for all formats
Will use dir-prop[-base] as a fallback otherwise CMD.

--HG--
extra : rebase_source : dc27f779f22d5f9795c425b92d34db29d62b495d
parent 82a8940b
......@@ -9,6 +9,7 @@ from distutils.errors import *
from distutils import log
from setuptools.command.sdist import sdist
from setuptools.compat import basestring
from setuptools import svn_util
from distutils.util import convert_path
from distutils.filelist import FileList as _FileList
from pkg_resources import parse_requirements, safe_name, parse_version, \
......@@ -217,40 +218,21 @@ class egg_info(Command):
@staticmethod
def get_svn_revision():
revision = 0
urlre = re.compile('url="([^"]+)"')
revre = re.compile('committed-rev="(\d+)"')
urlre11 = re.compile('<url>([^<>]+)</url>')
revre11 = re.compile('<commit\s+[^>]*revision="(\d+)"')
for base,dirs,files in os.walk(os.curdir):
if '.svn' not in dirs:
dirs[:] = []
continue # no sense walking uncontrolled subdirs
dirs.remove('.svn')
f = open(os.path.join(base,'.svn','entries'))
data = f.read()
f.close()
if data.startswith('<?xml'):
dirurl = urlre.search(data).group(1) # get repository URL
localrev = max([int(m.group(1)) for m in revre.finditer(data)]+[0])
else:
try: svnver = int(data.splitlines()[0])
except: svnver=-1
if svnver<8:
log.warn("unrecognized .svn/entries format; skipping %s", base)
enteries = svn_util.SVNEntries.load(base)
if not entries.is_valid:
log.warn(" get_svn_revision: Cannot determine how to read enteries.")
dirs[:] = []
continue
elif svnver > 10:
p = _Popen(['svn', 'info', '--xml'], stdout=_PIPE, shell=(sys.platform=='win32'))
data = unicode(p.communicate()[0], encoding='utf-8')
dirurl = urlre11.search(data).group(1)
localrev = max([int(m.group(1)) for m in revre11.finditer(data)]+[0])
else:
data = list(map(str.splitlines,data.split('\n\x0c\n')))
del data[0][0] # get rid of the '8' or '9' or '10'
dirurl = data[0][3]
localrev = max([int(d[9]) for d in data if len(d)>9 and d[9]]+[0])
localrev = entries.parse_revsion()
dirurl = entries.get_url()
if base==os.curdir:
base_url = dirurl+'/' # save the root url
......
......@@ -4,6 +4,7 @@ from distutils import log
from glob import glob
import os, re, sys, pkg_resources
from glob import glob
from setuptools.svn_util import SVNEntries
READMES = ('README', 'README.rst', 'README.txt')
......@@ -61,49 +62,13 @@ def _default_revctrl(dirname=''):
def externals_finder(dirname, filename):
"""Find any 'svn:externals' directories"""
found = False
f = open(filename,'rt')
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=='svn:externals':
found = True
elif kind=='V' and found:
f.close()
break
else:
f.close()
return
for line in data.splitlines():
parts = line.split()
if parts:
yield joinpath(dirname, parts[0])
for name in SVNEntries.load(dirname).get_external_dirs(filename):
yield joinpath(dirname, name)
entries_pattern = re.compile(r'name="([^"]+)"(?![^>]+deleted="true")', re.I)
def entries_finder(dirname, filename):
f = open(filename,'rU')
data = f.read()
f.close()
if data.startswith('<?xml'):
for match in entries_pattern.finditer(data):
yield joinpath(dirname,unescape(match.group(1)))
else:
svnver=-1
try: svnver = int(data.splitlines()[0])
except: pass
if svnver<8:
log.warn("unrecognized .svn/entries format in %s", os.path.abspath(dirname))
return
for record in map(str.splitlines, data.split('\n\x0c\n')[1:]):
# subversion 1.6/1.5/1.4
if not record or len(record)>=6 and record[5]=="delete":
continue # skip deleted
yield joinpath(dirname, record[0])
for record in SVNEntries.load(dirname).get_undeleted_records():
yield joinpath(dirname, record)
finders = [
......
......@@ -19,14 +19,29 @@ def get_entries_files(base, recurse=True):
#the special casing of the entry files seem to start at 1.4.x, so if we check
#for xml in entries and then fall back to the command line, this should catch everything.
#TODO add the text entry back, and make its use dependent on the non existence of svn?
class SVNEntries(object):
svn_tool_version = ''
def __init__(self, path, data):
self.path = path
self.data = data
if not self.svn_tool_version:
self.svn_tool_version = self.get_svn_tool_version()
@staticmethod
def get_svn_tool_version():
proc = _Popen(['svn', 'propget', self.path],
stdout=_PIPE, shell=(sys.platform=='win32'))
data = unicode(proc.communicate()[0], encoding='utf-8')
if data is not not:
return data.strip()
else:
return ''
@classmethod
def load(class_, base):
def load_dir(class_, base):
filename = os.path.join(base, '.svn', 'entries')
f = open(filename)
result = SVNEntries.read(f, None)
......@@ -41,9 +56,14 @@ class SVNEntries(object):
#entries were originally xml so pre-1.4.x
return SVNEntriesXML(data, path)
else if path is None:
raise ValueError('Must have path to call svn')
result = SVNEntriesText(data, path)
else:
return SVNEntriesCMD(data, path)
class_.svn_tool_version = class_.get_svn_tool_version()
result = SVNEntriesText(data, path)
if result.is_valid():
return svnentriescmd(data, path)
else:
return result
def parse_revision(self):
all_revs = self.parse_revision_numbers() + [0]
......@@ -52,12 +72,29 @@ class SVNEntries(object):
def __get_cached_external_dirs(self):
return self.external_dirs
def get_external_dirs(self):
#regard the shell argument, see: http://bugs.python.org/issue8557
# and http://stackoverflow.com/questions/5658622/python-subprocess-popen-environment-path
proc = _Popen(['svn', 'propget', self.path],
stdout=_PIPE, shell=(sys.platform=='win32'))
data = unicode(proc.communicate()[0], encoding='utf-8').splitlines()
def __get_externals_data(self, filename):
found = False
f = open(filename,'rt')
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=='svn:externals':
found = True
elif kind=='V' and found:
f.close()
break
else:
f.close()
return ''
def get_external_dirs(self, filename):
data = self.__get_externals_data(filename)
if not data:
return
data = [line.split() for line in data]
# http://svnbook.red-bean.com/en/1.6/svn.advanced.externals.html
......@@ -65,11 +102,63 @@ class SVNEntries(object):
#but looks like we only need the local relative path names so it's just
#2 either the first column or the last (of 2 or 3)
index = -1
if all("://" in line[-1] for line in data):
if all("://" in line[-1] or not line[-1] for line in data):
index = 0
self.external_dirs = [line[index] for line in data]
return self.dir_data
self.external_dirs = [line[index] for line in data if line[index]]
self.get_external_dirs = self.__get_cached_external_dirs
return self.external_dirs
class SVNEntriesText(SVNEntries):
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' # or '\n\x0c\n'?
sections = self.data.split(SECTION_DIVIDER)
sections = list(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 SVNEntriesXML(SVNEntries):
def is_valid(self):
......@@ -85,6 +174,7 @@ class SVNEntriesXML(SVNEntries):
return [
int(m.group(1))
for m in revre.finditer(self.data)
if m.group(1)
]
def get_undeleted_records(self):
......@@ -92,6 +182,7 @@ class SVNEntriesXML(SVNEntries):
results = [
unescape(match.group(1))
for match in entries_pattern.finditer(self.data)
if m.group(1)
]
return results
......@@ -145,6 +236,7 @@ class SVNEntriesCMD(SVNEntries):
int(m.group(1))
for entry in self.get_enteries()
for m in self.revre.finditer(entry)
if m.group(1)
]
def get_undeleted_records(self):
......@@ -156,5 +248,20 @@ class SVNEntriesCMD(SVNEntries):
m.group(1))
for entry in self.get_enteries()
for m in self.namere.finditer(entry)
if m.group(1)
]
def __get_externals_data(self, filename):
#othewise will be called twice.
if filename.lower() != 'dir-props':
return ''
#regard the shell argument, see: http://bugs.python.org/issue8557
# and http://stackoverflow.com/questions/5658622/python-subprocess-popen-environment-path
proc = _Popen(['svn', 'propget', self.path],
stdout=_PIPE, shell=(sys.platform=='win32'))
try:
return unicode(proc.communicate()[0], encoding='utf-8').splitlines()
except ValueError:
return ''
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