comparison hgext/convert/cvsps.py @ 7097:d4218edd55bd

convert: fix builtin cvsps under Windows Drafted and reviewed by Frank Kingswood <frank@kingswood-consulting.co.uk>.
author Patrick Mezard <pmezard@gmail.com>
date Mon, 13 Oct 2008 17:31:03 +0100
parents 12472a240398
children 810ca383da9c
comparison
equal deleted inserted replaced
7096:6dab29f6df37 7097:d4218edd55bd
39 self.__dict__.update(entries) 39 self.__dict__.update(entries)
40 40
41 class logerror(Exception): 41 class logerror(Exception):
42 pass 42 pass
43 43
44 def getrepopath(cvspath):
45 """Return the repository path from a CVS path.
46
47 >>> getrepopath('/foo/bar')
48 '/foo/bar'
49 >>> getrepopath('c:/foo/bar')
50 'c:/foo/bar'
51 >>> getrepopath(':pserver:10/foo/bar')
52 '/foo/bar'
53 >>> getrepopath(':pserver:10c:/foo/bar')
54 '/foo/bar'
55 >>> getrepopath(':pserver:/foo/bar')
56 '/foo/bar'
57 >>> getrepopath(':pserver:c:/foo/bar')
58 'c:/foo/bar'
59 >>> getrepopath(':pserver:truc@foo.bar:/foo/bar')
60 '/foo/bar'
61 >>> getrepopath(':pserver:truc@foo.bar:c:/foo/bar')
62 'c:/foo/bar'
63 """
64 # According to CVS manual, CVS paths are expressed like:
65 # [:method:][[user][:password]@]hostname[:[port]]/path/to/repository
66 #
67 # Unfortunately, Windows absolute paths start with a drive letter
68 # like 'c:' making it harder to parse. Here we assume that drive
69 # letters are only one character long and any CVS component before
70 # the repository path is at least 2 characters long, and use this
71 # to disambiguate.
72 parts = cvspath.split(':')
73 if len(parts) == 1:
74 return parts[0]
75 # Here there is an ambiguous case if we have a port number
76 # immediately followed by a Windows driver letter. We assume this
77 # never happens and decide it must be CVS path component,
78 # therefore ignoring it.
79 if len(parts[-2]) > 1:
80 return parts[-1].lstrip('0123456789')
81 return parts[-2] + ':' + parts[-1]
82
44 def createlog(ui, directory=None, root="", rlog=True, cache=None): 83 def createlog(ui, directory=None, root="", rlog=True, cache=None):
45 '''Collect the CVS rlog''' 84 '''Collect the CVS rlog'''
46 85
47 # Because we store many duplicate commit log messages, reusing strings 86 # Because we store many duplicate commit log messages, reusing strings
48 # saves a lot of memory and pickle storage space. 87 # saves a lot of memory and pickle storage space.
81 prefix = "" 120 prefix = ""
82 directory = prefix 121 directory = prefix
83 except IOError: 122 except IOError:
84 raise logerror('Not a CVS sandbox') 123 raise logerror('Not a CVS sandbox')
85 124
86 if prefix and not prefix.endswith('/'): 125 if prefix and not prefix.endswith(os.sep):
87 prefix += '/' 126 prefix += os.sep
88 127
89 # Use the Root file in the sandbox, if it exists 128 # Use the Root file in the sandbox, if it exists
90 try: 129 try:
91 root = file(os.path.join('CVS','Root')).read().strip() 130 root = file(os.path.join('CVS','Root')).read().strip()
92 except IOError: 131 except IOError:
132 171
133 # build the CVS commandline 172 # build the CVS commandline
134 cmd = ['cvs', '-q'] 173 cmd = ['cvs', '-q']
135 if root: 174 if root:
136 cmd.append('-d%s' % root) 175 cmd.append('-d%s' % root)
137 p = root.split(':')[-1] 176 p = util.normpath(getrepopath(root))
138 if not p.endswith('/'): 177 if not p.endswith('/'):
139 p += '/' 178 p += '/'
140 prefix = p + prefix 179 prefix = p + util.normpath(prefix)
141 cmd.append(['log', 'rlog'][rlog]) 180 cmd.append(['log', 'rlog'][rlog])
142 if date: 181 if date:
143 # no space between option and date string 182 # no space between option and date string
144 cmd.append('-d>%s' % date) 183 cmd.append('-d>%s' % date)
145 cmd.append(directory) 184 cmd.append(directory)
163 match = re_00.match(line) 202 match = re_00.match(line)
164 if match: 203 if match:
165 rcs = match.group(1) 204 rcs = match.group(1)
166 tags = {} 205 tags = {}
167 if rlog: 206 if rlog:
168 filename = rcs[:-2] 207 filename = util.normpath(rcs[:-2])
169 if filename.startswith(prefix): 208 if filename.startswith(prefix):
170 filename = filename[len(prefix):] 209 filename = filename[len(prefix):]
171 if filename.startswith('/'): 210 if filename.startswith('/'):
172 filename = filename[1:] 211 filename = filename[1:]
173 if filename.startswith('Attic/'): 212 if filename.startswith('Attic/'):
189 228
190 elif state == 1: 229 elif state == 1:
191 # expect 'Working file' (only when using log instead of rlog) 230 # expect 'Working file' (only when using log instead of rlog)
192 match = re_10.match(line) 231 match = re_10.match(line)
193 assert match, _('RCS file must be followed by working file') 232 assert match, _('RCS file must be followed by working file')
194 filename = match.group(1) 233 filename = util.normpath(match.group(1))
195 state = 2 234 state = 2
196 235
197 elif state == 2: 236 elif state == 2:
198 # expect 'symbolic names' 237 # expect 'symbolic names'
199 if re_20.match(line): 238 if re_20.match(line):