~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to patch.py

  • Committer: Aaron Bentley
  • Date: 2006-12-12 02:21:50 UTC
  • Revision ID: aaron.bentley@utoronto.ca-20061212022150-7lqyw46pbb3jhkak
Clean up patch command (support http urls again)

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
from urlparse import urlsplit, urlunsplit
 
20
 
 
21
from bzrlib import urlutils
19
22
from bzrlib.transport import get_transport
20
 
from urlparse import urlsplit, urlunsplit
21
23
from bzrlib.workingtree import WorkingTree
22
24
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):
 
25
 
 
26
def patch(tree, location, strip):
236
27
    """Apply a patch to a branch, using patch(1).  URLs may be used."""
237
28
    my_file = None
238
29
    if location is None:
239
30
        my_file = sys.stdin
240
31
    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')
 
32
        location = urlutils.normalize_url(location)
 
33
        (scheme, loc, path, query, fragment) = urlsplit(location)
 
34
        loc_start = urlunsplit((scheme, loc, '/', '', ''))
 
35
        my_file = get_transport(loc_start).get(path[1:])
249
36
    cmd = ['patch', '--directory', tree.basedir, '--strip', str(strip)]
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