##// END OF EJS Templates
right way to check if file was in renamed directory, fixes import monotone...
Pavel Volkovitskiy -
r7957:88a2687f default
parent child Browse files
Show More
@@ -0,0 +1,23
1 % tedious monotone keys configuration
2 % create monotone repository
3 mtn: adding dir1 to workspace manifest
4 mtn: adding dir1/subdir1 to workspace manifest
5 mtn: adding dir1/subdir1/file1 to workspace manifest
6 mtn: beginning commit on branch 'com.selenic.test'
7 mtn: committed revision 5ed13ff5582d8d1e319f079b694a37d2b45edfc8
8 % rename directory
9 mtn: skipping dir1, already accounted for in workspace
10 mtn: renaming dir1/subdir1 to dir1/subdir2 in workspace manifest
11 mtn: beginning commit on branch 'com.selenic.test'
12 mtn: committed revision 985204142a822b22ee86b509d61f3c5ab6857d2b
13 % convert
14 assuming destination repo.mtn-hg
15 initializing destination repo.mtn-hg repository
16 scanning source...
17 sorting...
18 converting...
19 1 initialize
20 0 rename
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 % manifest
23 dir1/subdir2/file1
@@ -1,201 +1,200
1 1 # monotone support for the convert extension
2 2
3 3 import os, re
4 4 from mercurial import util
5 5 from common import NoRepo, 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 29 self.delete_re = re.compile(space + "delete" + name)
30 30 self.tag_re = re.compile(space + "tag" + name + "revision" + revision)
31 31 self.cert_re = re.compile(lines + space + "name" + name + "value" + value)
32 32
33 33 attr = space + "file" + lines + space + "attr" + space
34 34 self.attr_execute_re = re.compile(attr + '"mtn:execute"' + space + '"true"')
35 35
36 36 # cached data
37 37 self.manifest_rev = None
38 38 self.manifest = None
39 39 self.files = None
40 40 self.dirs = None
41 41
42 42 norepo = NoRepo (_("%s does not look like a monotone repo") % path)
43 43 if not os.path.exists(path):
44 44 raise norepo
45 45
46 46 checktool('mtn', abort=False)
47 47
48 48 # test if there are any revisions
49 49 self.rev = None
50 50 try:
51 51 self.getheads()
52 52 except:
53 53 raise norepo
54 54 self.rev = rev
55 55
56 56 def mtnrun(self, *args, **kwargs):
57 57 kwargs['d'] = self.path
58 58 return self.run0('automate', *args, **kwargs)
59 59
60 60 def mtnloadmanifest(self, rev):
61 61 if self.manifest_rev == rev:
62 62 return
63 63 self.manifest = self.mtnrun("get_manifest_of", rev).split("\n\n")
64 64 self.manifest_rev = rev
65 65 self.files = {}
66 66 self.dirs = {}
67 67
68 68 for e in self.manifest:
69 69 m = self.file_re.match(e)
70 70 if m:
71 71 attr = ""
72 72 name = m.group(1)
73 73 node = m.group(2)
74 74 if self.attr_execute_re.match(e):
75 75 attr += "x"
76 76 self.files[name] = (node, attr)
77 77 m = self.dir_re.match(e)
78 78 if m:
79 79 self.dirs[m.group(1)] = True
80 80
81 81 def mtnisfile(self, name, rev):
82 82 # a non-file could be a directory or a deleted or renamed file
83 83 self.mtnloadmanifest(rev)
84 84 try:
85 85 self.files[name]
86 86 return True
87 87 except KeyError:
88 88 return False
89 89
90 90 def mtnisdir(self, name, rev):
91 91 self.mtnloadmanifest(rev)
92 92 try:
93 93 self.dirs[name]
94 94 return True
95 95 except KeyError:
96 96 return False
97 97
98 98 def mtngetcerts(self, rev):
99 99 certs = {"author":"<missing>", "date":"<missing>",
100 100 "changelog":"<missing>", "branch":"<missing>"}
101 101 cert_list = self.mtnrun("certs", rev).split('\n\n key "')
102 102 for e in cert_list:
103 103 m = self.cert_re.match(e)
104 104 if m:
105 105 name, value = m.groups()
106 106 value = value.replace(r'\"', '"')
107 107 value = value.replace(r'\\', '\\')
108 108 certs[name] = value
109 109 return certs
110 110
111 111 def mtnrenamefiles(self, files, fromdir, todir):
112 112 renamed = {}
113 113 for tofile in files:
114 suffix = tofile.lstrip(todir)
115 if todir + suffix == tofile:
116 renamed[tofile] = (fromdir + suffix).lstrip("/")
114 if tofile.startswith(todir):
115 renamed[tofile] = fromdir + tofile[len(todir):]
117 116 return renamed
118 117
119 118
120 119 # implement the converter_source interface:
121 120
122 121 def getheads(self):
123 122 if not self.rev:
124 123 return self.mtnrun("leaves").splitlines()
125 124 else:
126 125 return [self.rev]
127 126
128 127 def getchanges(self, rev):
129 128 #revision = self.mtncmd("get_revision %s" % rev).split("\n\n")
130 129 revision = self.mtnrun("get_revision", rev).split("\n\n")
131 130 files = {}
132 131 copies = {}
133 132 for e in revision:
134 133 m = self.add_file_re.match(e)
135 134 if m:
136 135 files[m.group(1)] = rev
137 136 m = self.patch_re.match(e)
138 137 if m:
139 138 files[m.group(1)] = rev
140 139
141 140 # Delete/rename is handled later when the convert engine
142 141 # discovers an IOError exception from getfile,
143 142 # but only if we add the "from" file to the list of changes.
144 143 m = self.delete_re.match(e)
145 144 if m:
146 145 files[m.group(1)] = rev
147 146 m = self.rename_re.match(e)
148 147 if m:
149 148 toname = m.group(2)
150 149 fromname = m.group(1)
151 150 if self.mtnisfile(toname, rev):
152 151 copies[toname] = fromname
153 152 files[toname] = rev
154 153 files[fromname] = rev
155 154 if self.mtnisdir(toname, rev):
156 155 renamed = self.mtnrenamefiles(self.files, fromname, toname)
157 156 for tofile, fromfile in renamed.items():
158 157 self.ui.debug (_("copying file in renamed dir from '%s' to '%s'") % (fromfile, tofile), '\n')
159 158 files[tofile] = rev
160 159 for fromfile in renamed.values():
161 160 files[fromfile] = rev
162 161 return (files.items(), copies)
163 162
164 163 def getmode(self, name, rev):
165 164 self.mtnloadmanifest(rev)
166 165 try:
167 166 node, attr = self.files[name]
168 167 return attr
169 168 except KeyError:
170 169 return ""
171 170
172 171 def getfile(self, name, rev):
173 172 if not self.mtnisfile(name, rev):
174 173 raise IOError() # file was deleted or renamed
175 174 try:
176 175 return self.mtnrun("get_file_of", name, r=rev)
177 176 except:
178 177 raise IOError() # file was deleted or renamed
179 178
180 179 def getcommit(self, rev):
181 180 certs = self.mtngetcerts(rev)
182 181 return commit(
183 182 author=certs["author"],
184 183 date=util.datestr(util.strdate(certs["date"], "%Y-%m-%dT%H:%M:%S")),
185 184 desc=certs["changelog"],
186 185 rev=rev,
187 186 parents=self.mtnrun("parents", rev).splitlines(),
188 187 branch=certs["branch"])
189 188
190 189 def gettags(self):
191 190 tags = {}
192 191 for e in self.mtnrun("tags").split("\n\n"):
193 192 m = self.tag_re.match(e)
194 193 if m:
195 194 tags[m.group(1)] = m.group(2)
196 195 return tags
197 196
198 197 def getchangedfiles(self, rev, i):
199 198 # This function is only needed to support --filemap
200 199 # ... and we don't support that
201 200 raise NotImplementedError()
General Comments 0
You need to be logged in to leave comments. Login now