##// END OF EJS Templates
generalize copy/rename to handle more than one source directory
Robin Farine -
r1512:53ad6ee6 default
parent child Browse files
Show More
@@ -0,0 +1,60 b''
1 #!/bin/sh
2
3 hg init
4 mkdir d1 d1/d11 d2
5 echo d1/a > d1/a
6 echo d1/ba > d1/ba
7 echo d1/a1 > d1/d11/a1
8 echo d1/b > d1/b
9 echo d2/b > d2/b
10 hg add d1/a d1/b d1/ba d1/d11/a1 d2/b
11 hg commit -m "1" -d "0 0"
12
13 echo "# rename a single file"
14 hg rename d1/d11/a1 d2/c
15 hg status
16 hg update -C
17
18 echo "# move a single file to an existing directory"
19 hg rename d1/d11/a1 d2
20 hg status
21 hg update -C
22
23 echo "# rename directory d1 as d3"
24 hg rename d1 d3
25 hg status
26 hg update -C
27
28 echo "# move directory d1/d11 to an existing directory d2 (removes empty d1)"
29 hg rename d1/d11 d2
30 hg status
31 hg update -C
32
33 echo "# move directories d1 and d2 to a new directory d3"
34 mkdir d3
35 hg rename d1 d2 d3
36 hg status
37 hg update -C
38
39 echo "# move everything under directory d1 to existing directory d2, do not"
40 echo "# overwrite existing files (d2/b)"
41 hg rename d1/* d2
42 hg status
43 diff d1/b d2/b
44 hg update -C
45
46 echo "# attempt to move potentially more than one file into a non-existent"
47 echo "# directory"
48 hg rename 'glob:d1/**' dx
49
50 echo "# move every file under d1 to d2/d21 (glob)"
51 mkdir d2/d21
52 hg rename 'glob:d1/**' d2/d21
53 hg status
54 hg update -C
55
56 echo "# move every file under d1 starting with an 'a' to d2/d21 (regexp)"
57 mkdir d2/d21
58 hg rename 're:d1/([^a][^/]*/)*a.*' d2/d21
59 hg status
60 hg update -C
@@ -0,0 +1,93 b''
1 # rename a single file
2 A d2/c
3 R d1/d11/a1
4 # move a single file to an existing directory
5 A d2/a1
6 R d1/d11/a1
7 # rename directory d1 as d3
8 copying d1/a to d3/a
9 copying d1/b to d3/b
10 copying d1/ba to d3/ba
11 copying d1/d11/a1 to d3/d11/a1
12 removing d1/a
13 removing d1/b
14 removing d1/ba
15 removing d1/d11/a1
16 A d3/a
17 A d3/b
18 A d3/ba
19 A d3/d11/a1
20 R d1/a
21 R d1/b
22 R d1/ba
23 R d1/d11/a1
24 # move directory d1/d11 to an existing directory d2 (removes empty d1)
25 copying d1/d11/a1 to d2/d11/a1
26 removing d1/d11/a1
27 A d2/d11/a1
28 R d1/d11/a1
29 # move directories d1 and d2 to a new directory d3
30 copying d1/a to d3/d1/a
31 copying d1/b to d3/d1/b
32 copying d1/ba to d3/d1/ba
33 copying d1/d11/a1 to d3/d1/d11/a1
34 copying d2/b to d3/d2/b
35 removing d1/a
36 removing d1/b
37 removing d1/ba
38 removing d1/d11/a1
39 removing d2/b
40 A d3/d1/a
41 A d3/d1/b
42 A d3/d1/ba
43 A d3/d1/d11/a1
44 A d3/d2/b
45 R d1/a
46 R d1/b
47 R d1/ba
48 R d1/d11/a1
49 R d2/b
50 # move everything under directory d1 to existing directory d2, do not
51 # overwrite existing files (d2/b)
52 d2/b: not overwriting - file already managed
53 copying d1/d11/a1 to d2/d11/a1
54 removing d1/d11/a1
55 A d2/a
56 A d2/ba
57 A d2/d11/a1
58 R d1/a
59 R d1/ba
60 R d1/d11/a1
61 1c1
62 < d1/b
63 ---
64 > d2/b
65 # attempt to move potentially more than one file into a non-existent
66 # directory
67 abort: with multiple sources, destination must be an existing directory
68 # move every file under d1 to d2/d21 (glob)
69 copying d1/a to d2/d21/a
70 copying d1/b to d2/d21/b
71 copying d1/ba to d2/d21/ba
72 copying d1/d11/a1 to d2/d21/a1
73 removing d1/a
74 removing d1/b
75 removing d1/ba
76 removing d1/d11/a1
77 A d2/d21/a
78 A d2/d21/a1
79 A d2/d21/b
80 A d2/d21/ba
81 R d1/a
82 R d1/b
83 R d1/ba
84 R d1/d11/a1
85 # move every file under d1 starting with an 'a' to d2/d21 (regexp)
86 copying d1/a to d2/d21/a
87 copying d1/d11/a1 to d2/d21/a1
88 removing d1/a
89 removing d1/d11/a1
90 A d2/d21/a
91 A d2/d21/a1
92 R d1/a
93 R d1/d11/a1
@@ -787,14 +787,9 b' def commit(ui, repo, *pats, **opts):'
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'),
@@ -805,74 +800,68 b' def docopy(ui, repo, pats, opts):'
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
General Comments 0
You need to be logged in to leave comments. Login now