comparison mercurial/commands.py @ 1512:53ad6ee6ede4

generalize copy/rename to handle more than one source directory
author Robin Farine <robin.farine@terminus.org>
date Tue, 08 Nov 2005 10:35:05 -0800
parents cd8fadd8c689
children 5c3b93b244aa
comparison
equal deleted inserted replaced
1511:a91bfbbe88d3 1512:53ad6ee6ede4
785 repo.commit(files, message, opts['user'], opts['date'], match) 785 repo.commit(files, message, opts['user'], opts['date'], match)
786 except ValueError, inst: 786 except ValueError, inst:
787 raise util.Abort(str(inst)) 787 raise util.Abort(str(inst))
788 788
789 def docopy(ui, repo, pats, opts): 789 def docopy(ui, repo, pats, opts):
790 if not pats: 790 cwd = repo.getcwd()
791 raise util.Abort(_('no source or destination specified')) 791 errors = 0
792 elif len(pats) == 1: 792 copied = []
793 raise util.Abort(_('no destination specified'))
794 pats = list(pats)
795 dest = pats.pop()
796 sources = []
797 dir2dir = len(pats) == 1 and os.path.isdir(pats[0])
798 793
799 def okaytocopy(abs, rel, exact): 794 def okaytocopy(abs, rel, exact):
800 reasons = {'?': _('is not managed'), 795 reasons = {'?': _('is not managed'),
801 'a': _('has been marked for add')} 796 'a': _('has been marked for add')}
802 reason = reasons.get(repo.dirstate.state(abs)) 797 reason = reasons.get(repo.dirstate.state(abs))
803 if reason: 798 if reason:
804 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason)) 799 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
805 else: 800 else:
806 return True 801 return True
807 802
808 for src, abs, rel, exact in walk(repo, pats, opts): 803 def copy(abssrc, relsrc, target, exact):
809 if okaytocopy(abs, rel, exact): 804 abstarget = util.canonpath(repo.root, cwd, target)
810 sources.append((abs, rel, exact)) 805 reltarget = util.pathto(cwd, abstarget)
811 if not sources: 806 if not opts['force'] and repo.dirstate.state(abstarget) not in 'a?':
812 raise util.Abort(_('no files to copy')) 807 ui.warn(_('%s: not overwriting - file already managed\n') %
813 808 reltarget)
814 cwd = repo.getcwd() 809 return
815 absdest = util.canonpath(repo.root, cwd, dest) 810 if ui.verbose or not exact:
816 reldest = util.pathto(cwd, absdest) 811 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
817 if os.path.exists(reldest):
818 destisfile = not os.path.isdir(reldest)
819 else:
820 destisfile = not dir2dir and (len(sources) == 1
821 or repo.dirstate.state(absdest) != '?')
822
823 if destisfile and len(sources) > 1:
824 raise util.Abort(_('with multiple sources, destination must be a '
825 'directory'))
826
827 srcpfxlen = 0
828 if dir2dir:
829 srcpfx = util.pathto(cwd, util.canonpath(repo.root, cwd, pats[0]))
830 if os.path.exists(reldest):
831 srcpfx = os.path.split(srcpfx)[0]
832 if srcpfx:
833 srcpfx += os.sep
834 srcpfxlen = len(srcpfx)
835
836 errs, copied = 0, []
837 for abs, rel, exact in sources:
838 if destisfile:
839 mydest = reldest
840 elif dir2dir:
841 mydest = os.path.join(dest, rel[srcpfxlen:])
842 else:
843 mydest = os.path.join(dest, os.path.basename(rel))
844 myabsdest = util.canonpath(repo.root, cwd, mydest)
845 myreldest = util.pathto(cwd, myabsdest)
846 if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
847 ui.warn(_('%s: not overwriting - file already managed\n') % myreldest)
848 continue
849 mydestdir = os.path.dirname(myreldest) or '.'
850 if not opts['after']: 812 if not opts['after']:
813 targetdir = os.path.dirname(reltarget) or '.'
814 if not os.path.isdir(targetdir):
815 os.makedirs(targetdir)
851 try: 816 try:
852 if dir2dir: os.makedirs(mydestdir) 817 shutil.copyfile(relsrc, reltarget)
853 elif not destisfile: os.mkdir(mydestdir) 818 shutil.copymode(relsrc, reltarget)
854 except OSError, inst:
855 if inst.errno != errno.EEXIST: raise
856 if ui.verbose or not exact:
857 ui.status(_('copying %s to %s\n') % (rel, myreldest))
858 if not opts['after']:
859 try:
860 shutil.copyfile(rel, myreldest)
861 shutil.copymode(rel, myreldest)
862 except shutil.Error, inst: 819 except shutil.Error, inst:
863 raise util.Abort(str(inst)) 820 raise util.Abort(str(inst))
864 except IOError, inst: 821 except IOError, inst:
865 if inst.errno == errno.ENOENT: 822 if inst.errno == errno.ENOENT:
866 ui.warn(_('%s: deleted in working copy\n') % rel) 823 ui.warn(_('%s: deleted in working copy\n') % relsrc)
867 else: 824 else:
868 ui.warn(_('%s: cannot copy - %s\n') % (rel, inst.strerror)) 825 ui.warn(_('%s: cannot copy - %s\n') %
869 errs += 1 826 (relsrc, inst.strerror))
870 continue 827 errors += 1
871 repo.copy(abs, myabsdest) 828 return
872 copied.append((abs, rel, exact)) 829 repo.copy(abssrc, abstarget)
873 if errs: 830 copied.append((abssrc, relsrc, exact))
831
832 pats = list(pats)
833 if not pats:
834 raise util.Abort(_('no source or destination specified'))
835 if len(pats) == 1:
836 raise util.Abort(_('no destination specified'))
837 dest = pats.pop()
838 destdirexists = os.path.isdir(dest)
839 if (len(pats) > 1 or not os.path.exists(pats[0])) and not destdirexists:
840 raise util.Abort(_('with multiple sources, destination must be an '
841 'existing directory'))
842
843 for pat in pats:
844 if os.path.isdir(pat):
845 if destdirexists:
846 striplen = len(os.path.split(pat)[0])
847 else:
848 striplen = len(pat)
849 if striplen:
850 striplen += len(os.sep)
851 targetpath = lambda p: os.path.join(dest, p[striplen:])
852 elif destdirexists:
853 targetpath = lambda p: os.path.join(dest, os.path.basename(p))
854 else:
855 targetpath = lambda p: dest
856 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
857 if okaytocopy(abssrc, relsrc, exact):
858 copy(abssrc, relsrc, targetpath(abssrc), exact)
859
860 if errors:
874 ui.warn(_('(consider using --after)\n')) 861 ui.warn(_('(consider using --after)\n'))
875 return errs, copied 862 if len(copied) == 0:
863 raise util.Abort(_('no files to copy'))
864 return errors, copied
876 865
877 def copy(ui, repo, *pats, **opts): 866 def copy(ui, repo, *pats, **opts):
878 """mark files as copied for the next commit 867 """mark files as copied for the next commit
879 868
880 Mark dest as having copies of source files. If dest is a 869 Mark dest as having copies of source files. If dest is a