Mercurial > hg > mercurial-crew-with-dirclash
comparison hgext/mq.py @ 2748:752b9475a700
New mq command qfold: Merge patches into the current patch.
Patches should be in the series file but not yet applied.
author | Brendan Cully <brendan@kublai.com> |
---|---|
date | Mon, 31 Jul 2006 20:33:56 -0700 |
parents | 0016fc748f61 |
children | 8c814c1ab31e 84218111e80f |
comparison
equal
deleted
inserted
replaced
2747:0016fc748f61 | 2748:752b9475a700 |
---|---|
1 | |
1 # queue.py - patch queues for mercurial | 2 # queue.py - patch queues for mercurial |
2 # | 3 # |
3 # Copyright 2005 Chris Mason <mason@suse.com> | 4 # Copyright 2005 Chris Mason <mason@suse.com> |
4 # | 5 # |
5 # This software may be used and distributed according to the terms | 6 # This software may be used and distributed according to the terms |
268 self.applied_dirty = 1 | 269 self.applied_dirty = 1 |
269 if err: | 270 if err: |
270 return (err, head) | 271 return (err, head) |
271 return (0, head) | 272 return (0, head) |
272 | 273 |
274 def patch(self, repo, patchfile): | |
275 '''Apply patchfile to the working directory. | |
276 patchfile: file name of patch''' | |
277 try: | |
278 pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') | |
279 f = os.popen("%s -d '%s' -p1 --no-backup-if-mismatch < '%s'" % | |
280 (pp, repo.root, patchfile)) | |
281 except: | |
282 self.ui.warn("patch failed, unable to continue (try -v)\n") | |
283 return (None, [], False) | |
284 files = [] | |
285 fuzz = False | |
286 for l in f: | |
287 l = l.rstrip('\r\n'); | |
288 if self.ui.verbose: | |
289 self.ui.warn(l + "\n") | |
290 if l[:14] == 'patching file ': | |
291 pf = os.path.normpath(l[14:]) | |
292 # when patch finds a space in the file name, it puts | |
293 # single quotes around the filename. strip them off | |
294 if pf[0] == "'" and pf[-1] == "'": | |
295 pf = pf[1:-1] | |
296 if pf not in files: | |
297 files.append(pf) | |
298 printed_file = False | |
299 file_str = l | |
300 elif l.find('with fuzz') >= 0: | |
301 if not printed_file: | |
302 self.ui.warn(file_str + '\n') | |
303 printed_file = True | |
304 self.ui.warn(l + '\n') | |
305 fuzz = True | |
306 elif l.find('saving rejects to file') >= 0: | |
307 self.ui.warn(l + '\n') | |
308 elif l.find('FAILED') >= 0: | |
309 if not printed_file: | |
310 self.ui.warn(file_str + '\n') | |
311 printed_file = True | |
312 self.ui.warn(l + '\n') | |
313 | |
314 return (not f.close(), files, fuzz) | |
315 | |
273 def apply(self, repo, series, list=False, update_status=True, | 316 def apply(self, repo, series, list=False, update_status=True, |
274 strict=False, patchdir=None, merge=None, wlock=None): | 317 strict=False, patchdir=None, merge=None, wlock=None): |
275 # TODO unify with commands.py | 318 # TODO unify with commands.py |
276 if not patchdir: | 319 if not patchdir: |
277 patchdir = self.path | 320 patchdir = self.path |
297 else: | 340 else: |
298 if list: | 341 if list: |
299 message.append("\nimported patch %s" % patch) | 342 message.append("\nimported patch %s" % patch) |
300 message = '\n'.join(message) | 343 message = '\n'.join(message) |
301 | 344 |
302 try: | 345 (patcherr, files, fuzz) = self.patch(repo, pf) |
303 pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') | 346 patcherr = not patcherr |
304 f = os.popen("%s -d '%s' -p1 --no-backup-if-mismatch < '%s'" % | |
305 (pp, repo.root, pf)) | |
306 except: | |
307 self.ui.warn("patch failed, unable to continue (try -v)\n") | |
308 err = 1 | |
309 break | |
310 files = [] | |
311 fuzz = False | |
312 for l in f: | |
313 l = l.rstrip('\r\n'); | |
314 if self.ui.verbose: | |
315 self.ui.warn(l + "\n") | |
316 if l[:14] == 'patching file ': | |
317 pf = os.path.normpath(l[14:]) | |
318 # when patch finds a space in the file name, it puts | |
319 # single quotes around the filename. strip them off | |
320 if pf[0] == "'" and pf[-1] == "'": | |
321 pf = pf[1:-1] | |
322 if pf not in files: | |
323 files.append(pf) | |
324 printed_file = False | |
325 file_str = l | |
326 elif l.find('with fuzz') >= 0: | |
327 if not printed_file: | |
328 self.ui.warn(file_str + '\n') | |
329 printed_file = True | |
330 self.ui.warn(l + '\n') | |
331 fuzz = True | |
332 elif l.find('saving rejects to file') >= 0: | |
333 self.ui.warn(l + '\n') | |
334 elif l.find('FAILED') >= 0: | |
335 if not printed_file: | |
336 self.ui.warn(file_str + '\n') | |
337 printed_file = True | |
338 self.ui.warn(l + '\n') | |
339 patcherr = f.close() | |
340 | 347 |
341 if merge and len(files) > 0: | 348 if merge and len(files) > 0: |
342 # Mark as merged and update dirstate parent info | 349 # Mark as merged and update dirstate parent info |
343 repo.dirstate.update(repo.dirstate.filterfiles(files), 'm') | 350 repo.dirstate.update(repo.dirstate.filterfiles(files), 'm') |
344 p1, p2 = repo.dirstate.parents() | 351 p1, p2 = repo.dirstate.parents() |
1287 """diff of the current patch""" | 1294 """diff of the current patch""" |
1288 # deep in the dirstate code, the walkhelper method wants a list, not a tuple | 1295 # deep in the dirstate code, the walkhelper method wants a list, not a tuple |
1289 repo.mq.diff(repo, list(files)) | 1296 repo.mq.diff(repo, list(files)) |
1290 return 0 | 1297 return 0 |
1291 | 1298 |
1299 def fold(ui, repo, *files): | |
1300 """fold the named patches into the current patch | |
1301 Patches must not yet be applied.""" | |
1302 q = repo.mq | |
1303 | |
1304 if not files: | |
1305 raise util.Abort(_('qfold requires at least one patch name')) | |
1306 if not q.check_toppatch(repo): | |
1307 raise util.Abort(_('No patches applied\n')) | |
1308 | |
1309 parent = q.lookup('qtip') | |
1310 patches = [] | |
1311 messages = [] | |
1312 for f in files: | |
1313 patch = q.lookup(f) | |
1314 if patch in patches or patch == parent: | |
1315 self.ui.warn(_('Skipping already folded patch %s') % patch) | |
1316 if q.isapplied(patch): | |
1317 raise util.Abort(_('qfold cannot fold already applied patch %s') % patch) | |
1318 patches.append(patch) | |
1319 | |
1320 for patch in patches: | |
1321 messages.append(q.readheaders(patch)[0]) | |
1322 pf = os.path.join(q.path, patch) | |
1323 (patchsuccess, files, fuzz) = q.patch(repo, pf) | |
1324 if not patchsuccess: | |
1325 raise util.Abort(_('Error folding patch %s') % patch) | |
1326 | |
1327 message = q.readheaders(parent)[0] | |
1328 for msg in messages: | |
1329 message.append('* * *') | |
1330 message.extend(msg) | |
1331 message = '\n'.join(message) | |
1332 | |
1333 q.refresh(repo, msg=message) | |
1334 | |
1335 for patch in patches: | |
1336 q.delete(repo, patch) | |
1337 | |
1338 q.save_dirty() | |
1339 | |
1292 def header(ui, repo, patch=None): | 1340 def header(ui, repo, patch=None): |
1293 """Print the header of the topmost or specified patch""" | 1341 """Print the header of the topmost or specified patch""" |
1294 q = repo.mq | 1342 q = repo.mq |
1295 | 1343 |
1296 if patch: | 1344 if patch: |
1460 (commit, | 1508 (commit, |
1461 commands.table["^commit|ci"][1], | 1509 commands.table["^commit|ci"][1], |
1462 'hg qcommit [OPTION]... [FILE]...'), | 1510 'hg qcommit [OPTION]... [FILE]...'), |
1463 "^qdiff": (diff, [], 'hg qdiff [FILE]...'), | 1511 "^qdiff": (diff, [], 'hg qdiff [FILE]...'), |
1464 "qdelete": (delete, [], 'hg qdelete PATCH'), | 1512 "qdelete": (delete, [], 'hg qdelete PATCH'), |
1513 'qfold': (fold, [], 'hg qfold PATCH...'), | |
1465 'qheader': (header, [], | 1514 'qheader': (header, [], |
1466 _('hg qheader [PATCH]')), | 1515 _('hg qheader [PATCH]')), |
1467 "^qimport": | 1516 "^qimport": |
1468 (qimport, | 1517 (qimport, |
1469 [('e', 'existing', None, 'import file in patch dir'), | 1518 [('e', 'existing', None, 'import file in patch dir'), |