Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/commands.py @ 5589:9981b6b19ecf
move commands.docopy to cmdutil.copy
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Sun, 02 Dec 2007 18:11:59 -0600 |
parents | 8788ff630c26 |
children | 2493a478f395 |
comparison
equal
deleted
inserted
replaced
5588:083b6e3142a2 | 5589:9981b6b19ecf |
---|---|
436 def commitfunc(ui, repo, files, message, match, opts): | 436 def commitfunc(ui, repo, files, message, match, opts): |
437 return repo.commit(files, message, opts['user'], opts['date'], match, | 437 return repo.commit(files, message, opts['user'], opts['date'], match, |
438 force_editor=opts.get('force_editor')) | 438 force_editor=opts.get('force_editor')) |
439 cmdutil.commit(ui, repo, commitfunc, pats, opts) | 439 cmdutil.commit(ui, repo, commitfunc, pats, opts) |
440 | 440 |
441 def docopy(ui, repo, pats, opts): | |
442 # called with the repo lock held | |
443 # | |
444 # hgsep => pathname that uses "/" to separate directories | |
445 # ossep => pathname that uses os.sep to separate directories | |
446 cwd = repo.getcwd() | |
447 errors = 0 | |
448 copied = [] | |
449 targets = {} | |
450 | |
451 # abs: hgsep | |
452 # rel: ossep | |
453 # return: hgsep | |
454 def okaytocopy(abs, rel, exact): | |
455 reasons = {'?': _('is not managed'), | |
456 'r': _('has been marked for remove')} | |
457 state = repo.dirstate[abs] | |
458 reason = reasons.get(state) | |
459 if reason: | |
460 if exact: | |
461 ui.warn(_('%s: not copying - file %s\n') % (rel, reason)) | |
462 else: | |
463 if state == 'a': | |
464 origsrc = repo.dirstate.copied(abs) | |
465 if origsrc is not None: | |
466 return origsrc | |
467 return abs | |
468 | |
469 # origsrc: hgsep | |
470 # abssrc: hgsep | |
471 # relsrc: ossep | |
472 # otarget: ossep | |
473 def copy(origsrc, abssrc, relsrc, otarget, exact): | |
474 abstarget = util.canonpath(repo.root, cwd, otarget) | |
475 reltarget = repo.pathto(abstarget, cwd) | |
476 prevsrc = targets.get(abstarget) | |
477 src = repo.wjoin(abssrc) | |
478 target = repo.wjoin(abstarget) | |
479 if prevsrc is not None: | |
480 ui.warn(_('%s: not overwriting - %s collides with %s\n') % | |
481 (reltarget, repo.pathto(abssrc, cwd), | |
482 repo.pathto(prevsrc, cwd))) | |
483 return | |
484 if (not opts['after'] and os.path.exists(target) or | |
485 opts['after'] and repo.dirstate[abstarget] in 'mn'): | |
486 if not opts['force']: | |
487 ui.warn(_('%s: not overwriting - file exists\n') % | |
488 reltarget) | |
489 return | |
490 if not opts['after'] and not opts.get('dry_run'): | |
491 os.unlink(target) | |
492 if opts['after']: | |
493 if not os.path.exists(target): | |
494 return | |
495 else: | |
496 targetdir = os.path.dirname(target) or '.' | |
497 if not os.path.isdir(targetdir) and not opts.get('dry_run'): | |
498 os.makedirs(targetdir) | |
499 try: | |
500 restore = repo.dirstate[abstarget] == 'r' | |
501 if restore and not opts.get('dry_run'): | |
502 repo.undelete([abstarget]) | |
503 try: | |
504 if not opts.get('dry_run'): | |
505 util.copyfile(src, target) | |
506 restore = False | |
507 finally: | |
508 if restore: | |
509 repo.remove([abstarget]) | |
510 except IOError, inst: | |
511 if inst.errno == errno.ENOENT: | |
512 ui.warn(_('%s: deleted in working copy\n') % relsrc) | |
513 else: | |
514 ui.warn(_('%s: cannot copy - %s\n') % | |
515 (relsrc, inst.strerror)) | |
516 errors += 1 | |
517 return | |
518 if ui.verbose or not exact: | |
519 ui.status(_('copying %s to %s\n') % (relsrc, reltarget)) | |
520 targets[abstarget] = abssrc | |
521 if abstarget != origsrc: | |
522 if repo.dirstate[origsrc] == 'a': | |
523 if not ui.quiet: | |
524 ui.warn(_("%s has not been committed yet, so no copy " | |
525 "data will be stored for %s.\n") | |
526 % (repo.pathto(origsrc, cwd), reltarget)) | |
527 if abstarget not in repo.dirstate and not opts.get('dry_run'): | |
528 repo.add([abstarget]) | |
529 elif not opts.get('dry_run'): | |
530 repo.copy(origsrc, abstarget) | |
531 copied.append((abssrc, relsrc, exact)) | |
532 | |
533 # pat: ossep | |
534 # dest ossep | |
535 # srcs: list of (hgsep, hgsep, ossep, bool) | |
536 # return: function that takes hgsep and returns ossep | |
537 def targetpathfn(pat, dest, srcs): | |
538 if os.path.isdir(pat): | |
539 abspfx = util.canonpath(repo.root, cwd, pat) | |
540 abspfx = util.localpath(abspfx) | |
541 if destdirexists: | |
542 striplen = len(os.path.split(abspfx)[0]) | |
543 else: | |
544 striplen = len(abspfx) | |
545 if striplen: | |
546 striplen += len(os.sep) | |
547 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:]) | |
548 elif destdirexists: | |
549 res = lambda p: os.path.join(dest, | |
550 os.path.basename(util.localpath(p))) | |
551 else: | |
552 res = lambda p: dest | |
553 return res | |
554 | |
555 # pat: ossep | |
556 # dest ossep | |
557 # srcs: list of (hgsep, hgsep, ossep, bool) | |
558 # return: function that takes hgsep and returns ossep | |
559 def targetpathafterfn(pat, dest, srcs): | |
560 if util.patkind(pat, None)[0]: | |
561 # a mercurial pattern | |
562 res = lambda p: os.path.join(dest, | |
563 os.path.basename(util.localpath(p))) | |
564 else: | |
565 abspfx = util.canonpath(repo.root, cwd, pat) | |
566 if len(abspfx) < len(srcs[0][0]): | |
567 # A directory. Either the target path contains the last | |
568 # component of the source path or it does not. | |
569 def evalpath(striplen): | |
570 score = 0 | |
571 for s in srcs: | |
572 t = os.path.join(dest, util.localpath(s[0])[striplen:]) | |
573 if os.path.exists(t): | |
574 score += 1 | |
575 return score | |
576 | |
577 abspfx = util.localpath(abspfx) | |
578 striplen = len(abspfx) | |
579 if striplen: | |
580 striplen += len(os.sep) | |
581 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])): | |
582 score = evalpath(striplen) | |
583 striplen1 = len(os.path.split(abspfx)[0]) | |
584 if striplen1: | |
585 striplen1 += len(os.sep) | |
586 if evalpath(striplen1) > score: | |
587 striplen = striplen1 | |
588 res = lambda p: os.path.join(dest, | |
589 util.localpath(p)[striplen:]) | |
590 else: | |
591 # a file | |
592 if destdirexists: | |
593 res = lambda p: os.path.join(dest, | |
594 os.path.basename(util.localpath(p))) | |
595 else: | |
596 res = lambda p: dest | |
597 return res | |
598 | |
599 | |
600 pats = util.expand_glob(pats) | |
601 if not pats: | |
602 raise util.Abort(_('no source or destination specified')) | |
603 if len(pats) == 1: | |
604 raise util.Abort(_('no destination specified')) | |
605 dest = pats.pop() | |
606 destdirexists = os.path.isdir(dest) | |
607 if not destdirexists: | |
608 if len(pats) > 1 or util.patkind(pats[0], None)[0]: | |
609 raise util.Abort(_('with multiple sources, destination must be an ' | |
610 'existing directory')) | |
611 if dest.endswith(os.sep) or os.altsep and dest.endswith(os.altsep): | |
612 raise util.Abort(_('destination %s is not a directory') % dest) | |
613 if opts['after']: | |
614 tfn = targetpathafterfn | |
615 else: | |
616 tfn = targetpathfn | |
617 copylist = [] | |
618 for pat in pats: | |
619 srcs = [] | |
620 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts, | |
621 globbed=True): | |
622 origsrc = okaytocopy(abssrc, relsrc, exact) | |
623 if origsrc: | |
624 srcs.append((origsrc, abssrc, relsrc, exact)) | |
625 if not srcs: | |
626 continue | |
627 copylist.append((tfn(pat, dest, srcs), srcs)) | |
628 if not copylist: | |
629 raise util.Abort(_('no files to copy')) | |
630 | |
631 for targetpath, srcs in copylist: | |
632 for origsrc, abssrc, relsrc, exact in srcs: | |
633 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact) | |
634 | |
635 if errors: | |
636 ui.warn(_('(consider using --after)\n')) | |
637 return errors, copied | |
638 | |
639 def copy(ui, repo, *pats, **opts): | 441 def copy(ui, repo, *pats, **opts): |
640 """mark files as copied for the next commit | 442 """mark files as copied for the next commit |
641 | 443 |
642 Mark dest as having copies of source files. If dest is a | 444 Mark dest as having copies of source files. If dest is a |
643 directory, copies are put in that directory. If dest is a file, | 445 directory, copies are put in that directory. If dest is a file, |
650 This command takes effect in the next commit. To undo a copy | 452 This command takes effect in the next commit. To undo a copy |
651 before that, see hg revert. | 453 before that, see hg revert. |
652 """ | 454 """ |
653 wlock = repo.wlock(False) | 455 wlock = repo.wlock(False) |
654 try: | 456 try: |
655 errs, copied = docopy(ui, repo, pats, opts) | 457 errs, copied = cmdutil.copy(ui, repo, pats, opts) |
656 finally: | 458 finally: |
657 del wlock | 459 del wlock |
658 return errs | 460 return errs |
659 | 461 |
660 def debugancestor(ui, index, rev1, rev2): | 462 def debugancestor(ui, index, rev1, rev2): |
2258 This command takes effect in the next commit. To undo a rename | 2060 This command takes effect in the next commit. To undo a rename |
2259 before that, see hg revert. | 2061 before that, see hg revert. |
2260 """ | 2062 """ |
2261 wlock = repo.wlock(False) | 2063 wlock = repo.wlock(False) |
2262 try: | 2064 try: |
2263 errs, copied = docopy(ui, repo, pats, opts) | 2065 errs, copied = cmdutil.copy(ui, repo, pats, opts) |
2264 names = [] | 2066 names = [] |
2265 for abs, rel, exact in copied: | 2067 for abs, rel, exact in copied: |
2266 if ui.verbose or not exact: | 2068 if ui.verbose or not exact: |
2267 ui.status(_('removing %s\n') % rel) | 2069 ui.status(_('removing %s\n') % rel) |
2268 names.append(abs) | 2070 names.append(abs) |