comparison mercurial/patch.py @ 2952:6ba3409f9725

merge.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Fri, 18 Aug 2006 17:02:38 -0700
parents 5ddf7d305a27 2f190e998eb3
children efd26ceedafb
comparison
equal deleted inserted replaced
2951:5ddf7d305a27 2952:6ba3409f9725
8 from demandload import demandload 8 from demandload import demandload
9 from i18n import gettext as _ 9 from i18n import gettext as _
10 from node import * 10 from node import *
11 demandload(globals(), "cmdutil mdiff util") 11 demandload(globals(), "cmdutil mdiff util")
12 demandload(globals(), "cStringIO email.Parser errno os re shutil sys tempfile") 12 demandload(globals(), "cStringIO email.Parser errno os re shutil sys tempfile")
13
14 # helper functions
15
16 def copyfile(src, dst, basedir=None):
17 if not basedir:
18 basedir = os.getcwd()
19
20 abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)]
21 if os.path.exists(absdst):
22 raise util.Abort(_("cannot create %s: destination already exists") %
23 dst)
24
25 targetdir = os.path.dirname(absdst)
26 if not os.path.isdir(targetdir):
27 os.makedirs(targetdir)
28 try:
29 shutil.copyfile(abssrc, absdst)
30 shutil.copymode(abssrc, absdst)
31 except shutil.Error, inst:
32 raise util.Abort(str(inst))
33
34 # public functions
13 35
14 def extract(ui, fileobj): 36 def extract(ui, fileobj):
15 '''extract patch from data read from fileobj. 37 '''extract patch from data read from fileobj.
16 38
17 patch can be normal patch or contained in email message. 39 patch can be normal patch or contained in email message.
172 for i in range(len(gitpatches)): 194 for i in range(len(gitpatches)):
173 p = gitpatches[i] 195 p = gitpatches[i]
174 if not p.copymod: 196 if not p.copymod:
175 continue 197 continue
176 198
177 if os.path.exists(p.path): 199 copyfile(p.oldpath, p.path)
178 raise util.Abort(_("cannot create %s: destination already exists") %
179 p.path)
180
181 (src, dst) = [os.path.join(os.getcwd(), n)
182 for n in (p.oldpath, p.path)]
183
184 targetdir = os.path.dirname(dst)
185 if not os.path.isdir(targetdir):
186 os.makedirs(targetdir)
187 try:
188 shutil.copyfile(src, dst)
189 shutil.copymode(src, dst)
190 except shutil.Error, inst:
191 raise util.Abort(str(inst))
192 200
193 # rewrite patch hunk 201 # rewrite patch hunk
194 while pfline < p.lineno: 202 while pfline < p.lineno:
195 tmpfp.write(pf.readline()) 203 tmpfp.write(pf.readline())
196 pfline += 1 204 pfline += 1
279 ignorewsamount=(opts.get('ignore_space_change') or 287 ignorewsamount=(opts.get('ignore_space_change') or
280 ui.configbool('diff', 'ignorewsamount', None)), 288 ui.configbool('diff', 'ignorewsamount', None)),
281 ignoreblanklines=(opts.get('ignore_blank_lines') or 289 ignoreblanklines=(opts.get('ignore_blank_lines') or
282 ui.configbool('diff', 'ignoreblanklines', None))) 290 ui.configbool('diff', 'ignoreblanklines', None)))
283 291
292 def updatedir(ui, repo, patches, wlock=None):
293 '''Update dirstate after patch application according to metadata'''
294 if not patches:
295 return
296 copies = []
297 removes = []
298 cfiles = patches.keys()
299 copts = {'after': False, 'force': False}
300 cwd = repo.getcwd()
301 if cwd:
302 cfiles = [util.pathto(cwd, f) for f in patches.keys()]
303 for f in patches:
304 ctype, gp = patches[f]
305 if ctype == 'RENAME':
306 copies.append((gp.oldpath, gp.path, gp.copymod))
307 removes.append(gp.oldpath)
308 elif ctype == 'COPY':
309 copies.append((gp.oldpath, gp.path, gp.copymod))
310 elif ctype == 'DELETE':
311 removes.append(gp.path)
312 for src, dst, after in copies:
313 if not after:
314 copyfile(src, dst, repo.root)
315 repo.copy(src, dst, wlock=wlock)
316 if removes:
317 repo.remove(removes, True, wlock=wlock)
318 for f in patches:
319 ctype, gp = patches[f]
320 if gp and gp.mode:
321 x = gp.mode & 0100 != 0
322 dst = os.path.join(repo.root, gp.path)
323 util.set_exec(dst, x)
324 cmdutil.addremove(repo, cfiles, wlock=wlock)
325 files = patches.keys()
326 files.extend([r for r in removes if r not in files])
327 files.sort()
328
329 return files
330
284 def diff(repo, node1=None, node2=None, files=None, match=util.always, 331 def diff(repo, node1=None, node2=None, files=None, match=util.always,
285 fp=None, changes=None, opts=None): 332 fp=None, changes=None, opts=None):
286 '''print diff of changes to files between two nodes, or node and 333 '''print diff of changes to files between two nodes, or node and
287 working directory. 334 working directory.
288 335
294 if fp is None: 341 if fp is None:
295 fp = repo.ui 342 fp = repo.ui
296 343
297 if not node1: 344 if not node1:
298 node1 = repo.dirstate.parents()[0] 345 node1 = repo.dirstate.parents()[0]
346
347 clcache = {}
348 def getchangelog(n):
349 if n not in clcache:
350 clcache[n] = repo.changelog.read(n)
351 return clcache[n]
352 mcache = {}
353 def getmanifest(n):
354 if n not in mcache:
355 mcache[n] = repo.manifest.read(n)
356 return mcache[n]
357 fcache = {}
358 def getfile(f):
359 if f not in fcache:
360 fcache[f] = repo.file(f)
361 return fcache[f]
362
299 # reading the data for node1 early allows it to play nicely 363 # reading the data for node1 early allows it to play nicely
300 # with repo.status and the revlog cache. 364 # with repo.status and the revlog cache.
301 change = repo.changelog.read(node1) 365 change = getchangelog(node1)
302 mmap = repo.manifest.read(change[0]) 366 mmap = getmanifest(change[0])
303 date1 = util.datestr(change[2]) 367 date1 = util.datestr(change[2])
304 368
305 if not changes: 369 if not changes:
306 changes = repo.status(node1, node2, files, match=match)[:5] 370 changes = repo.status(node1, node2, files, match=match)[:5]
307 modified, added, removed, deleted, unknown = changes 371 modified, added, removed, deleted, unknown = changes
318 modified, added, removed = map(filterfiles, (modified, added, removed)) 382 modified, added, removed = map(filterfiles, (modified, added, removed))
319 383
320 if not modified and not added and not removed: 384 if not modified and not added and not removed:
321 return 385 return
322 386
387 def renamedbetween(f, n1, n2):
388 r1, r2 = map(repo.changelog.rev, (n1, n2))
389 src = None
390 while r2 > r1:
391 cl = getchangelog(n2)[0]
392 m = getmanifest(cl)
393 try:
394 src = getfile(f).renamed(m[f])
395 except KeyError:
396 return None
397 if src:
398 f = src[0]
399 n2 = repo.changelog.parents(n2)[0]
400 r2 = repo.changelog.rev(n2)
401 return src
402
323 if node2: 403 if node2:
324 change = repo.changelog.read(node2) 404 change = getchangelog(node2)
325 mmap2 = repo.manifest.read(change[0]) 405 mmap2 = getmanifest(change[0])
326 _date2 = util.datestr(change[2]) 406 _date2 = util.datestr(change[2])
327 def date2(f): 407 def date2(f):
328 return _date2 408 return _date2
329 def read(f): 409 def read(f):
330 return repo.file(f).read(mmap2[f]) 410 return getfile(f).read(mmap2[f])
331 def renamed(f): 411 def renamed(f):
332 src = repo.file(f).renamed(mmap2[f]) 412 return renamedbetween(f, node1, node2)
333 return src and src[0] or None
334 else: 413 else:
335 tz = util.makedate()[1] 414 tz = util.makedate()[1]
336 _date2 = util.datestr() 415 _date2 = util.datestr()
337 def date2(f): 416 def date2(f):
338 try: 417 try:
341 if err.errno != errno.ENOENT: raise 420 if err.errno != errno.ENOENT: raise
342 return _date2 421 return _date2
343 def read(f): 422 def read(f):
344 return repo.wread(f) 423 return repo.wread(f)
345 def renamed(f): 424 def renamed(f):
346 return repo.dirstate.copies.get(f) 425 src = repo.dirstate.copies.get(f)
426 parent = repo.dirstate.parents()[0]
427 if src:
428 f = src[0]
429 of = renamedbetween(f, node1, parent)
430 if of:
431 return of
432 elif src:
433 cl = getchangelog(parent)[0]
434 return (src, getmanifest(cl)[src])
435 else:
436 return None
347 437
348 if repo.ui.quiet: 438 if repo.ui.quiet:
349 r = None 439 r = None
350 else: 440 else:
351 hexfunc = repo.ui.verbose and hex or short 441 hexfunc = repo.ui.verbose and hex or short
355 copied = {} 445 copied = {}
356 for f in added: 446 for f in added:
357 src = renamed(f) 447 src = renamed(f)
358 if src: 448 if src:
359 copied[f] = src 449 copied[f] = src
360 srcs = [x[1] for x in copied.items()] 450 srcs = [x[1][0] for x in copied.items()]
361 451
362 all = modified + added + removed 452 all = modified + added + removed
363 all.sort() 453 all.sort()
364 for f in all: 454 for f in all:
365 to = None 455 to = None
366 tn = None 456 tn = None
367 dodiff = True 457 dodiff = True
368 if f in mmap: 458 if f in mmap:
369 to = repo.file(f).read(mmap[f]) 459 to = getfile(f).read(mmap[f])
370 if f not in removed: 460 if f not in removed:
371 tn = read(f) 461 tn = read(f)
372 if opts.git: 462 if opts.git:
373 def gitmode(x): 463 def gitmode(x):
374 return x and '100755' or '100644' 464 return x and '100755' or '100644'
383 if node2: 473 if node2:
384 mode = gitmode(mmap2.execf(f)) 474 mode = gitmode(mmap2.execf(f))
385 else: 475 else:
386 mode = gitmode(util.is_exec(repo.wjoin(f), None)) 476 mode = gitmode(util.is_exec(repo.wjoin(f), None))
387 if f in copied: 477 if f in copied:
388 a = copied[f] 478 a, arev = copied[f]
389 omode = gitmode(mmap.execf(a)) 479 omode = gitmode(mmap.execf(a))
390 addmodehdr(header, omode, mode) 480 addmodehdr(header, omode, mode)
391 op = a in removed and 'rename' or 'copy' 481 op = a in removed and 'rename' or 'copy'
392 header.append('%s from %s\n' % (op, a)) 482 header.append('%s from %s\n' % (op, a))
393 header.append('%s to %s\n' % (op, f)) 483 header.append('%s to %s\n' % (op, f))
394 to = repo.file(a).read(mmap[a]) 484 to = getfile(a).read(arev)
395 else: 485 else:
396 header.append('new file mode %s\n' % mode) 486 header.append('new file mode %s\n' % mode)
397 elif f in removed: 487 elif f in removed:
398 if f in srcs: 488 if f in srcs:
399 dodiff = False 489 dodiff = False