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