~ubuntu-core-dev/update-manager/main

« back to all changes in this revision

Viewing changes to DistUpgrade/DistUpgradePatcher.py

  • Committer: Michael Terry
  • Date: 2012-05-15 19:43:43 UTC
  • mto: This revision was merged to the branch mainline in revision 2428.
  • Revision ID: michael.terry@canonical.com-20120515194343-tocvo0awttmggie1
update several strings to match the software updater spec; most notably, rename from Update Manager to Software Updater

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# DistUpgradeEdPatcher.py 
 
2
#  
 
3
#  Copyright (c) 2011 Canonical
 
4
#  
 
5
#  Author: Michael Vogt <michael.vogt@ubuntu.com>
 
6
 
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.
 
11
 
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.
 
16
 
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
 
20
#  USA
 
21
 
 
22
import hashlib
 
23
import re
 
24
 
 
25
 
 
26
class PatchError(Exception):
 
27
    """ Error during the patch process """
 
28
    pass
 
29
 
 
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
 
34
    """
 
35
 
 
36
    # we only have two states, waiting for command or reading data
 
37
    (STATE_EXPECT_COMMAND,
 
38
     STATE_EXPECT_DATA) = range(2)
 
39
 
 
40
    # this is inefficient for big files
 
41
    orig_lines = open(orig).readlines()
 
42
    start = end = 0
 
43
 
 
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, 
 
49
            line = line.strip()
 
50
            # check if we have a substitute command
 
51
            if line.startswith("s/"):
 
52
                # strip away the "s/"
 
53
                line = line[2:]
 
54
                # chop off the flags at the end 
 
55
                subs, flags = line.rsplit("/", 1)
 
56
                if flags:
 
57
                    raise PatchError("flags for s// not supported yet")
 
58
                # get the actual substitution regexp and replacement and 
 
59
                # execute it
 
60
                regexp, sep, repl = subs.partition("/")
 
61
                new, count = re.subn(regexp, repl, orig_lines[start], count=1)
 
62
                orig_lines[start] = new
 
63
                continue
 
64
            # otherwise the last char is the command
 
65
            command = line[-1]
 
66
            # read address
 
67
            (start_str, sep, end_str) = line[:-1].partition(",")
 
68
            # ed starts with 1 while python with 0
 
69
            start = int(start_str)
 
70
            start -= 1
 
71
            # if we don't have end, set it to the next line
 
72
            if end_str is "":
 
73
                end = start+1
 
74
            else:
 
75
                end = int(end_str)
 
76
            # interpret command
 
77
            if command == "c":
 
78
                del orig_lines[start:end]
 
79
                state = STATE_EXPECT_DATA
 
80
                start -= 1
 
81
            elif command == "a":
 
82
                # not allowed to have a range in append
 
83
                state = STATE_EXPECT_DATA
 
84
            elif command == "d":
 
85
                del orig_lines[start:end]
 
86
            else:
 
87
                raise PatchError("unknown command: '%s'" % line)
 
88
        elif state == STATE_EXPECT_DATA:
 
89
            # this is the data end marker
 
90
            if line == ".\n":
 
91
                state = STATE_EXPECT_COMMAND
 
92
            else:
 
93
                # copy line verbatim and increase position
 
94
                start += 1
 
95
                orig_lines.insert(start, line)
 
96
 
 
97
    # done with the patching, (optional) verify and write result
 
98
    result = "".join(orig_lines)
 
99
    if result_md5sum:
 
100
        md5 = hashlib.md5()
 
101
        md5.update(result)
 
102
        if md5.hexdigest() != result_md5sum:
 
103
            raise PatchError("the md5sum after patching is not correct")
 
104
    open(orig, "w").write(result)
 
105
    return True