1
# DistUpgradeEdPatcher.py
3
# Copyright (c) 2011 Canonical
5
# Author: Michael Vogt <michael.vogt@ubuntu.com>
7
# This program is free software; you can redistribute it and/or
8
# modify it under the terms of the GNU General Public License as
9
# published by the Free Software Foundation; either version 2 of the
10
# License, or (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26
class PatchError(Exception):
27
""" Error during the patch process """
30
def patch(orig, edpatch, result_md5sum=None):
31
""" python implementation of enough "ed" to apply ed-style
32
patches. Note that this patches in memory so its *not*
33
suitable for big files
36
# we only have two states, waiting for command or reading data
37
(STATE_EXPECT_COMMAND,
38
STATE_EXPECT_DATA) = range(2)
40
# this is inefficient for big files
41
orig_lines = open(orig).readlines()
44
# we start in wait-for-commend state
45
state = STATE_EXPECT_COMMAND
46
for line in open(edpatch):
47
if state == STATE_EXPECT_COMMAND:
48
# in commands get rid of whitespace,
50
# check if we have a substitute command
51
if line.startswith("s/"):
54
# chop off the flags at the end
55
subs, flags = line.rsplit("/", 1)
57
raise PatchError("flags for s// not supported yet")
58
# get the actual substitution regexp and replacement and
60
regexp, sep, repl = subs.partition("/")
61
new, count = re.subn(regexp, repl, orig_lines[start], count=1)
62
orig_lines[start] = new
64
# otherwise the last char is the command
67
(start_str, sep, end_str) = line[:-1].partition(",")
68
# ed starts with 1 while python with 0
69
start = int(start_str)
71
# if we don't have end, set it to the next line
78
del orig_lines[start:end]
79
state = STATE_EXPECT_DATA
82
# not allowed to have a range in append
83
state = STATE_EXPECT_DATA
85
del orig_lines[start:end]
87
raise PatchError("unknown command: '%s'" % line)
88
elif state == STATE_EXPECT_DATA:
89
# this is the data end marker
91
state = STATE_EXPECT_COMMAND
93
# copy line verbatim and increase position
95
orig_lines.insert(start, line)
97
# done with the patching, (optional) verify and write result
98
result = "".join(orig_lines)
102
if md5.hexdigest() != result_md5sum:
103
raise PatchError("the md5sum after patching is not correct")
104
open(orig, "w").write(result)