##// END OF EJS Templates
convert/mtn: record changes from directory renames (issue1587)...
Patrick Mezard -
r8050:087cc65b default
parent child Browse files
Show More
@@ -1,201 +1,200
1 # monotone support for the convert extension
1 # monotone support for the convert extension
2
2
3 import os, re, time
3 import os, re, time
4 from mercurial import util
4 from mercurial import util
5 from common import NoRepo, MissingTool, commit, converter_source, checktool
5 from common import NoRepo, MissingTool, commit, converter_source, checktool
6 from common import commandline
6 from common import commandline
7 from mercurial.i18n import _
7 from mercurial.i18n import _
8
8
9 class monotone_source(converter_source, commandline):
9 class monotone_source(converter_source, commandline):
10 def __init__(self, ui, path=None, rev=None):
10 def __init__(self, ui, path=None, rev=None):
11 converter_source.__init__(self, ui, path, rev)
11 converter_source.__init__(self, ui, path, rev)
12 commandline.__init__(self, ui, 'mtn')
12 commandline.__init__(self, ui, 'mtn')
13
13
14 self.ui = ui
14 self.ui = ui
15 self.path = path
15 self.path = path
16
16
17 # regular expressions for parsing monotone output
17 # regular expressions for parsing monotone output
18 space = r'\s*'
18 space = r'\s*'
19 name = r'\s+"((?:\\"|[^"])*)"\s*'
19 name = r'\s+"((?:\\"|[^"])*)"\s*'
20 value = name
20 value = name
21 revision = r'\s+\[(\w+)\]\s*'
21 revision = r'\s+\[(\w+)\]\s*'
22 lines = r'(?:.|\n)+'
22 lines = r'(?:.|\n)+'
23
23
24 self.dir_re = re.compile(space + "dir" + name)
24 self.dir_re = re.compile(space + "dir" + name)
25 self.file_re = re.compile(space + "file" + name + "content" + revision)
25 self.file_re = re.compile(space + "file" + name + "content" + revision)
26 self.add_file_re = re.compile(space + "add_file" + name + "content" + revision)
26 self.add_file_re = re.compile(space + "add_file" + name + "content" + revision)
27 self.patch_re = re.compile(space + "patch" + name + "from" + revision + "to" + revision)
27 self.patch_re = re.compile(space + "patch" + name + "from" + revision + "to" + revision)
28 self.rename_re = re.compile(space + "rename" + name + "to" + name)
28 self.rename_re = re.compile(space + "rename" + name + "to" + name)
29 self.delete_re = re.compile(space + "delete" + name)
29 self.delete_re = re.compile(space + "delete" + name)
30 self.tag_re = re.compile(space + "tag" + name + "revision" + revision)
30 self.tag_re = re.compile(space + "tag" + name + "revision" + revision)
31 self.cert_re = re.compile(lines + space + "name" + name + "value" + value)
31 self.cert_re = re.compile(lines + space + "name" + name + "value" + value)
32
32
33 attr = space + "file" + lines + space + "attr" + space
33 attr = space + "file" + lines + space + "attr" + space
34 self.attr_execute_re = re.compile(attr + '"mtn:execute"' + space + '"true"')
34 self.attr_execute_re = re.compile(attr + '"mtn:execute"' + space + '"true"')
35
35
36 # cached data
36 # cached data
37 self.manifest_rev = None
37 self.manifest_rev = None
38 self.manifest = None
38 self.manifest = None
39 self.files = None
39 self.files = None
40 self.dirs = None
40 self.dirs = None
41
41
42 norepo = NoRepo (_("%s does not look like a monotone repo") % path)
42 norepo = NoRepo (_("%s does not look like a monotone repo") % path)
43 if not os.path.exists(path):
43 if not os.path.exists(path):
44 raise norepo
44 raise norepo
45
45
46 checktool('mtn', abort=False)
46 checktool('mtn', abort=False)
47
47
48 # test if there are any revisions
48 # test if there are any revisions
49 self.rev = None
49 self.rev = None
50 try:
50 try:
51 self.getheads()
51 self.getheads()
52 except:
52 except:
53 raise norepo
53 raise norepo
54 self.rev = rev
54 self.rev = rev
55
55
56 def mtnrun(self, *args, **kwargs):
56 def mtnrun(self, *args, **kwargs):
57 kwargs['d'] = self.path
57 kwargs['d'] = self.path
58 return self.run0('automate', *args, **kwargs)
58 return self.run0('automate', *args, **kwargs)
59
59
60 def mtnloadmanifest(self, rev):
60 def mtnloadmanifest(self, rev):
61 if self.manifest_rev == rev:
61 if self.manifest_rev == rev:
62 return
62 return
63 self.manifest = self.mtnrun("get_manifest_of", rev).split("\n\n")
63 self.manifest = self.mtnrun("get_manifest_of", rev).split("\n\n")
64 self.manifest_rev = rev
64 self.manifest_rev = rev
65 self.files = {}
65 self.files = {}
66 self.dirs = {}
66 self.dirs = {}
67
67
68 for e in self.manifest:
68 for e in self.manifest:
69 m = self.file_re.match(e)
69 m = self.file_re.match(e)
70 if m:
70 if m:
71 attr = ""
71 attr = ""
72 name = m.group(1)
72 name = m.group(1)
73 node = m.group(2)
73 node = m.group(2)
74 if self.attr_execute_re.match(e):
74 if self.attr_execute_re.match(e):
75 attr += "x"
75 attr += "x"
76 self.files[name] = (node, attr)
76 self.files[name] = (node, attr)
77 m = self.dir_re.match(e)
77 m = self.dir_re.match(e)
78 if m:
78 if m:
79 self.dirs[m.group(1)] = True
79 self.dirs[m.group(1)] = True
80
80
81 def mtnisfile(self, name, rev):
81 def mtnisfile(self, name, rev):
82 # a non-file could be a directory or a deleted or renamed file
82 # a non-file could be a directory or a deleted or renamed file
83 self.mtnloadmanifest(rev)
83 self.mtnloadmanifest(rev)
84 try:
84 try:
85 self.files[name]
85 self.files[name]
86 return True
86 return True
87 except KeyError:
87 except KeyError:
88 return False
88 return False
89
89
90 def mtnisdir(self, name, rev):
90 def mtnisdir(self, name, rev):
91 self.mtnloadmanifest(rev)
91 self.mtnloadmanifest(rev)
92 try:
92 try:
93 self.dirs[name]
93 self.dirs[name]
94 return True
94 return True
95 except KeyError:
95 except KeyError:
96 return False
96 return False
97
97
98 def mtngetcerts(self, rev):
98 def mtngetcerts(self, rev):
99 certs = {"author":"<missing>", "date":"<missing>",
99 certs = {"author":"<missing>", "date":"<missing>",
100 "changelog":"<missing>", "branch":"<missing>"}
100 "changelog":"<missing>", "branch":"<missing>"}
101 cert_list = self.mtnrun("certs", rev).split('\n\n key "')
101 cert_list = self.mtnrun("certs", rev).split('\n\n key "')
102 for e in cert_list:
102 for e in cert_list:
103 m = self.cert_re.match(e)
103 m = self.cert_re.match(e)
104 if m:
104 if m:
105 name, value = m.groups()
105 name, value = m.groups()
106 value = value.replace(r'\"', '"')
106 value = value.replace(r'\"', '"')
107 value = value.replace(r'\\', '\\')
107 value = value.replace(r'\\', '\\')
108 certs[name] = value
108 certs[name] = value
109 return certs
109 return certs
110
110
111 def mtnrenamefiles(self, files, fromdir, todir):
111 def mtnrenamefiles(self, files, fromdir, todir):
112 renamed = {}
112 renamed = {}
113 for tofile in files:
113 for tofile in files:
114 suffix = tofile.lstrip(todir)
114 if tofile.startswith(todir + '/'):
115 if todir + suffix == tofile:
115 renamed[tofile] = fromdir + tofile[len(todir):]
116 renamed[tofile] = (fromdir + suffix).lstrip("/")
117 return renamed
116 return renamed
118
117
119
120 # implement the converter_source interface:
118 # implement the converter_source interface:
121
119
122 def getheads(self):
120 def getheads(self):
123 if not self.rev:
121 if not self.rev:
124 return self.mtnrun("leaves").splitlines()
122 return self.mtnrun("leaves").splitlines()
125 else:
123 else:
126 return [self.rev]
124 return [self.rev]
127
125
128 def getchanges(self, rev):
126 def getchanges(self, rev):
129 #revision = self.mtncmd("get_revision %s" % rev).split("\n\n")
127 #revision = self.mtncmd("get_revision %s" % rev).split("\n\n")
130 revision = self.mtnrun("get_revision", rev).split("\n\n")
128 revision = self.mtnrun("get_revision", rev).split("\n\n")
131 files = {}
129 files = {}
132 copies = {}
130 copies = {}
133 for e in revision:
131 for e in revision:
134 m = self.add_file_re.match(e)
132 m = self.add_file_re.match(e)
135 if m:
133 if m:
136 files[m.group(1)] = rev
134 files[m.group(1)] = rev
137 m = self.patch_re.match(e)
135 m = self.patch_re.match(e)
138 if m:
136 if m:
139 files[m.group(1)] = rev
137 files[m.group(1)] = rev
140
138
141 # Delete/rename is handled later when the convert engine
139 # Delete/rename is handled later when the convert engine
142 # discovers an IOError exception from getfile,
140 # discovers an IOError exception from getfile,
143 # but only if we add the "from" file to the list of changes.
141 # but only if we add the "from" file to the list of changes.
144 m = self.delete_re.match(e)
142 m = self.delete_re.match(e)
145 if m:
143 if m:
146 files[m.group(1)] = rev
144 files[m.group(1)] = rev
147 m = self.rename_re.match(e)
145 m = self.rename_re.match(e)
148 if m:
146 if m:
149 toname = m.group(2)
147 toname = m.group(2)
150 fromname = m.group(1)
148 fromname = m.group(1)
151 if self.mtnisfile(toname, rev):
149 if self.mtnisfile(toname, rev):
152 copies[toname] = fromname
150 copies[toname] = fromname
153 files[toname] = rev
151 files[toname] = rev
154 files[fromname] = rev
152 files[fromname] = rev
155 if self.mtnisdir(toname, rev):
153 if self.mtnisdir(toname, rev):
156 renamed = self.mtnrenamefiles(self.files, fromname, toname)
154 renamed = self.mtnrenamefiles(self.files, fromname, toname)
157 for tofile, fromfile in renamed.items():
155 for tofile, fromfile in renamed.items():
158 self.ui.debug (_("copying file in renamed dir from '%s' to '%s'") % (fromfile, tofile), '\n')
156 self.ui.debug (_("copying file in renamed dir from '%s' to '%s'") % (fromfile, tofile), '\n')
159 files[tofile] = rev
157 files[tofile] = rev
158 copies[tofile] = fromfile
160 for fromfile in renamed.values():
159 for fromfile in renamed.values():
161 files[fromfile] = rev
160 files[fromfile] = rev
162 return (files.items(), copies)
161 return (files.items(), copies)
163
162
164 def getmode(self, name, rev):
163 def getmode(self, name, rev):
165 self.mtnloadmanifest(rev)
164 self.mtnloadmanifest(rev)
166 try:
165 try:
167 node, attr = self.files[name]
166 node, attr = self.files[name]
168 return attr
167 return attr
169 except KeyError:
168 except KeyError:
170 return ""
169 return ""
171
170
172 def getfile(self, name, rev):
171 def getfile(self, name, rev):
173 if not self.mtnisfile(name, rev):
172 if not self.mtnisfile(name, rev):
174 raise IOError() # file was deleted or renamed
173 raise IOError() # file was deleted or renamed
175 try:
174 try:
176 return self.mtnrun("get_file_of", name, r=rev)
175 return self.mtnrun("get_file_of", name, r=rev)
177 except:
176 except:
178 raise IOError() # file was deleted or renamed
177 raise IOError() # file was deleted or renamed
179
178
180 def getcommit(self, rev):
179 def getcommit(self, rev):
181 certs = self.mtngetcerts(rev)
180 certs = self.mtngetcerts(rev)
182 return commit(
181 return commit(
183 author=certs["author"],
182 author=certs["author"],
184 date=util.datestr(util.strdate(certs["date"], "%Y-%m-%dT%H:%M:%S")),
183 date=util.datestr(util.strdate(certs["date"], "%Y-%m-%dT%H:%M:%S")),
185 desc=certs["changelog"],
184 desc=certs["changelog"],
186 rev=rev,
185 rev=rev,
187 parents=self.mtnrun("parents", rev).splitlines(),
186 parents=self.mtnrun("parents", rev).splitlines(),
188 branch=certs["branch"])
187 branch=certs["branch"])
189
188
190 def gettags(self):
189 def gettags(self):
191 tags = {}
190 tags = {}
192 for e in self.mtnrun("tags").split("\n\n"):
191 for e in self.mtnrun("tags").split("\n\n"):
193 m = self.tag_re.match(e)
192 m = self.tag_re.match(e)
194 if m:
193 if m:
195 tags[m.group(1)] = m.group(2)
194 tags[m.group(1)] = m.group(2)
196 return tags
195 return tags
197
196
198 def getchangedfiles(self, rev, i):
197 def getchangedfiles(self, rev, i):
199 # This function is only needed to support --filemap
198 # This function is only needed to support --filemap
200 # ... and we don't support that
199 # ... and we don't support that
201 raise NotImplementedError()
200 raise NotImplementedError()
@@ -1,89 +1,106
1 #!/bin/sh
1 #!/bin/sh
2
2
3 "$TESTDIR/hghave" mtn || exit 80
3 "$TESTDIR/hghave" mtn || exit 80
4
4
5 # Monotone directory is called .monotone on *nix and monotone
5 # Monotone directory is called .monotone on *nix and monotone
6 # on Windows. Having a variable here ease test patching.
6 # on Windows. Having a variable here ease test patching.
7 mtndir=.monotone
7 mtndir=.monotone
8 echo "[extensions]" >> $HGRCPATH
8 echo "[extensions]" >> $HGRCPATH
9 echo "convert=" >> $HGRCPATH
9 echo "convert=" >> $HGRCPATH
10 echo 'hgext.graphlog =' >> $HGRCPATH
10 echo 'hgext.graphlog =' >> $HGRCPATH
11
11
12 HOME=`pwd`/do_not_use_HOME_mtn; export HOME
12 HOME=`pwd`/do_not_use_HOME_mtn; export HOME
13 # Windows version of monotone home
13 # Windows version of monotone home
14 APPDATA=$HOME; export APPDATA
14 APPDATA=$HOME; export APPDATA
15
15
16 echo % tedious monotone keys configuration
16 echo % tedious monotone keys configuration
17 # The /dev/null redirection is necessary under Windows, or
17 # The /dev/null redirection is necessary under Windows, or
18 # it complains about home directory permissions
18 # it complains about home directory permissions
19 mtn --quiet genkey test@selenic.com 1>/dev/null 2>&1 <<EOF
19 mtn --quiet genkey test@selenic.com 1>/dev/null 2>&1 <<EOF
20 passphrase
20 passphrase
21 passphrase
21 passphrase
22 EOF
22 EOF
23 cat >> $HOME/$mtndir/monotonerc <<EOF
23 cat >> $HOME/$mtndir/monotonerc <<EOF
24 function get_passphrase(keypair_id)
24 function get_passphrase(keypair_id)
25 return "passphrase"
25 return "passphrase"
26 end
26 end
27 EOF
27 EOF
28
28
29 echo % create monotone repository
29 echo % create monotone repository
30 mtn db init --db=repo.mtn
30 mtn db init --db=repo.mtn
31 mtn --db=repo.mtn --branch=com.selenic.test setup workingdir
31 mtn --db=repo.mtn --branch=com.selenic.test setup workingdir
32 cd workingdir
32 cd workingdir
33 echo a > a
33 echo a > a
34 mkdir dir
34 mkdir dir
35 echo b > dir/b
35 echo b > dir/b
36 python -c 'file("bin", "wb").write("a\\x00b")'
36 python -c 'file("bin", "wb").write("a\\x00b")'
37 echo c > c
37 echo c > c
38 mtn add a dir/b c bin
38 mtn add a dir/b c bin
39 mtn ci -m initialize
39 mtn ci -m initialize
40 echo % update monotone working directory
40 echo % update monotone working directory
41 mtn mv a dir/a
41 mtn mv a dir/a
42 echo a >> dir/a
42 echo a >> dir/a
43 echo b >> dir/b
43 echo b >> dir/b
44 mtn drop c
44 mtn drop c
45 python -c 'file("bin", "wb").write("b\\x00c")'
45 python -c 'file("bin", "wb").write("b\\x00c")'
46 mtn ci -m update1
46 mtn ci -m update1
47 cd ..
47 cd ..
48
48
49 echo % convert once
49 echo % convert once
50 hg convert -s mtn repo.mtn
50 hg convert -s mtn repo.mtn
51
51
52 cd workingdir
52 cd workingdir
53 echo e > e
53 echo e > e
54 mtn add e
54 mtn add e
55 mtn drop dir/b
55 mtn drop dir/b
56 mtn mv bin bin2
56 mtn mv bin bin2
57 mtn ci -m 'update2 "with" quotes'
57 mtn ci -m 'update2 "with" quotes'
58 # Test directory move
58 echo '% test directory move'
59 mkdir -p dir1/subdir1
60 mkdir -p dir1/subdir2_other
61 echo file1 > dir1/subdir1/file1
62 echo file2 > dir1/subdir2_other/file1
63 mtn add dir1/subdir1/file1 dir1/subdir2_other/file1
64 mtn ci -m createdir1
65 mtn rename dir1/subdir1 dir1/subdir2
66 mtn ci -m movedir1
67 echo '% test subdirectory move'
59 mtn mv dir dir2
68 mtn mv dir dir2
60 mtn ci -m movedir
69 mtn ci -m movedir
61 # Test directory removal with empty directory
70 # Test directory removal with empty directory
62 mkdir dir2/dir
71 mkdir dir2/dir
63 mkdir dir2/dir/subdir
72 mkdir dir2/dir/subdir
64 echo f > dir2/dir/subdir/f
73 echo f > dir2/dir/subdir/f
65 mkdir dir2/dir/emptydir
74 mkdir dir2/dir/emptydir
66 mtn add --quiet -R dir2/dir
75 mtn add --quiet -R dir2/dir
67 mtn ci -m emptydir
76 mtn ci -m emptydir
68 mtn drop -R dir2/dir
77 mtn drop -R dir2/dir
69 mtn ci -m dropdirectory
78 mtn ci -m dropdirectory
70 cd ..
79 cd ..
71
80
72 echo % convert incrementally
81 echo % convert incrementally
73 hg convert -s mtn repo.mtn
82 hg convert -s mtn repo.mtn
74
83
75 glog()
84 glog()
76 {
85 {
77 hg glog --template '#rev# "#desc|firstline#" files: #files#\n' "$@"
86 hg glog --template '#rev# "#desc|firstline#" files: #files#\n' "$@"
78 }
87 }
79
88
80 cd repo.mtn-hg
89 cd repo.mtn-hg
81 hg up -C
90 hg up -C
82 glog
91 glog
83 echo % manifest
92 echo % manifest
84 hg manifest
93 hg manifest
85 echo % contents
94 echo % contents
86 cat dir2/a
95 cat dir2/a
87 test -d dir2/dir && echo 'removed dir2/dir is still there!'
96 test -d dir2/dir && echo 'removed dir2/dir is still there!'
97
98 echo % file move
99 hg log -v -C -r 1 | grep copies
100 echo % check directory move
101 hg manifest -r 4
102 test -d dir1/subdir2 || echo 'new dir1/subdir2 does not exist!'
103 test -d dir1/subdir1 && echo 'renamed dir1/subdir1 is still there!'
104 hg log -v -C -r 4 | grep copies
88 exit 0
105 exit 0
89
106
@@ -1,68 +1,98
1 % tedious monotone keys configuration
1 % tedious monotone keys configuration
2 % create monotone repository
2 % create monotone repository
3 mtn: adding a to workspace manifest
3 mtn: adding a to workspace manifest
4 mtn: adding bin to workspace manifest
4 mtn: adding bin to workspace manifest
5 mtn: adding c to workspace manifest
5 mtn: adding c to workspace manifest
6 mtn: adding dir to workspace manifest
6 mtn: adding dir to workspace manifest
7 mtn: adding dir/b to workspace manifest
7 mtn: adding dir/b to workspace manifest
8 mtn: beginning commit on branch 'com.selenic.test'
8 mtn: beginning commit on branch 'com.selenic.test'
9 mtn: committed revision 803ef0bf815e35b951dbd4310acd1e45e675016e
9 mtn: committed revision 803ef0bf815e35b951dbd4310acd1e45e675016e
10 % update monotone working directory
10 % update monotone working directory
11 mtn: skipping dir, already accounted for in workspace
11 mtn: skipping dir, already accounted for in workspace
12 mtn: renaming a to dir/a in workspace manifest
12 mtn: renaming a to dir/a in workspace manifest
13 mtn: dropping c from workspace manifest
13 mtn: dropping c from workspace manifest
14 mtn: beginning commit on branch 'com.selenic.test'
14 mtn: beginning commit on branch 'com.selenic.test'
15 mtn: committed revision 4daf60753d6fe21a06ce5f716303fe55fd6d3a56
15 mtn: committed revision 4daf60753d6fe21a06ce5f716303fe55fd6d3a56
16 % convert once
16 % convert once
17 assuming destination repo.mtn-hg
17 assuming destination repo.mtn-hg
18 initializing destination repo.mtn-hg repository
18 initializing destination repo.mtn-hg repository
19 scanning source...
19 scanning source...
20 sorting...
20 sorting...
21 converting...
21 converting...
22 1 initialize
22 1 initialize
23 0 update1
23 0 update1
24 mtn: adding e to workspace manifest
24 mtn: adding e to workspace manifest
25 mtn: dropping dir/b from workspace manifest
25 mtn: dropping dir/b from workspace manifest
26 mtn: renaming bin to bin2 in workspace manifest
26 mtn: renaming bin to bin2 in workspace manifest
27 mtn: beginning commit on branch 'com.selenic.test'
27 mtn: beginning commit on branch 'com.selenic.test'
28 mtn: committed revision 6c6977a6ef609ec80e40779f89dbd2772c96de62
28 mtn: committed revision 6c6977a6ef609ec80e40779f89dbd2772c96de62
29 % test directory move
30 mtn: adding dir1 to workspace manifest
31 mtn: adding dir1/subdir1 to workspace manifest
32 mtn: adding dir1/subdir1/file1 to workspace manifest
33 mtn: adding dir1/subdir2_other to workspace manifest
34 mtn: adding dir1/subdir2_other/file1 to workspace manifest
35 mtn: beginning commit on branch 'com.selenic.test'
36 mtn: committed revision e066b1feb2b7a7110450c2c18b5b4462011427d1
37 mtn: skipping dir1, already accounted for in workspace
38 mtn: renaming dir1/subdir1 to dir1/subdir2 in workspace manifest
39 mtn: beginning commit on branch 'com.selenic.test'
40 mtn: committed revision 2ad2409d25bb8d2583b57a3d4c0fa1df62aa1f79
41 % test subdirectory move
29 mtn: renaming dir to dir2 in workspace manifest
42 mtn: renaming dir to dir2 in workspace manifest
30 mtn: beginning commit on branch 'com.selenic.test'
43 mtn: beginning commit on branch 'com.selenic.test'
31 mtn: committed revision 5de5abe7c15eae70cf3acdda23c9c319ea50c1af
44 mtn: committed revision a85290b81fc4a8fbce4dc4d956404109842b406e
32 mtn: beginning commit on branch 'com.selenic.test'
45 mtn: beginning commit on branch 'com.selenic.test'
33 mtn: committed revision 27a423be1e406595cc57f50f42a8790fa0a93d8e
46 mtn: committed revision 7e3c8746060117104f16ff2d9212cf0f810cbff0
34 mtn: dropping dir2/dir/subdir/f from workspace manifest
47 mtn: dropping dir2/dir/subdir/f from workspace manifest
35 mtn: dropping dir2/dir/subdir from workspace manifest
48 mtn: dropping dir2/dir/subdir from workspace manifest
36 mtn: dropping dir2/dir/emptydir from workspace manifest
49 mtn: dropping dir2/dir/emptydir from workspace manifest
37 mtn: dropping dir2/dir from workspace manifest
50 mtn: dropping dir2/dir from workspace manifest
38 mtn: beginning commit on branch 'com.selenic.test'
51 mtn: beginning commit on branch 'com.selenic.test'
39 mtn: committed revision ba57ba5ac63178529d37fa8a2a1a012fc0e42047
52 mtn: committed revision a97e0433d041a6d253c5dc27e080d544e55d9c19
40 % convert incrementally
53 % convert incrementally
41 assuming destination repo.mtn-hg
54 assuming destination repo.mtn-hg
42 scanning source...
55 scanning source...
43 sorting...
56 sorting...
44 converting...
57 converting...
45 3 update2 "with" quotes
58 5 update2 "with" quotes
59 4 createdir1
60 3 movedir1
46 2 movedir
61 2 movedir
47 1 emptydir
62 1 emptydir
48 0 dropdirectory
63 0 dropdirectory
49 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 @ 5 "dropdirectory" files: dir2/dir/subdir/f
65 @ 7 "dropdirectory" files: dir2/dir/subdir/f
66 |
67 o 6 "emptydir" files: dir2/dir/subdir/f
51 |
68 |
52 o 4 "emptydir" files: dir2/dir/subdir/f
69 o 5 "movedir" files: dir/a dir2/a
53 |
70 |
54 o 3 "movedir" files: dir/a dir2/a
71 o 4 "movedir1" files: dir1/subdir1/file1 dir1/subdir2/file1
72 |
73 o 3 "createdir1" files: dir1/subdir1/file1 dir1/subdir2_other/file1
55 |
74 |
56 o 2 "update2 "with" quotes" files: bin bin2 dir/b e
75 o 2 "update2 "with" quotes" files: bin bin2 dir/b e
57 |
76 |
58 o 1 "update1" files: a bin c dir/a dir/b
77 o 1 "update1" files: a bin c dir/a dir/b
59 |
78 |
60 o 0 "initialize" files: a bin c dir/b
79 o 0 "initialize" files: a bin c dir/b
61
80
62 % manifest
81 % manifest
63 bin2
82 bin2
83 dir1/subdir2/file1
84 dir1/subdir2_other/file1
64 dir2/a
85 dir2/a
65 e
86 e
66 % contents
87 % contents
67 a
88 a
68 a
89 a
90 % file move
91 copies: dir/a (a)
92 % check directory move
93 bin2
94 dir/a
95 dir1/subdir2/file1
96 dir1/subdir2_other/file1
97 e
98 copies: dir1/subdir2/file1 (dir1/subdir1/file1)
General Comments 0
You need to be logged in to leave comments. Login now