comparison hgext/convert/monotone.py @ 6307:6840668e3bf6

cleanup monotone conversion and use commandline class
author Mikkel Fahnøe Jørgensen <mikkel@dvide.com>
date Sun, 03 Feb 2008 16:14:05 +0100
parents 2f9de4aaea9e
children 950e72fc7cf3
comparison
equal deleted inserted replaced
6306:2f9de4aaea9e 6307:6840668e3bf6
1 # monotone support for the convert extension 1 # monotone support for the convert extension
2 2
3 import os 3 import os, re, time
4 import re
5 import time
6 from mercurial import util 4 from mercurial import util
5 from common import NoRepo, commit, converter_source, checktool, commandline
6 from mercurial.i18n import _
7 7
8 from common import NoRepo, commit, converter_source, checktool 8 class monotone_source(converter_source, commandline):
9
10 class monotone_source(converter_source):
11 def __init__(self, ui, path=None, rev=None): 9 def __init__(self, ui, path=None, rev=None):
12 converter_source.__init__(self, ui, path, rev) 10 converter_source.__init__(self, ui, path, rev)
13 11 commandline.__init__(self, ui, 'mtn')
12
14 self.ui = ui 13 self.ui = ui
15 self.path = path 14 self.path = path
16 15
17
18 # regular expressions for parsing monotone output 16 # regular expressions for parsing monotone output
19
20 space = r'\s*' 17 space = r'\s*'
21 name = r'\s+"((?:[^"]|\\")*)"\s*' 18 name = r'\s+"((?:[^"]|\\")*)"\s*'
22 value = name 19 value = name
23 revision = r'\s+\[(\w+)\]\s*' 20 revision = r'\s+\[(\w+)\]\s*'
24 lines = r'(?:.|\n)+' 21 lines = r'(?:.|\n)+'
25 22
26 self.dir_re = re.compile(space + "dir" + name) 23 self.dir_re = re.compile(space + "dir" + name)
27 self.file_re = re.compile(space + "file" + name + "content" + revision) 24 self.file_re = re.compile(space + "file" + name + "content" + revision)
28 self.add_file_re = re.compile(space + "add_file" + name + "content" + revision) 25 self.add_file_re = re.compile(space + "add_file" + name + "content" + revision)
29 self.patch_re = re.compile(space + "patch" + name + "from" + revision + "to" + revision) 26 self.patch_re = re.compile(space + "patch" + name + "from" + revision + "to" + revision)
30 self.rename_re = re.compile(space + "rename" + name + "to" + name) 27 self.rename_re = re.compile(space + "rename" + name + "to" + name)
31 self.tag_re = re.compile(space + "tag" + name + "revision" + revision) 28 self.tag_re = re.compile(space + "tag" + name + "revision" + revision)
32 self.cert_re = re.compile(lines + space + "name" + name + "value" + value) 29 self.cert_re = re.compile(lines + space + "name" + name + "value" + value)
33 30
34 attr = space + "file" + lines + space + "attr" + space 31 attr = space + "file" + lines + space + "attr" + space
35 self.attr_execute_re = re.compile(attr + '"mtn:execute"' + space + '"true"') 32 self.attr_execute_re = re.compile(attr + '"mtn:execute"' + space + '"true"')
36 33
37 # cached data 34 # cached data
38
39 self.manifest_rev = None 35 self.manifest_rev = None
40 self.manifest = None 36 self.manifest = None
41 self.files = None 37 self.files = None
42 self.dirs = None 38 self.dirs = None
43 39
44 norepo = NoRepo("%s does not look like a monotone repo" % path) 40 norepo = NoRepo (_("%s does not look like a monotone repo") % path)
45 if not os.path.exists(path): 41 if not os.path.exists(path):
46 raise norepo 42 raise norepo
47 43
48 checktool('mtn') 44 checktool('mtn')
49 45
50 # test if there are are any revisions 46 # test if there are any revisions
51 self.rev = None 47 self.rev = None
52 try : 48 try:
53 self.getheads() 49 self.getheads()
54 except : 50 except:
55 raise norepo 51 raise norepo
56
57 self.rev = rev 52 self.rev = rev
58 53
59 54 def mtnrun(self, *args, **kwargs):
60 def mtncmd(self, arg): 55 kwargs['d'] = self.path
61 cmdline = "mtn -d %s automate %s" % (util.shellquote(self.path), arg) 56 return self.run0('automate', *args, **kwargs)
62 self.ui.debug(cmdline, '\n') 57
63 p = util.popen(cmdline)
64 result = p.read()
65 if p.close():
66 raise IOError()
67 return result
68
69 def mtnloadmanifest(self, rev): 58 def mtnloadmanifest(self, rev):
70 if self.manifest_rev == rev: 59 if self.manifest_rev == rev:
71 return 60 return
61 self.manifest = self.mtnrun("get_manifest_of", rev).split("\n\n")
72 self.manifest_rev = rev 62 self.manifest_rev = rev
73 self.manifest = self.mtncmd("get_manifest_of %s" % rev).split("\n\n") 63 self.files = {}
74 64 self.dirs = {}
75 manifest = self.manifest
76 files = {}
77 dirs = {}
78 65
79 for e in manifest: 66 for e in self.manifest:
80 m = self.file_re.match(e) 67 m = self.file_re.match(e)
81 if m: 68 if m:
82 attr = "" 69 attr = ""
83 name = m.group(1) 70 name = m.group(1)
84 node = m.group(2) 71 node = m.group(2)
85 if self.attr_execute_re.match(e): 72 if self.attr_execute_re.match(e):
86 attr += "x" 73 attr += "x"
87 files[name] = (node, attr) 74 self.files[name] = (node, attr)
88 m = self.dir_re.match(e) 75 m = self.dir_re.match(e)
89 if m: 76 if m:
90 dirs[m.group(1)] = True 77 self.dirs[m.group(1)] = True
91
92 self.files = files
93 self.dirs = dirs
94 78
95 def mtnisfile(self, name, rev): 79 def mtnisfile(self, name, rev):
96 # a non-file could be a directory or a deleted or renamed file 80 # a non-file could be a directory or a deleted or renamed file
97 self.mtnloadmanifest(rev) 81 self.mtnloadmanifest(rev)
98 try : 82 try:
99 self.files[name] 83 self.files[name]
100 return True 84 return True
101 except KeyError: 85 except KeyError:
102 return False 86 return False
103 87
104 def mtnisdir(self, name, rev): 88 def mtnisdir(self, name, rev):
105 self.mtnloadmanifest(rev) 89 self.mtnloadmanifest(rev)
106 try : 90 try:
107 self.dirs[name] 91 self.dirs[name]
108 return True 92 return True
109 except KeyError: 93 except KeyError:
110 return False 94 return False
111 95
112 def mtngetcerts(self, rev): 96 def mtngetcerts(self, rev):
113 certs = {"author":"<missing>", "date":"<missing>", 97 certs = {"author":"<missing>", "date":"<missing>",
114 "changelog":"<missing>", "branch":"<missing>"} 98 "changelog":"<missing>", "branch":"<missing>"}
115 cert_list = self.mtncmd("certs %s" % rev).split("\n\n") 99 cert_list = self.mtnrun("certs", rev).split("\n\n")
116 for e in cert_list: 100 for e in cert_list:
117 m = self.cert_re.match(e) 101 m = self.cert_re.match(e)
118 if m: 102 if m:
119 certs[m.group(1)] = m.group(2) 103 certs[m.group(1)] = m.group(2)
120 return certs 104 return certs
121
122 def mtngetparents(self, rev):
123 parents = self.mtncmd("parents %s" % rev).strip("\n").split("\n")
124 p = []
125 for x in parents:
126 if len(x) >= 40: # blank revs have been seen otherwise
127 p.append(x)
128 return p
129 105
130 def mtnrenamefiles(self, files, fromdir, todir): 106 def mtnrenamefiles(self, files, fromdir, todir):
131 renamed = {} 107 renamed = {}
132 for tofile in files: 108 for tofile in files:
133 suffix = tofile.lstrip(todir) 109 suffix = tofile.lstrip(todir)
134 if todir + suffix == tofile: 110 if todir + suffix == tofile:
135 renamed[tofile] = (fromdir + suffix).lstrip("/") 111 renamed[tofile] = (fromdir + suffix).lstrip("/")
136 return renamed 112 return renamed
137 113
138 114
139 # implement the converter_source interface: 115 # implement the converter_source interface:
140 116
141 def getheads(self): 117 def getheads(self):
142 if not self.rev or self.rev == "": 118 if not self.rev:
143 return self.mtncmd("leaves").splitlines() 119 return self.mtnrun("leaves").splitlines()
144 else: 120 else:
145 return [self.rev] 121 return [self.rev]
146 122
147 def getchanges(self, rev): 123 def getchanges(self, rev):
148 revision = self.mtncmd("get_revision %s" % rev).split("\n\n") 124 #revision = self.mtncmd("get_revision %s" % rev).split("\n\n")
125 revision = self.mtnrun("get_revision", rev).split("\n\n")
149 files = {} 126 files = {}
150 copies = {} 127 copies = {}
151 for e in revision: 128 for e in revision:
152 m = self.add_file_re.match(e) 129 m = self.add_file_re.match(e)
153 if m: 130 if m:
168 files[toname] = rev 145 files[toname] = rev
169 files[fromname] = rev 146 files[fromname] = rev
170 if self.mtnisdir(toname, rev): 147 if self.mtnisdir(toname, rev):
171 renamed = self.mtnrenamefiles(self.files, fromname, toname) 148 renamed = self.mtnrenamefiles(self.files, fromname, toname)
172 for tofile, fromfile in renamed.items(): 149 for tofile, fromfile in renamed.items():
173 self.ui.debug (("copying file in renamed dir from '%s' to '%s'" % (fromfile, tofile)), "\n") 150 self.ui.debug (_("copying file in renamed dir from '%s' to '%s'") % (fromfile, tofile), '\n')
174 files[tofile] = rev 151 files[tofile] = rev
175 for fromfile in renamed.values(): 152 for fromfile in renamed.values():
176 files[fromfile] = rev 153 files[fromfile] = rev
154 return (files.items(), copies)
177 155
178 return (files.items(), copies)
179
180 def getmode(self, name, rev): 156 def getmode(self, name, rev):
181 self.mtnloadmanifest(rev) 157 self.mtnloadmanifest(rev)
182 try : 158 try:
183 node, attr = self.files[name] 159 node, attr = self.files[name]
184 return attr 160 return attr
185 except KeyError: 161 except KeyError:
186 return "" 162 return ""
187 163
188 def getfile(self, name, rev): 164 def getfile(self, name, rev):
189 if not self.mtnisfile(name, rev): 165 if not self.mtnisfile(name, rev):
190 raise IOError() # file was deleted or renamed 166 raise IOError() # file was deleted or renamed
191 return self.mtncmd("get_file_of %s -r %s" % (util.shellquote(name), rev)) 167 try:
192 168 return self.mtnrun("get_file_of", name, r=rev)
193 def getcommit(self, rev): 169 except:
170 raise IOError() # file was deleted or renamed
171
172 def getcommit(self, rev):
194 certs = self.mtngetcerts(rev) 173 certs = self.mtngetcerts(rev)
195 return commit( 174 return commit(
196 author=certs["author"], 175 author=certs["author"],
197 date=util.datestr(util.strdate(certs["date"], "%Y-%m-%dT%H:%M:%S")), 176 date=util.datestr(util.strdate(certs["date"], "%Y-%m-%dT%H:%M:%S")),
198 desc=certs["changelog"], 177 desc=certs["changelog"],
199 rev=rev, 178 rev=rev,
200 parents=self.mtngetparents(rev), 179 parents=self.mtnrun("parents", rev).splitlines(),
201 branch=certs["branch"]) 180 branch=certs["branch"])
202 181
203 def gettags(self): 182 def gettags(self):
204 tags = {} 183 tags = {}
205 for e in self.mtncmd("tags").split("\n\n"): 184 for e in self.mtnrun("tags").split("\n\n"):
206 m = self.tag_re.match(e) 185 m = self.tag_re.match(e)
207 if m: 186 if m:
208 tags[m.group(1)] = m.group(2) 187 tags[m.group(1)] = m.group(2)
209 return tags 188 return tags
210 189