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 |