# HG changeset patch # User ymh # Date 1304351223 -7200 # Node ID c18c0211348b8fcb3280bc9ace886d5bc1b598ac # Parent acba3bceebf34640ed38636f287ee492f181c610 prepare new version diff -r acba3bceebf3 -r c18c0211348b sbin/create_python_env.py --- a/sbin/create_python_env.py Mon May 02 12:30:49 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,286 +0,0 @@ -""" -Call this like ``python create_python_env.py``; it will -refresh the project-boot.py script - --prerequisite: - -- virtualenv -- distribute -- psycopg2 requires the PostgreSQL libpq libraries and the pg_config utility - -- virtualenv --distribute --no-site-packages venv -- python project-boot.py --distribute --no-site-packages --index-url=http://pypi.websushi.org/ --clear bvenv - -""" - -import os -import subprocess -import re -import sys - - -here = os.path.dirname(os.path.abspath(__file__)) -base_dir = here -script_name = os.path.join(base_dir, 'project-boot.py') - -import virtualenv - -# things to install -# - psycopg2 -> pip -# - PIL -> pip -# - pyxml -> pip -# - 4Suite-xml - easy_install ftp://ftp.4suite.org/pub/4Suite/4Suite-XML-1.0.2.tar.bz2 -# - pylucene - script - -src_base = os.path.join(here,"res","src") -lib_path = os.path.abspath(os.path.join(here,"res","lib")) -patch_path = os.path.abspath(os.path.join(here,"res","patch")) - -EXTRA_TEXT = "URLS = { \n" - -EXTRA_TEXT += " 'DISTRIBUTE' : { 'setup': 'distribute', 'url': 'http://pypi.python.org/packages/source/d/distribute/distribute-0.6.13.tar.gz', 'local': '"+ os.path.abspath(os.path.join(src_base,"distribute-0.6.13.tar.gz"))+"'},\n" -EXTRA_TEXT += " 'PSYCOPG2' : { 'setup': 'psycopg2','url': 'http://initd.org/pub/software/psycopg/psycopg2-2.2.1.tar.gz', 'local': '"+ os.path.abspath(os.path.join(src_base,"psycopg2-2.2.1.tar.gz"))+"'},\n" -EXTRA_TEXT += " 'FOURSUITE_XML' : { 'setup': '4Suite-XML', 'url': 'ftp://ftp.4suite.org/pub/4Suite/4Suite-XML-1.0.2.tar.bz2', 'local': '"+ os.path.abspath(os.path.join(src_base,"4Suite-XML-1.0.2.tar.bz2"))+"'},\n" -EXTRA_TEXT += " 'PYLUCENE' : { 'setup': 'http://apache.crihan.fr/dist/lucene/pylucene/pylucene-3.0.1-1-src.tar.gz', 'url': 'http://apache.crihan.fr/dist/lucene/pylucene/pylucene-3.0.1-1-src.tar.gz', 'local': '"+ os.path.abspath(os.path.join(src_base,"pylucene-3.0.1-1-src.tar.gz"))+"'},\n" -EXTRA_TEXT += " 'PIL' : { 'setup': 'pil', 'url': 'http://effbot.org/downloads/Imaging-1.1.7.tar.gz', 'local': '"+ os.path.abspath(os.path.join(src_base,"Imaging-1.1.7.tar.gz"))+"'},\n" -EXTRA_TEXT += " 'PYXML' : { 'setup': 'http://sourceforge.net/projects/pyxml/files/pyxml/0.8.4/PyXML-0.8.4.tar.gz/download', 'url': 'http://sourceforge.net/projects/pyxml/files/pyxml/0.8.4/PyXML-0.8.4.tar.gz/download', 'local': '"+ os.path.abspath(os.path.join(src_base,"PyXML-0.8.4.tar.gz"))+"', 'patch': '"+os.path.join(patch_path,"pyxml.patch")+"'},\n" - -EXTRA_TEXT += "}\n" - -EXTRA_TEXT += "import sys\n" -EXTRA_TEXT += "sys.path.append('"+lib_path+"')\n" - -EXTRA_TEXT += """ - -import shutil -import tarfile -import urllib -import platform -import patch -import zipfile -from distutils.sysconfig import get_python_lib - - -INDEX_URL = 'http://pypi.python.org/simple/' - - -def extend_parser(parser): - parser.add_option( - '--index-url', - metavar='INDEX_URL', - dest='index_url', - default='', - help='base URL of Python Package Index') - parser.add_option( - '--type-install', - metavar='type_install', - dest='type_install', - default='local', - help='type install : local, url, setup') - - -def adjust_options(options, args): - pass - - -def after_install(options, home_dir): - home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) - base_dir = os.path.dirname(home_dir) - src_dir = join(home_dir, 'src') - tmp_dir = join(home_dir, 'tmp') - ensure_dir(src_dir) - ensure_dir(tmp_dir) - system_str = platform.system() - python_lib_dir = get_python_lib() - - res_source_key = options.type_install - - logger.indent += 2 - try: - - #get pylucene - logger.notify("Get Pylucene from %s " % URLS['PYLUCENE'][res_source_key]) - pylucene_src = os.path.join(src_dir,"pylucene.tar.gz") - urllib.urlretrieve(URLS['PYLUCENE'][res_source_key], pylucene_src) - tf = tarfile.open(pylucene_src,'r:gz') - pylucene_base_path = os.path.join(src_dir,"pylucene") - logger.notify("Extract Pylucene to %s " % pylucene_base_path) - tf.extractall(pylucene_base_path) - tf.close() - - pylucene_src_path = os.path.join(pylucene_base_path, os.listdir(pylucene_base_path)[0]) - jcc_src_path = os.path.abspath(os.path.join(pylucene_src_path,"jcc")) - - #install jcc - - #patch for linux - if system_str == 'Linux' : - olddir = os.getcwd() - patch_dest_path = os.path.join(lib_dir, 'site-packages','setuptools-0.6c11-py'+'%s.%s' % (sys.version_info[0], sys.version_info[1])+'.egg') - - if os.path.isfile(patch_dest_path): - # must unzip egg - # rename file and etract all - shutil.move(patch_dest_path, patch_dest_path + ".zip") - zf = zipfile.ZipFile(patch_dest_path + ".zip",'r') - zf.extractall(patch_dest_path) - os.remove(patch_dest_path + ".zip") - logger.notify("Patch jcc : %s " % (patch_dest_path)) - os.chdir(patch_dest_path) - p = patch.fromfile(os.path.join(jcc_src_path,"jcc","patches","patch.43.0.6c11")) - p.apply() - os.chdir(olddir) - - logger.notify("Install jcc") - call_subprocess([os.path.abspath(os.path.join(home_dir, 'bin', 'python')), 'setup.py', 'install'], - cwd=jcc_src_path, - filter_stdout=filter_python_develop, - show_stdout=True) - #install pylucene - - logger.notify("Install pylucene") - #modify makefile - makefile_path = os.path.join(pylucene_src_path,"Makefile") - logger.notify("Modify makefile %s " % makefile_path) - shutil.move( makefile_path, makefile_path+"~" ) - - destination= open( makefile_path, "w" ) - source= open( makefile_path+"~", "r" ) - destination.write("PREFIX_PYTHON="+os.path.abspath(home_dir)+"\\n") - destination.write("ANT=ant\\n") - destination.write("PYTHON=$(PREFIX_PYTHON)/bin/python\\n") - - if system_str == "Darwin": - if sys.version_info >= (2,6): - destination.write("JCC=$(PYTHON) -m jcc.__main__ --shared --arch x86_64 --arch i386\\n") - else: - destination.write("JCC=$(PYTHON) -m jcc --shared\\n") - destination.write("NUM_FILES=2\\n") - elif system_str == "Windows": - destination.write("JCC=$(PYTHON) -m jcc.__main__ --shared --arch x86_64 --arch i386\\n") - destination.write("NUM_FILES=2\\n") - else: - if sys.version_info >= (2,6) and sys.version_info < (2,7): - destination.write("JCC=$(PYTHON) -m jcc.__main__ --shared\\n") - else: - destination.write("JCC=$(PYTHON) -m jcc --shared\\n") - destination.write("NUM_FILES=2\\n") - for line in source: - destination.write( line ) - source.close() - destination.close() - os.remove(makefile_path+"~" ) - - logger.notify("pylucene make") - call_subprocess(['make'], - cwd=os.path.abspath(pylucene_src_path), - filter_stdout=filter_python_develop, - show_stdout=True) - - logger.notify("pylucene make install") - call_subprocess(['make', 'install'], - cwd=os.path.abspath(pylucene_src_path), - filter_stdout=filter_python_develop, - show_stdout=True) - - logger.notify("PyXML install : %s " % URLS['PYXML'][res_source_key]) - if sys.version_info >= (2,6): - logger.notify("PyXML -> python version >= 2.6 : patching") - pyxml_src = os.path.join(src_dir,"pyxml.tar.gz") - urllib.urlretrieve(URLS['PYXML'][res_source_key], pyxml_src) - logger.notify("PyXML -> python version >= 2.6 : extract archive") - tf = tarfile.open(pyxml_src,'r:gz') - pyxml_base_path = os.path.join(src_dir,"pyxml") - tf.extractall(pyxml_base_path) - tf.close() - - #patch - pyxml_version = os.listdir(pyxml_base_path)[0] - pyxml_path = os.path.join(pyxml_base_path, pyxml_version) - olddir = os.getcwd() - os.chdir(pyxml_path) - logger.notify("PyXML -> python version >= 2.6 : do patch %s : %s " % (pyxml_path, URLS['PYXML']['patch'])) - p = patch.fromfile(URLS['PYXML']['patch']) - p.apply() - os.chdir(olddir) - logger.notify("PyXML -> python version >= 2.6 : install") - call_subprocess([os.path.abspath(os.path.join(home_dir, 'bin', 'pip')), 'install', '-E', os.path.abspath(home_dir), '--build='+os.path.abspath(pyxml_base_path), '--no-download', pyxml_version], - cwd=os.path.abspath(tmp_dir), - filter_stdout=filter_python_develop, - show_stdout=True) - else: - call_subprocess([os.path.abspath(os.path.join(home_dir, 'bin', 'pip')), 'install', '-E', os.path.abspath(home_dir), URLS['PYXML'][res_source_key]], - cwd=os.path.abspath(tmp_dir), - filter_stdout=filter_python_develop, - show_stdout=True) - - logger.notify("Install Distribute from %s" % URLS['DISTRIBUTE'][res_source_key]) - call_subprocess([os.path.abspath(os.path.join(home_dir, 'bin', 'pip')), 'install', '-E', os.path.abspath(home_dir), URLS['DISTRIBUTE'][res_source_key]], - cwd=os.path.abspath(tmp_dir), - filter_stdout=filter_python_develop, - show_stdout=True) - - logger.notify("Install Psycopg2 from %s" % URLS['PSYCOPG2'][res_source_key]) - call_subprocess([os.path.abspath(os.path.join(home_dir, 'bin', 'pip')), 'install', '-E', os.path.abspath(home_dir), URLS['PSYCOPG2'][res_source_key]], - cwd=os.path.abspath(tmp_dir), - filter_stdout=filter_python_develop, - show_stdout=True) - - logger.notify("Install PIL from %s" % URLS['PIL'][res_source_key]) - call_subprocess([os.path.abspath(os.path.join(home_dir, 'bin', 'pip')), 'install', '-E', os.path.abspath(home_dir), URLS['PIL'][res_source_key]], - cwd=os.path.abspath(tmp_dir), - filter_stdout=filter_python_develop, - show_stdout=True) - - logger.notify("Install 4Suite-XML from %s" % URLS['FOURSUITE_XML'][res_source_key]) - call_subprocess([os.path.abspath(os.path.join(home_dir, 'bin', 'easy_install')), URLS['FOURSUITE_XML'][res_source_key]], - cwd=os.path.abspath(tmp_dir), - filter_stdout=filter_python_develop, - show_stdout=True) - - logger.notify("Clear source dir") - shutil.rmtree(src_dir) - - finally: - logger.indent -= 2 - script_dir = join(base_dir, 'bin') - logger.notify('Run "%s Package" to install new packages that provide builds' - % join(script_dir, 'easy_install')) - -def ensure_dir(dir): - if not os.path.exists(dir): - logger.notify('Creating directory %s' % dir) - os.makedirs(dir) - -def filter_python_develop(line): - if not line.strip(): - return Logger.DEBUG - for prefix in ['Searching for', 'Reading ', 'Best match: ', 'Processing ', - 'Moving ', 'Adding ', 'running ', 'writing ', 'Creating ', - 'creating ', 'Copying ']: - if line.startswith(prefix): - return Logger.DEBUG - return Logger.NOTIFY -""" - -def main(): - python_version = ".".join(map(str,sys.version_info[0:2])) - text = virtualenv.create_bootstrap_script(EXTRA_TEXT, python_version=python_version) - if os.path.exists(script_name): - f = open(script_name) - cur_text = f.read() - f.close() - else: - cur_text = '' - print 'Updating %s' % script_name - if cur_text == 'text': - print 'No update' - else: - print 'Script changed; updating...' - f = open(script_name, 'w') - f.write(text) - f.close() - -if __name__ == '__main__': - main() - diff -r acba3bceebf3 -r c18c0211348b sbin/res/lib/patch.py --- a/sbin/res/lib/patch.py Mon May 02 12:30:49 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,589 +0,0 @@ -""" Patch utility to apply unified diffs - - Brute-force line-by-line non-recursive parsing - - Copyright (c) 2008-2010 anatoly techtonik - Available under the terms of MIT license - - Project home: http://code.google.com/p/python-patch/ - - - $Id: patch.py 76 2010-04-08 19:10:21Z techtonik $ - $HeadURL: https://python-patch.googlecode.com/svn/trunk/patch.py $ -""" - -__author__ = "techtonik.rainforce.org" -__version__ = "10.04" - -import copy -import logging -import re -# cStringIO doesn't support unicode in 2.5 -from StringIO import StringIO -from logging import debug, info, warning - -from os.path import exists, isfile, abspath -from os import unlink - - -#------------------------------------------------ -# Logging is controlled by "python_patch" logger - -debugmode = False - -logger = logging.getLogger("python_patch") -loghandler = logging.StreamHandler() -logger.addHandler(loghandler) - -debug = logger.debug -info = logger.info -warning = logger.warning - -#: disable library logging by default -logger.setLevel(logging.CRITICAL) - -#------------------------------------------------ - - -def fromfile(filename): - """ Parse patch file and return Patch() object - """ - - info("reading patch from file %s" % filename) - fp = open(filename, "rb") - patch = Patch(fp) - fp.close() - return patch - - -def fromstring(s): - """ Parse text string and return Patch() object - """ - - return Patch( - StringIO.StringIO(s) - ) - - - -class HunkInfo(object): - """ Parsed hunk data container (hunk starts with @@ -R +R @@) """ - - def __init__(self): - self.startsrc=None #: line count starts with 1 - self.linessrc=None - self.starttgt=None - self.linestgt=None - self.invalid=False - self.text=[] - - def copy(self): - return copy.copy(self) - -# def apply(self, estream): -# """ write hunk data into enumerable stream -# return strings one by one until hunk is -# over -# -# enumerable stream are tuples (lineno, line) -# where lineno starts with 0 -# """ -# pass - - - -class Patch(object): - - def __init__(self, stream=None): - - # define Patch data members - # table with a row for every source file - - #: list of source filenames - self.source=None - self.target=None - #: list of lists of hunks - self.hunks=None - #: file endings statistics for every hunk - self.hunkends=None - - if stream: - self.parse(stream) - - def copy(self): - return copy.copy(self) - - def parse(self, stream): - """ parse unified diff """ - self.source = [] - self.target = [] - self.hunks = [] - self.hunkends = [] - - # define possible file regions that will direct the parser flow - header = False # comments before the patch body - filenames = False # lines starting with --- and +++ - - hunkhead = False # @@ -R +R @@ sequence - hunkbody = False # - hunkskip = False # skipping invalid hunk mode - - header = True - lineends = dict(lf=0, crlf=0, cr=0) - nextfileno = 0 - nexthunkno = 0 #: even if index starts with 0 user messages number hunks from 1 - - # hunkinfo holds parsed values, hunkactual - calculated - hunkinfo = HunkInfo() - hunkactual = dict(linessrc=None, linestgt=None) - - fe = enumerate(stream) - for lineno, line in fe: - - # analyze state - if header and line.startswith("--- "): - header = False - # switch to filenames state - filenames = True - #: skip hunkskip and hunkbody code until you read definition of hunkhead - if hunkbody: - # process line first - if re.match(r"^[- \+\\]", line): - # gather stats about line endings - if line.endswith("\r\n"): - self.hunkends[nextfileno-1]["crlf"] += 1 - elif line.endswith("\n"): - self.hunkends[nextfileno-1]["lf"] += 1 - elif line.endswith("\r"): - self.hunkends[nextfileno-1]["cr"] += 1 - - if line.startswith("-"): - hunkactual["linessrc"] += 1 - elif line.startswith("+"): - hunkactual["linestgt"] += 1 - elif not line.startswith("\\"): - hunkactual["linessrc"] += 1 - hunkactual["linestgt"] += 1 - hunkinfo.text.append(line) - # todo: handle \ No newline cases - else: - warning("invalid hunk no.%d at %d for target file %s" % (nexthunkno, lineno+1, self.target[nextfileno-1])) - # add hunk status node - self.hunks[nextfileno-1].append(hunkinfo.copy()) - self.hunks[nextfileno-1][nexthunkno-1]["invalid"] = True - # switch to hunkskip state - hunkbody = False - hunkskip = True - - # check exit conditions - if hunkactual["linessrc"] > hunkinfo.linessrc or hunkactual["linestgt"] > hunkinfo.linestgt: - warning("extra hunk no.%d lines at %d for target %s" % (nexthunkno, lineno+1, self.target[nextfileno-1])) - # add hunk status node - self.hunks[nextfileno-1].append(hunkinfo.copy()) - self.hunks[nextfileno-1][nexthunkno-1]["invalid"] = True - # switch to hunkskip state - hunkbody = False - hunkskip = True - elif hunkinfo.linessrc == hunkactual["linessrc"] and hunkinfo.linestgt == hunkactual["linestgt"]: - self.hunks[nextfileno-1].append(hunkinfo.copy()) - # switch to hunkskip state - hunkbody = False - hunkskip = True - - # detect mixed window/unix line ends - ends = self.hunkends[nextfileno-1] - if ((ends["cr"]!=0) + (ends["crlf"]!=0) + (ends["lf"]!=0)) > 1: - warning("inconsistent line ends in patch hunks for %s" % self.source[nextfileno-1]) - if debugmode: - debuglines = dict(ends) - debuglines.update(file=self.target[nextfileno-1], hunk=nexthunkno) - debug("crlf: %(crlf)d lf: %(lf)d cr: %(cr)d\t - file: %(file)s hunk: %(hunk)d" % debuglines) - - if hunkskip: - match = re.match("^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))?", line) - if match: - # switch to hunkhead state - hunkskip = False - hunkhead = True - elif line.startswith("--- "): - # switch to filenames state - hunkskip = False - filenames = True - if debugmode and len(self.source) > 0: - debug("- %2d hunks for %s" % (len(self.hunks[nextfileno-1]), self.source[nextfileno-1])) - - if filenames: - if line.startswith("--- "): - if nextfileno in self.source: - warning("skipping invalid patch for %s" % self.source[nextfileno]) - del self.source[nextfileno] - # double source filename line is encountered - # attempt to restart from this second line - re_filename = "^--- ([^\t]+)" - match = re.match(re_filename, line) - # todo: support spaces in filenames - if match: - self.source.append(match.group(1).strip()) - else: - warning("skipping invalid filename at line %d" % lineno) - # switch back to header state - filenames = False - header = True - elif not line.startswith("+++ "): - if nextfileno in self.source: - warning("skipping invalid patch with no target for %s" % self.source[nextfileno]) - del self.source[nextfileno] - else: - # this should be unreachable - warning("skipping invalid target patch") - filenames = False - header = True - else: - if nextfileno in self.target: - warning("skipping invalid patch - double target at line %d" % lineno) - del self.source[nextfileno] - del self.target[nextfileno] - nextfileno -= 1 - # double target filename line is encountered - # switch back to header state - filenames = False - header = True - else: - re_filename = "^\+\+\+ ([^\t]+)" - match = re.match(re_filename, line) - if not match: - warning("skipping invalid patch - no target filename at line %d" % lineno) - # switch back to header state - filenames = False - header = True - else: - self.target.append(match.group(1).strip()) - nextfileno += 1 - # switch to hunkhead state - filenames = False - hunkhead = True - nexthunkno = 0 - self.hunks.append([]) - self.hunkends.append(lineends.copy()) - continue - - if hunkhead: - match = re.match("^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))?", line) - if not match: - if nextfileno-1 not in self.hunks: - warning("skipping invalid patch with no hunks for file %s" % self.target[nextfileno-1]) - # switch to header state - hunkhead = False - header = True - continue - else: - # switch to header state - hunkhead = False - header = True - else: - hunkinfo.startsrc = int(match.group(1)) - hunkinfo.linessrc = 1 - if match.group(3): hunkinfo.linessrc = int(match.group(3)) - hunkinfo.starttgt = int(match.group(4)) - hunkinfo.linestgt = 1 - if match.group(6): hunkinfo.linestgt = int(match.group(6)) - hunkinfo.invalid = False - hunkinfo.text = [] - - hunkactual["linessrc"] = hunkactual["linestgt"] = 0 - - # switch to hunkbody state - hunkhead = False - hunkbody = True - nexthunkno += 1 - continue - else: - if not hunkskip: - warning("patch file incomplete - %s" % filename) - # sys.exit(?) - else: - # duplicated message when an eof is reached - if debugmode and len(self.source) > 0: - debug("- %2d hunks for %s" % (len(self.hunks[nextfileno-1]), self.source[nextfileno-1])) - - info("total files: %d total hunks: %d" % (len(self.source), sum(len(hset) for hset in self.hunks))) - - - def apply(self): - """ apply parsed patch """ - - total = len(self.source) - for fileno, filename in enumerate(self.source): - - f2patch = filename - if not exists(f2patch): - f2patch = self.target[fileno] - if not exists(f2patch): - warning("source/target file does not exist\n--- %s\n+++ %s" % (filename, f2patch)) - continue - if not isfile(f2patch): - warning("not a file - %s" % f2patch) - continue - filename = f2patch - - info("processing %d/%d:\t %s" % (fileno+1, total, filename)) - - # validate before patching - f2fp = open(filename) - hunkno = 0 - hunk = self.hunks[fileno][hunkno] - hunkfind = [] - hunkreplace = [] - validhunks = 0 - canpatch = False - for lineno, line in enumerate(f2fp): - if lineno+1 < hunk.startsrc: - continue - elif lineno+1 == hunk.startsrc: - hunkfind = [x[1:].rstrip("\r\n") for x in hunk.text if x[0] in " -"] - hunkreplace = [x[1:].rstrip("\r\n") for x in hunk.text if x[0] in " +"] - #pprint(hunkreplace) - hunklineno = 0 - - # todo \ No newline at end of file - - # check hunks in source file - if lineno+1 < hunk.startsrc+len(hunkfind)-1: - if line.rstrip("\r\n") == hunkfind[hunklineno]: - hunklineno+=1 - else: - debug("hunk no.%d doesn't match source file %s" % (hunkno+1, filename)) - # file may be already patched, but we will check other hunks anyway - hunkno += 1 - if hunkno < len(self.hunks[fileno]): - hunk = self.hunks[fileno][hunkno] - continue - else: - break - - # check if processed line is the last line - if lineno+1 == hunk.startsrc+len(hunkfind)-1: - debug("file %s hunk no.%d -- is ready to be patched" % (filename, hunkno+1)) - hunkno+=1 - validhunks+=1 - if hunkno < len(self.hunks[fileno]): - hunk = self.hunks[fileno][hunkno] - else: - if validhunks == len(self.hunks[fileno]): - # patch file - canpatch = True - break - else: - if hunkno < len(self.hunks[fileno]): - warning("premature end of source file %s at hunk %d" % (filename, hunkno+1)) - - f2fp.close() - - if validhunks < len(self.hunks[fileno]): - if self._match_file_hunks(filename, self.hunks[fileno]): - warning("already patched %s" % filename) - else: - warning("source file is different - %s" % filename) - if canpatch: - backupname = filename+".orig" - if exists(backupname): - warning("can't backup original file to %s - aborting" % backupname) - else: - import shutil - shutil.move(filename, backupname) - if self.write_hunks(backupname, filename, self.hunks[fileno]): - warning("successfully patched %s" % filename) - unlink(backupname) - else: - warning("error patching file %s" % filename) - shutil.copy(filename, filename+".invalid") - warning("invalid version is saved to %s" % filename+".invalid") - # todo: proper rejects - shutil.move(backupname, filename) - - # todo: check for premature eof - - - def can_patch(self, filename): - """ Check if specified filename can be patched. Returns None if file can - not be found among source filenames. False if patch can not be applied - clearly. True otherwise. - - :returns: True, False or None - """ - idx = self._get_file_idx(filename, source=True) - if idx == None: - return None - return self._match_file_hunks(filename, self.hunks[idx]) - - - def _match_file_hunks(self, filepath, hunks): - matched = True - fp = open(abspath(filepath)) - - class NoMatch(Exception): - pass - - lineno = 1 - line = fp.readline() - hno = None - try: - for hno, h in enumerate(hunks): - # skip to first line of the hunk - while lineno < h.starttgt: - if not len(line): # eof - debug("check failed - premature eof before hunk: %d" % (hno+1)) - raise NoMatch - line = fp.readline() - lineno += 1 - for hline in h.text: - if hline.startswith("-"): - continue - if not len(line): - debug("check failed - premature eof on hunk: %d" % (hno+1)) - # todo: \ No newline at the end of file - raise NoMatch - if line.rstrip("\r\n") != hline[1:].rstrip("\r\n"): - debug("file is not patched - failed hunk: %d" % (hno+1)) - raise NoMatch - line = fp.readline() - lineno += 1 - - except NoMatch: - matched = False - # todo: display failed hunk, i.e. expected/found - - fp.close() - return matched - - - def patch_stream(self, instream, hunks): - """ Generator that yields stream patched with hunks iterable - - Converts lineends in hunk lines to the best suitable format - autodetected from input - """ - - # todo: At the moment substituted lineends may not be the same - # at the start and at the end of patching. Also issue a - # warning/throw about mixed lineends (is it really needed?) - - hunks = iter(hunks) - - srclineno = 1 - - lineends = {'\n':0, '\r\n':0, '\r':0} - def get_line(): - """ - local utility function - return line from source stream - collecting line end statistics on the way - """ - line = instream.readline() - # 'U' mode works only with text files - if line.endswith("\r\n"): - lineends["\r\n"] += 1 - elif line.endswith("\n"): - lineends["\n"] += 1 - elif line.endswith("\r"): - lineends["\r"] += 1 - return line - - for hno, h in enumerate(hunks): - debug("hunk %d" % (hno+1)) - # skip to line just before hunk starts - while srclineno < h.startsrc: - yield get_line() - srclineno += 1 - - for hline in h.text: - # todo: check \ No newline at the end of file - if hline.startswith("-") or hline.startswith("\\"): - get_line() - srclineno += 1 - continue - else: - if not hline.startswith("+"): - get_line() - srclineno += 1 - line2write = hline[1:] - # detect if line ends are consistent in source file - if sum([bool(lineends[x]) for x in lineends]) == 1: - newline = [x for x in lineends if lineends[x] != 0][0] - yield line2write.rstrip("\r\n")+newline - else: # newlines are mixed - yield line2write - - for line in instream: - yield line - - - def write_hunks(self, srcname, tgtname, hunks): - src = open(srcname, "rb") - tgt = open(tgtname, "wb") - - debug("processing target file %s" % tgtname) - - tgt.writelines(self.patch_stream(src, hunks)) - - tgt.close() - src.close() - return True - - - def _get_file_idx(self, filename, source=None): - """ Detect index of given filename within patch. - - :param filename: - :param source: search filename among sources (True), - targets (False), or both (None) - :returns: int or None - """ - filename = abspath(filename) - if source == True or source == None: - for i,fnm in enumerate(self.source): - if filename == abspath(fnm): - return i - if source == False or source == None: - for i,fnm in enumerate(self.target): - if filename == abspath(fnm): - return i - - - - -from optparse import OptionParser -from os.path import exists -import sys - -if __name__ == "__main__": - opt = OptionParser(usage="%prog [options] unipatch-file", version="python-patch %s" % __version__) - opt.add_option("--debug", action="store_true", dest="debugmode", help="debug mode") - (options, args) = opt.parse_args() - - if not args: - opt.print_version() - opt.print_help() - sys.exit() - debugmode = options.debugmode - patchfile = args[0] - if not exists(patchfile) or not isfile(patchfile): - sys.exit("patch file does not exist - %s" % patchfile) - - - if debugmode: - loglevel = logging.DEBUG - logformat = "%(levelname)8s %(message)s" - else: - loglevel = logging.INFO - logformat = "%(message)s" - logger.setLevel(loglevel) - loghandler.setFormatter(logging.Formatter(logformat)) - - - - patch = fromfile(patchfile) - #pprint(patch) - patch.apply() - - # todo: document and test line ends handling logic - patch.py detects proper line-endings - # for inserted hunks and issues a warning if patched file has incosistent line ends diff -r acba3bceebf3 -r c18c0211348b sbin/res/patch/pyxml.patch --- a/sbin/res/patch/pyxml.patch Mon May 02 12:30:49 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -diff -ur xml/xpath/ParsedAbbreviatedAbsoluteLocationPath.py b/xml/xpath/ParsedAbbreviatedAbsoluteLocationPath.py ---- xml/xpath/ParsedAbbreviatedAbsoluteLocationPath.py 2003-03-11 15:01:34.000000000 +0100 -+++ xml/xpath/ParsedAbbreviatedAbsoluteLocationPath.py 2009-05-25 16:32:26.000000000 +0200 -@@ -24,8 +24,8 @@ - self._rel = rel - nt = ParsedNodeTest.ParsedNodeTest('node', '') - ppl = ParsedPredicateList.ParsedPredicateList([]) -- as = ParsedAxisSpecifier.ParsedAxisSpecifier('descendant-or-self') -- self._step = ParsedStep.ParsedStep(as, nt, ppl) -+ asp = ParsedAxisSpecifier.ParsedAxisSpecifier('descendant-or-self') -+ self._step = ParsedStep.ParsedStep(asp, nt, ppl) - return - - def evaluate(self, context): -diff -ur a/xml/xpath/ParsedAbbreviatedRelativeLocationPath.py b/xml/xpath/ParsedAbbreviatedRelativeLocationPath.py ---- xml/xpath/ParsedAbbreviatedRelativeLocationPath.py 2003-03-11 15:01:34.000000000 +0100 -+++ xml/xpath/ParsedAbbreviatedRelativeLocationPath.py 2009-05-25 16:27:55.000000000 +0200 -@@ -28,8 +28,8 @@ - self._right = right - nt = ParsedNodeTest.ParsedNodeTest('node','') - ppl = ParsedPredicateList.ParsedPredicateList([]) -- as = ParsedAxisSpecifier.ParsedAxisSpecifier('descendant-or-self') -- self._middle = ParsedStep.ParsedStep(as, nt, ppl) -+ asp = ParsedAxisSpecifier.ParsedAxisSpecifier('descendant-or-self') -+ self._middle = ParsedStep.ParsedStep(asp, nt, ppl) - - def evaluate(self, context): - res = [] diff -r acba3bceebf3 -r c18c0211348b sbin/res/src/4Suite-XML-1.0.2.tar.bz2 Binary file sbin/res/src/4Suite-XML-1.0.2.tar.bz2 has changed diff -r acba3bceebf3 -r c18c0211348b sbin/res/src/Imaging-1.1.7.tar.gz Binary file sbin/res/src/Imaging-1.1.7.tar.gz has changed diff -r acba3bceebf3 -r c18c0211348b sbin/res/src/PyXML-0.8.4.tar.gz Binary file sbin/res/src/PyXML-0.8.4.tar.gz has changed diff -r acba3bceebf3 -r c18c0211348b sbin/res/src/distribute-0.6.13.tar.gz Binary file sbin/res/src/distribute-0.6.13.tar.gz has changed diff -r acba3bceebf3 -r c18c0211348b sbin/res/src/psycopg2-2.2.1.tar.gz Binary file sbin/res/src/psycopg2-2.2.1.tar.gz has changed diff -r acba3bceebf3 -r c18c0211348b sbin/res/src/pylucene-3.0.1-1-src.tar.gz Binary file sbin/res/src/pylucene-3.0.1-1-src.tar.gz has changed diff -r acba3bceebf3 -r c18c0211348b sbin/sync_blinkster_venv --- a/sbin/sync_blinkster_venv Mon May 02 12:30:49 2011 +0200 +++ b/sbin/sync_blinkster_venv Mon May 02 17:47:03 2011 +0200 @@ -9,7 +9,7 @@ #text2unix ~/tmp/blinkster_V$1 if [ -d ~/tmp/blinkster_V$1 ]; then - cat <