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
18
from subprocess import Popen, PIPE
19
from bzrlib.transport import get_transport
20
from urlparse import urlsplit, urlunsplit
21
from bzrlib.workingtree import WorkingTree
22
from bzrlib.plugins.bzrtools.bzrtools import open_from_url
23
from errors import PatchFailed, PatchInvokeError
25
def patch(tree, location, strip, quiet=False):
23
import bzrlib.transform
28
"""This class process the bzr patch
32
execute attribute support
34
def __init__(self, tt, tree, bzrdir):
42
self.skipchange = True
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])
51
def get_transid(self, path):
52
return self.tt.trans_id_tree_path(path)
55
def _extractname(self, s):
74
def extractname(self, s):
77
space = s.find(" ",space+1) # find the 2nd space
79
return self._extractname(s[space+1:])[0]
82
def extractnames(self, s):
85
space = s.find(" ",space+1) # find the 2nd space
88
source, pos = self._extractname(s)
89
assert( pos +4 < len(s) )
90
dest, dummy = self._extractname(s[pos+4:])
99
def do_patch(self, changes, targetid):
100
# apply change to target_id
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)
107
#sys.stdout.write("# %s\n"%line)
108
child_proc.stdin.write(line+'\n')
109
child_proc.stdin.close()
110
r = child_proc.wait()
114
def process(self, cmd = None):
116
while cmd and len(cmd) and cmd[-1] in "\n\r":
119
if ( cmd == None or cmd.startswith("===") ) and self.changes:
120
assert(self.target_id)
122
#print "********** mode=",self.mode
124
if self.mode == "mv" or self.mode == "mod":
125
self.tt.delete_contents(self.target_id)
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)
131
self.target_id = None
135
if cmd == None: return
136
if not cmd.startswith("==="):
137
if self.skipchange: return
138
assert(self.target_id)
140
self.changes.append(cmd)
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
147
self.skipchange = False
150
if ( cmd.startswith("=== removed file") or
151
cmd.startswith("=== removed directory") or
152
cmd.startswith("=== removed symlink") ):
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
161
elif cmd.startswith("=== added file"):
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
169
elif cmd.startswith("=== modified file"):
170
target = self.extractname(cmd)[2:]
171
self.target_id = self.get_transid(target)
173
print "patching '%s'"%target
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
181
elif cmd.startswith("=== added symlink"):
182
assert(not self.link)
183
self.link = self.extractname(cmd)[2:]
185
elif cmd.startswith("=== target is"):
187
target = self.extractname(cmd)
188
link_id = self.get_transid(self.link)
190
print "symlinking '%s' => '%s'\n"%(target, link_id)
191
self.tt.create_symlink(target, link_id)
194
elif ( cmd.startswith("=== renamed symlink") or
195
cmd.startswith("=== renamed file") or
196
cmd.startswith("=== renamed directory") ):
198
source,dest = self.extractnames(cmd)
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)
206
if cmd.startswith("=== renamed file"):
207
self.target_id = sourceid
210
print "renaming '%s' => '%s'"%(source,dest)
214
sys.stderr.write("Unsupported tag: '%s'\n"%cmd)
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)
229
# we have to remove the \n\r
230
bzr_tags_proc.process(l)
232
bzr_tags_proc.flush( )
233
bzr_tags_proc.apply( )
235
def patch(tree, location, strip, legacy):
26
236
"""Apply a patch to a branch, using patch(1). URLs may be used."""
28
238
if location is None:
29
239
my_file = sys.stdin
31
my_file = open_from_url(location)
32
patches = [my_file.read()]
33
return run_patch(tree.basedir, patches, strip, quiet=quiet)
36
def run_patch(directory, patches, strip=0, reverse=False, dry_run=False,
37
quiet=False, _patch_cmd='patch', target_file=None):
38
args = [_patch_cmd, '-d', directory, '-s', '-p%d' % strip, '-f']
40
args.append('--quiet')
42
if sys.platform == "win32":
43
args.append('--binary')
48
if sys.platform.startswith('freebsd'):
49
args.append('--check')
51
args.append('--dry-run')
52
stderr = subprocess.PIPE
241
for prefix in ('http://', 'sftp://', 'file://'):
242
if not location.startswith(prefix):
244
(scheme, loc, path, query, fragment) = urlsplit(location)
245
loc_start = urlunsplit((scheme, loc, '/', '', ''))
246
my_file = get_transport(loc_start).get(path[1:])
248
my_file = file(location, 'rb')
249
cmd = ['patch', '--directory', tree.basedir, '--strip', str(strip)]
252
child_proc = Popen(cmd, stdin=PIPE)
254
child_proc.stdin.write(line)
255
child_proc.stdin.close()
256
r = child_proc.wait()
55
if target_file is not None:
56
args.append(target_file)
59
process = subprocess.Popen(args, stdin=subprocess.PIPE,
60
stdout=subprocess.PIPE, stderr=stderr)
62
raise PatchInvokeError(e)
65
process.stdin.write(str(patch))
69
raise PatchInvokeError(e, process.stderr.read())
71
result = process.wait()
73
sys.stdout.write(process.stdout.read())
259
do_patch(sys.stdin.readlines( ))