From 8d389a37b8237d9dfb3f2b92baf79acda9c5b3f1 Mon Sep 17 00:00:00 2001 From: Philip Thiem Date: Sun, 30 Jun 2013 13:13:33 -0500 Subject: 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 --- setuptools/svn_utils.py | 135 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 121 insertions(+), 14 deletions(-) (limited to 'setuptools/svn_utils.py') diff --git a/setuptools/svn_utils.py b/setuptools/svn_utils.py index d36f64ea..dff1c4b0 100644 --- a/setuptools/svn_utils.py +++ b/setuptools/svn_utils.py @@ -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): @@ -155,6 +247,21 @@ class SVNEntriesCMD(SVNEntries): return [ m.group(1)) for entry in self.get_enteries() - for m in self.namere.finditer(entry) + 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 '' -- cgit v1.2.1