~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to patch.py

  • Committer: Aaron Bentley
  • Date: 2007-06-12 22:09:44 UTC
  • mfrom: (540.1.2 bzrtools-0.17)
  • Revision ID: aaron.bentley@utoronto.ca-20070612220944-5zw4hlzp1ctq6mkl
Merge fixes from 0.17

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
#    You should have received a copy of the GNU General Public License
15
15
#    along with this program; if not, write to the Free Software
16
16
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 
import sys, os
 
17
import sys
18
18
from subprocess import Popen, PIPE
 
19
 
 
20
from bzrlib import urlutils
19
21
from bzrlib.transport import get_transport
20
 
from urlparse import urlsplit, urlunsplit
21
22
from bzrlib.workingtree import WorkingTree
22
23
import bzrlib.add
23
 
import bzrlib.transform
24
 
import bzrlib.branch
25
 
import bzrlib.bzrdir
26
 
 
27
 
class BzrPatchProc:
28
 
    """This class process the bzr patch
29
 
 
30
 
        TODO:
31
 
          error handling
32
 
          execute attribute support
33
 
    """
34
 
    def __init__(self, tt, tree, bzrdir):
35
 
        self.link = None
36
 
        self.changes = []
37
 
        self.mode = None
38
 
        self.command = None
39
 
        self.target_id = None
40
 
        self.tt = tt
41
 
        self.tree = tree
42
 
        self.skipchange = True
43
 
 
44
 
        self.bzrdir = bzrdir
45
 
        self.branch =  self.bzrdir.open_branch( )
46
 
        self.repo = self.bzrdir.find_repository( )
47
 
        h = self.branch.revision_history( )
48
 
        self.inv = self.repo.get_inventory(h[-1])
49
 
 
50
 
 
51
 
    def get_transid(self, path):
52
 
        return self.tt.trans_id_tree_path(path)
53
 
 
54
 
 
55
 
    def _extractname(self, s):
56
 
        x = s[0]
57
 
        i = 1
58
 
        ls = len(s)
59
 
 
60
 
        while i < ls:
61
 
            if s[i] == '\\':
62
 
                assert(i+1 < ls )
63
 
                i += 2
64
 
                continue
65
 
 
66
 
            if s[i] == x:
67
 
                return s[1:i],i+1
68
 
 
69
 
            i += 1
70
 
 
71
 
        assert(False)
72
 
 
73
 
 
74
 
    def extractname(self, s):
75
 
        space=-1
76
 
        for i in range(0,3):
77
 
            space = s.find(" ",space+1)    # find the 2nd space
78
 
        assert(space>=0)
79
 
        return self._extractname(s[space+1:])[0]
80
 
 
81
 
 
82
 
    def extractnames(self, s):
83
 
        space=-1
84
 
        for i in range(0,3):
85
 
            space = s.find(" ",space+1)    # find the 2nd space
86
 
        assert(space>=0)
87
 
        s=s[space+1:]
88
 
        source, pos = self._extractname(s)
89
 
        assert( pos +4 < len(s) )
90
 
        dest,  dummy = self._extractname(s[pos+4:])
91
 
 
92
 
        return source,dest
93
 
 
94
 
 
95
 
    def flush(self):
96
 
        self.process( )
97
 
 
98
 
 
99
 
    def do_patch(self, changes, targetid):
100
 
        # apply change to target_id
101
 
        if 1:
102
 
            cmd = ['patch', '-o', self.tt._limbo_name(targetid),
103
 
                '--directory', self.branch.base, '-p1']
104
 
            #sys.stdout.write("# %r\n"%cmd)
105
 
            child_proc = Popen(cmd, stdin=PIPE)
106
 
            for line in changes:
107
 
                #sys.stdout.write("# %s\n"%line)
108
 
                child_proc.stdin.write(line+'\n')
109
 
            child_proc.stdin.close()
110
 
            r = child_proc.wait()
111
 
 
112
 
        self.changes = []
113
 
 
114
 
    def process(self, cmd = None):
115
 
 
116
 
        while cmd and len(cmd) and cmd[-1] in "\n\r":
117
 
            cmd = cmd[:-1]
118
 
 
119
 
        if ( cmd == None or cmd.startswith("===") ) and self.changes:
120
 
            assert(self.target_id)
121
 
 
122
 
            #print "********** mode=",self.mode
123
 
 
124
 
            if self.mode == "mv" or self.mode == "mod":
125
 
                self.tt.delete_contents(self.target_id)
126
 
 
127
 
            if self.mode == "add" or self.mode == "mod" or self.mode == "mv":
128
 
                self.tt.create_file([],self.target_id)
129
 
                self.do_patch(self.changes, self.target_id)
130
 
 
131
 
            self.target_id = None
132
 
            self.changes = []
133
 
            self.mode = None
134
 
 
135
 
        if cmd == None: return
136
 
        if not cmd.startswith("==="):
137
 
            if self.skipchange: return
138
 
            assert(self.target_id)
139
 
            assert(self.mode)
140
 
            self.changes.append(cmd)
141
 
            return
142
 
 
143
 
        # thr target_id is set during a rename; but there is possibility
144
 
        # that after a rename, is not to do a change
145
 
        self.target_id = None
146
 
        # skip change
147
 
        self.skipchange = False
148
 
        self.mode = None
149
 
 
150
 
        if ( cmd.startswith("=== removed file") or
151
 
             cmd.startswith("=== removed directory") or
152
 
             cmd.startswith("=== removed symlink") ):
153
 
 
154
 
            target = self.extractname(cmd)[2:]
155
 
            tid = self.get_transid(target)
156
 
            self.tt.delete_versioned(tid)
157
 
            print "removing '%s'"%target
158
 
            self.skipchange = True
159
 
            self.mode = "rm"
160
 
 
161
 
        elif cmd.startswith("=== added file"):
162
 
            
163
 
            target = self.extractname(cmd)[2:]
164
 
            self.target_id = self.get_transid(target)
165
 
            #self.tt.create_file([],self.target_id)
166
 
            print "adding '%s'"%target
167
 
            self.mode = "add"
168
 
 
169
 
        elif cmd.startswith("=== modified file"):
170
 
            target = self.extractname(cmd)[2:]
171
 
            self.target_id = self.get_transid(target)
172
 
            self.mode = "mod"
173
 
            print "patching '%s'"%target
174
 
 
175
 
        elif cmd.startswith("=== added directory"):
176
 
            target = self.extractname(cmd)[2:]
177
 
            target_id = self.get_transid(target)
178
 
            self.tt.create_directory(target_id)
179
 
            print "adding directory '%s'"%target
180
 
 
181
 
        elif cmd.startswith("=== added symlink"):
182
 
            assert(not self.link)
183
 
            self.link = self.extractname(cmd)[2:]
184
 
 
185
 
        elif cmd.startswith("=== target is"):
186
 
            assert(self.link)
187
 
            target = self.extractname(cmd)
188
 
            link_id = self.get_transid(self.link)
189
 
            
190
 
            print "symlinking '%s' => '%s'\n"%(target, link_id)
191
 
            self.tt.create_symlink(target, link_id)
192
 
            self.link = None
193
 
 
194
 
        elif ( cmd.startswith("=== renamed symlink") or
195
 
               cmd.startswith("=== renamed file") or
196
 
               cmd.startswith("=== renamed directory") ):
197
 
 
198
 
            source,dest = self.extractnames(cmd)
199
 
            source = source[2:]
200
 
            dest = dest[2:]
201
 
            sourceid = self.get_transid(source)
202
 
            pdir,pname = os.path.split(dest)
203
 
            pdir_id = self.get_transid(pdir)
204
 
            self.tt.adjust_path(pname, pdir_id, sourceid)
205
 
 
206
 
            if cmd.startswith("=== renamed file"):
207
 
                self.target_id = sourceid
208
 
                self.mode = "mv"
209
 
 
210
 
            print "renaming '%s' => '%s'"%(source,dest)
211
 
 
212
 
 
213
 
        else:
214
 
            sys.stderr.write("Unsupported tag: '%s'\n"%cmd)
215
 
 
216
 
    def apply(self):
217
 
        self.tt.apply( )
218
 
 
219
 
 
220
 
 
221
 
def do_patch(p):
222
 
 
223
 
    tree = WorkingTree.open_containing(u'.')[0]
224
 
    tt = bzrlib.transform.TreeTransform(tree)
225
 
    bzrdir = bzrlib.bzrdir.BzrDir.open(".")
226
 
    bzr_tags_proc = BzrPatchProc(tt, tree, bzrdir)
227
 
 
228
 
    for l in p:
229
 
        # we have to remove the \n\r
230
 
        bzr_tags_proc.process(l)
231
 
 
232
 
    bzr_tags_proc.flush( )
233
 
    bzr_tags_proc.apply( )
234
 
 
235
 
def patch(tree, location, strip, legacy):
 
24
 
 
25
def patch(tree, location, strip, quiet=False):
236
26
    """Apply a patch to a branch, using patch(1).  URLs may be used."""
237
27
    my_file = None
238
28
    if location is None:
239
29
        my_file = sys.stdin
240
30
    else:
241
 
        for prefix in ('http://', 'sftp://', 'file://'):
242
 
            if not location.startswith(prefix):
243
 
                continue
244
 
            (scheme, loc, path, query, fragment) = urlsplit(location)
245
 
            loc_start = urlunsplit((scheme, loc, '/', '', ''))
246
 
            my_file = get_transport(loc_start).get(path[1:])
247
 
        if my_file is None:
248
 
            my_file = file(location, 'rb')
 
31
        location = urlutils.normalize_url(location)
 
32
        dirname, basename = urlutils.split(location)
 
33
        my_file = get_transport(dirname).get(basename)
249
34
    cmd = ['patch', '--directory', tree.basedir, '--strip', str(strip)]
 
35
    if quiet:
 
36
        cmd.append('--quiet')
250
37
    r = 0
251
 
    if legacy:
252
 
        child_proc = Popen(cmd, stdin=PIPE)
253
 
        for line in my_file:
254
 
            child_proc.stdin.write(line)
255
 
        child_proc.stdin.close()
256
 
        r = child_proc.wait()
257
 
    else:
258
 
 
259
 
        do_patch(sys.stdin.readlines( ))
 
38
    child_proc = Popen(cmd, stdin=PIPE)
 
39
    for line in my_file:
 
40
        child_proc.stdin.write(line)
 
41
    child_proc.stdin.close()
 
42
    r = child_proc.wait()
260
43
    return r