##// END OF EJS Templates
convert: remove superfluous pass statements
Augie Fackler -
r34368:5adbd380 default
parent child Browse files
Show More
@@ -1,496 +1,491 b''
1 # common.py - common code for the convert extension
1 # common.py - common code for the convert extension
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import base64
9 import base64
10 import datetime
10 import datetime
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import subprocess
14 import subprocess
15
15
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17 from mercurial import (
17 from mercurial import (
18 encoding,
18 encoding,
19 error,
19 error,
20 phases,
20 phases,
21 util,
21 util,
22 )
22 )
23
23
24 pickle = util.pickle
24 pickle = util.pickle
25 propertycache = util.propertycache
25 propertycache = util.propertycache
26
26
27 def encodeargs(args):
27 def encodeargs(args):
28 def encodearg(s):
28 def encodearg(s):
29 lines = base64.encodestring(s)
29 lines = base64.encodestring(s)
30 lines = [l.splitlines()[0] for l in lines]
30 lines = [l.splitlines()[0] for l in lines]
31 return ''.join(lines)
31 return ''.join(lines)
32
32
33 s = pickle.dumps(args)
33 s = pickle.dumps(args)
34 return encodearg(s)
34 return encodearg(s)
35
35
36 def decodeargs(s):
36 def decodeargs(s):
37 s = base64.decodestring(s)
37 s = base64.decodestring(s)
38 return pickle.loads(s)
38 return pickle.loads(s)
39
39
40 class MissingTool(Exception):
40 class MissingTool(Exception):
41 pass
41 pass
42
42
43 def checktool(exe, name=None, abort=True):
43 def checktool(exe, name=None, abort=True):
44 name = name or exe
44 name = name or exe
45 if not util.findexe(exe):
45 if not util.findexe(exe):
46 if abort:
46 if abort:
47 exc = error.Abort
47 exc = error.Abort
48 else:
48 else:
49 exc = MissingTool
49 exc = MissingTool
50 raise exc(_('cannot find required "%s" tool') % name)
50 raise exc(_('cannot find required "%s" tool') % name)
51
51
52 class NoRepo(Exception):
52 class NoRepo(Exception):
53 pass
53 pass
54
54
55 SKIPREV = 'SKIP'
55 SKIPREV = 'SKIP'
56
56
57 class commit(object):
57 class commit(object):
58 def __init__(self, author, date, desc, parents, branch=None, rev=None,
58 def __init__(self, author, date, desc, parents, branch=None, rev=None,
59 extra=None, sortkey=None, saverev=True, phase=phases.draft,
59 extra=None, sortkey=None, saverev=True, phase=phases.draft,
60 optparents=None):
60 optparents=None):
61 self.author = author or 'unknown'
61 self.author = author or 'unknown'
62 self.date = date or '0 0'
62 self.date = date or '0 0'
63 self.desc = desc
63 self.desc = desc
64 self.parents = parents # will be converted and used as parents
64 self.parents = parents # will be converted and used as parents
65 self.optparents = optparents or [] # will be used if already converted
65 self.optparents = optparents or [] # will be used if already converted
66 self.branch = branch
66 self.branch = branch
67 self.rev = rev
67 self.rev = rev
68 self.extra = extra or {}
68 self.extra = extra or {}
69 self.sortkey = sortkey
69 self.sortkey = sortkey
70 self.saverev = saverev
70 self.saverev = saverev
71 self.phase = phase
71 self.phase = phase
72
72
73 class converter_source(object):
73 class converter_source(object):
74 """Conversion source interface"""
74 """Conversion source interface"""
75
75
76 def __init__(self, ui, path=None, revs=None):
76 def __init__(self, ui, path=None, revs=None):
77 """Initialize conversion source (or raise NoRepo("message")
77 """Initialize conversion source (or raise NoRepo("message")
78 exception if path is not a valid repository)"""
78 exception if path is not a valid repository)"""
79 self.ui = ui
79 self.ui = ui
80 self.path = path
80 self.path = path
81 self.revs = revs
81 self.revs = revs
82
82
83 self.encoding = 'utf-8'
83 self.encoding = 'utf-8'
84
84
85 def checkhexformat(self, revstr, mapname='splicemap'):
85 def checkhexformat(self, revstr, mapname='splicemap'):
86 """ fails if revstr is not a 40 byte hex. mercurial and git both uses
86 """ fails if revstr is not a 40 byte hex. mercurial and git both uses
87 such format for their revision numbering
87 such format for their revision numbering
88 """
88 """
89 if not re.match(r'[0-9a-fA-F]{40,40}$', revstr):
89 if not re.match(r'[0-9a-fA-F]{40,40}$', revstr):
90 raise error.Abort(_('%s entry %s is not a valid revision'
90 raise error.Abort(_('%s entry %s is not a valid revision'
91 ' identifier') % (mapname, revstr))
91 ' identifier') % (mapname, revstr))
92
92
93 def before(self):
93 def before(self):
94 pass
94 pass
95
95
96 def after(self):
96 def after(self):
97 pass
97 pass
98
98
99 def targetfilebelongstosource(self, targetfilename):
99 def targetfilebelongstosource(self, targetfilename):
100 """Returns true if the given targetfile belongs to the source repo. This
100 """Returns true if the given targetfile belongs to the source repo. This
101 is useful when only a subdirectory of the target belongs to the source
101 is useful when only a subdirectory of the target belongs to the source
102 repo."""
102 repo."""
103 # For normal full repo converts, this is always True.
103 # For normal full repo converts, this is always True.
104 return True
104 return True
105
105
106 def setrevmap(self, revmap):
106 def setrevmap(self, revmap):
107 """set the map of already-converted revisions"""
107 """set the map of already-converted revisions"""
108 pass
109
108
110 def getheads(self):
109 def getheads(self):
111 """Return a list of this repository's heads"""
110 """Return a list of this repository's heads"""
112 raise NotImplementedError
111 raise NotImplementedError
113
112
114 def getfile(self, name, rev):
113 def getfile(self, name, rev):
115 """Return a pair (data, mode) where data is the file content
114 """Return a pair (data, mode) where data is the file content
116 as a string and mode one of '', 'x' or 'l'. rev is the
115 as a string and mode one of '', 'x' or 'l'. rev is the
117 identifier returned by a previous call to getchanges().
116 identifier returned by a previous call to getchanges().
118 Data is None if file is missing/deleted in rev.
117 Data is None if file is missing/deleted in rev.
119 """
118 """
120 raise NotImplementedError
119 raise NotImplementedError
121
120
122 def getchanges(self, version, full):
121 def getchanges(self, version, full):
123 """Returns a tuple of (files, copies, cleanp2).
122 """Returns a tuple of (files, copies, cleanp2).
124
123
125 files is a sorted list of (filename, id) tuples for all files
124 files is a sorted list of (filename, id) tuples for all files
126 changed between version and its first parent returned by
125 changed between version and its first parent returned by
127 getcommit(). If full, all files in that revision is returned.
126 getcommit(). If full, all files in that revision is returned.
128 id is the source revision id of the file.
127 id is the source revision id of the file.
129
128
130 copies is a dictionary of dest: source
129 copies is a dictionary of dest: source
131
130
132 cleanp2 is the set of files filenames that are clean against p2.
131 cleanp2 is the set of files filenames that are clean against p2.
133 (Files that are clean against p1 are already not in files (unless
132 (Files that are clean against p1 are already not in files (unless
134 full). This makes it possible to handle p2 clean files similarly.)
133 full). This makes it possible to handle p2 clean files similarly.)
135 """
134 """
136 raise NotImplementedError
135 raise NotImplementedError
137
136
138 def getcommit(self, version):
137 def getcommit(self, version):
139 """Return the commit object for version"""
138 """Return the commit object for version"""
140 raise NotImplementedError
139 raise NotImplementedError
141
140
142 def numcommits(self):
141 def numcommits(self):
143 """Return the number of commits in this source.
142 """Return the number of commits in this source.
144
143
145 If unknown, return None.
144 If unknown, return None.
146 """
145 """
147 return None
146 return None
148
147
149 def gettags(self):
148 def gettags(self):
150 """Return the tags as a dictionary of name: revision
149 """Return the tags as a dictionary of name: revision
151
150
152 Tag names must be UTF-8 strings.
151 Tag names must be UTF-8 strings.
153 """
152 """
154 raise NotImplementedError
153 raise NotImplementedError
155
154
156 def recode(self, s, encoding=None):
155 def recode(self, s, encoding=None):
157 if not encoding:
156 if not encoding:
158 encoding = self.encoding or 'utf-8'
157 encoding = self.encoding or 'utf-8'
159
158
160 if isinstance(s, unicode):
159 if isinstance(s, unicode):
161 return s.encode("utf-8")
160 return s.encode("utf-8")
162 try:
161 try:
163 return s.decode(encoding).encode("utf-8")
162 return s.decode(encoding).encode("utf-8")
164 except UnicodeError:
163 except UnicodeError:
165 try:
164 try:
166 return s.decode("latin-1").encode("utf-8")
165 return s.decode("latin-1").encode("utf-8")
167 except UnicodeError:
166 except UnicodeError:
168 return s.decode(encoding, "replace").encode("utf-8")
167 return s.decode(encoding, "replace").encode("utf-8")
169
168
170 def getchangedfiles(self, rev, i):
169 def getchangedfiles(self, rev, i):
171 """Return the files changed by rev compared to parent[i].
170 """Return the files changed by rev compared to parent[i].
172
171
173 i is an index selecting one of the parents of rev. The return
172 i is an index selecting one of the parents of rev. The return
174 value should be the list of files that are different in rev and
173 value should be the list of files that are different in rev and
175 this parent.
174 this parent.
176
175
177 If rev has no parents, i is None.
176 If rev has no parents, i is None.
178
177
179 This function is only needed to support --filemap
178 This function is only needed to support --filemap
180 """
179 """
181 raise NotImplementedError
180 raise NotImplementedError
182
181
183 def converted(self, rev, sinkrev):
182 def converted(self, rev, sinkrev):
184 '''Notify the source that a revision has been converted.'''
183 '''Notify the source that a revision has been converted.'''
185 pass
186
184
187 def hasnativeorder(self):
185 def hasnativeorder(self):
188 """Return true if this source has a meaningful, native revision
186 """Return true if this source has a meaningful, native revision
189 order. For instance, Mercurial revisions are store sequentially
187 order. For instance, Mercurial revisions are store sequentially
190 while there is no such global ordering with Darcs.
188 while there is no such global ordering with Darcs.
191 """
189 """
192 return False
190 return False
193
191
194 def hasnativeclose(self):
192 def hasnativeclose(self):
195 """Return true if this source has ability to close branch.
193 """Return true if this source has ability to close branch.
196 """
194 """
197 return False
195 return False
198
196
199 def lookuprev(self, rev):
197 def lookuprev(self, rev):
200 """If rev is a meaningful revision reference in source, return
198 """If rev is a meaningful revision reference in source, return
201 the referenced identifier in the same format used by getcommit().
199 the referenced identifier in the same format used by getcommit().
202 return None otherwise.
200 return None otherwise.
203 """
201 """
204 return None
202 return None
205
203
206 def getbookmarks(self):
204 def getbookmarks(self):
207 """Return the bookmarks as a dictionary of name: revision
205 """Return the bookmarks as a dictionary of name: revision
208
206
209 Bookmark names are to be UTF-8 strings.
207 Bookmark names are to be UTF-8 strings.
210 """
208 """
211 return {}
209 return {}
212
210
213 def checkrevformat(self, revstr, mapname='splicemap'):
211 def checkrevformat(self, revstr, mapname='splicemap'):
214 """revstr is a string that describes a revision in the given
212 """revstr is a string that describes a revision in the given
215 source control system. Return true if revstr has correct
213 source control system. Return true if revstr has correct
216 format.
214 format.
217 """
215 """
218 return True
216 return True
219
217
220 class converter_sink(object):
218 class converter_sink(object):
221 """Conversion sink (target) interface"""
219 """Conversion sink (target) interface"""
222
220
223 def __init__(self, ui, path):
221 def __init__(self, ui, path):
224 """Initialize conversion sink (or raise NoRepo("message")
222 """Initialize conversion sink (or raise NoRepo("message")
225 exception if path is not a valid repository)
223 exception if path is not a valid repository)
226
224
227 created is a list of paths to remove if a fatal error occurs
225 created is a list of paths to remove if a fatal error occurs
228 later"""
226 later"""
229 self.ui = ui
227 self.ui = ui
230 self.path = path
228 self.path = path
231 self.created = []
229 self.created = []
232
230
233 def revmapfile(self):
231 def revmapfile(self):
234 """Path to a file that will contain lines
232 """Path to a file that will contain lines
235 source_rev_id sink_rev_id
233 source_rev_id sink_rev_id
236 mapping equivalent revision identifiers for each system."""
234 mapping equivalent revision identifiers for each system."""
237 raise NotImplementedError
235 raise NotImplementedError
238
236
239 def authorfile(self):
237 def authorfile(self):
240 """Path to a file that will contain lines
238 """Path to a file that will contain lines
241 srcauthor=dstauthor
239 srcauthor=dstauthor
242 mapping equivalent authors identifiers for each system."""
240 mapping equivalent authors identifiers for each system."""
243 return None
241 return None
244
242
245 def putcommit(self, files, copies, parents, commit, source, revmap, full,
243 def putcommit(self, files, copies, parents, commit, source, revmap, full,
246 cleanp2):
244 cleanp2):
247 """Create a revision with all changed files listed in 'files'
245 """Create a revision with all changed files listed in 'files'
248 and having listed parents. 'commit' is a commit object
246 and having listed parents. 'commit' is a commit object
249 containing at a minimum the author, date, and message for this
247 containing at a minimum the author, date, and message for this
250 changeset. 'files' is a list of (path, version) tuples,
248 changeset. 'files' is a list of (path, version) tuples,
251 'copies' is a dictionary mapping destinations to sources,
249 'copies' is a dictionary mapping destinations to sources,
252 'source' is the source repository, and 'revmap' is a mapfile
250 'source' is the source repository, and 'revmap' is a mapfile
253 of source revisions to converted revisions. Only getfile() and
251 of source revisions to converted revisions. Only getfile() and
254 lookuprev() should be called on 'source'. 'full' means that 'files'
252 lookuprev() should be called on 'source'. 'full' means that 'files'
255 is complete and all other files should be removed.
253 is complete and all other files should be removed.
256 'cleanp2' is a set of the filenames that are unchanged from p2
254 'cleanp2' is a set of the filenames that are unchanged from p2
257 (only in the common merge case where there two parents).
255 (only in the common merge case where there two parents).
258
256
259 Note that the sink repository is not told to update itself to
257 Note that the sink repository is not told to update itself to
260 a particular revision (or even what that revision would be)
258 a particular revision (or even what that revision would be)
261 before it receives the file data.
259 before it receives the file data.
262 """
260 """
263 raise NotImplementedError
261 raise NotImplementedError
264
262
265 def puttags(self, tags):
263 def puttags(self, tags):
266 """Put tags into sink.
264 """Put tags into sink.
267
265
268 tags: {tagname: sink_rev_id, ...} where tagname is an UTF-8 string.
266 tags: {tagname: sink_rev_id, ...} where tagname is an UTF-8 string.
269 Return a pair (tag_revision, tag_parent_revision), or (None, None)
267 Return a pair (tag_revision, tag_parent_revision), or (None, None)
270 if nothing was changed.
268 if nothing was changed.
271 """
269 """
272 raise NotImplementedError
270 raise NotImplementedError
273
271
274 def setbranch(self, branch, pbranches):
272 def setbranch(self, branch, pbranches):
275 """Set the current branch name. Called before the first putcommit
273 """Set the current branch name. Called before the first putcommit
276 on the branch.
274 on the branch.
277 branch: branch name for subsequent commits
275 branch: branch name for subsequent commits
278 pbranches: (converted parent revision, parent branch) tuples"""
276 pbranches: (converted parent revision, parent branch) tuples"""
279 pass
280
277
281 def setfilemapmode(self, active):
278 def setfilemapmode(self, active):
282 """Tell the destination that we're using a filemap
279 """Tell the destination that we're using a filemap
283
280
284 Some converter_sources (svn in particular) can claim that a file
281 Some converter_sources (svn in particular) can claim that a file
285 was changed in a revision, even if there was no change. This method
282 was changed in a revision, even if there was no change. This method
286 tells the destination that we're using a filemap and that it should
283 tells the destination that we're using a filemap and that it should
287 filter empty revisions.
284 filter empty revisions.
288 """
285 """
289 pass
290
286
291 def before(self):
287 def before(self):
292 pass
288 pass
293
289
294 def after(self):
290 def after(self):
295 pass
291 pass
296
292
297 def putbookmarks(self, bookmarks):
293 def putbookmarks(self, bookmarks):
298 """Put bookmarks into sink.
294 """Put bookmarks into sink.
299
295
300 bookmarks: {bookmarkname: sink_rev_id, ...}
296 bookmarks: {bookmarkname: sink_rev_id, ...}
301 where bookmarkname is an UTF-8 string.
297 where bookmarkname is an UTF-8 string.
302 """
298 """
303 pass
304
299
305 def hascommitfrommap(self, rev):
300 def hascommitfrommap(self, rev):
306 """Return False if a rev mentioned in a filemap is known to not be
301 """Return False if a rev mentioned in a filemap is known to not be
307 present."""
302 present."""
308 raise NotImplementedError
303 raise NotImplementedError
309
304
310 def hascommitforsplicemap(self, rev):
305 def hascommitforsplicemap(self, rev):
311 """This method is for the special needs for splicemap handling and not
306 """This method is for the special needs for splicemap handling and not
312 for general use. Returns True if the sink contains rev, aborts on some
307 for general use. Returns True if the sink contains rev, aborts on some
313 special cases."""
308 special cases."""
314 raise NotImplementedError
309 raise NotImplementedError
315
310
316 class commandline(object):
311 class commandline(object):
317 def __init__(self, ui, command):
312 def __init__(self, ui, command):
318 self.ui = ui
313 self.ui = ui
319 self.command = command
314 self.command = command
320
315
321 def prerun(self):
316 def prerun(self):
322 pass
317 pass
323
318
324 def postrun(self):
319 def postrun(self):
325 pass
320 pass
326
321
327 def _cmdline(self, cmd, *args, **kwargs):
322 def _cmdline(self, cmd, *args, **kwargs):
328 cmdline = [self.command, cmd] + list(args)
323 cmdline = [self.command, cmd] + list(args)
329 for k, v in kwargs.iteritems():
324 for k, v in kwargs.iteritems():
330 if len(k) == 1:
325 if len(k) == 1:
331 cmdline.append('-' + k)
326 cmdline.append('-' + k)
332 else:
327 else:
333 cmdline.append('--' + k.replace('_', '-'))
328 cmdline.append('--' + k.replace('_', '-'))
334 try:
329 try:
335 if len(k) == 1:
330 if len(k) == 1:
336 cmdline.append('' + v)
331 cmdline.append('' + v)
337 else:
332 else:
338 cmdline[-1] += '=' + v
333 cmdline[-1] += '=' + v
339 except TypeError:
334 except TypeError:
340 pass
335 pass
341 cmdline = [util.shellquote(arg) for arg in cmdline]
336 cmdline = [util.shellquote(arg) for arg in cmdline]
342 if not self.ui.debugflag:
337 if not self.ui.debugflag:
343 cmdline += ['2>', os.devnull]
338 cmdline += ['2>', os.devnull]
344 cmdline = ' '.join(cmdline)
339 cmdline = ' '.join(cmdline)
345 return cmdline
340 return cmdline
346
341
347 def _run(self, cmd, *args, **kwargs):
342 def _run(self, cmd, *args, **kwargs):
348 def popen(cmdline):
343 def popen(cmdline):
349 p = subprocess.Popen(cmdline, shell=True, bufsize=-1,
344 p = subprocess.Popen(cmdline, shell=True, bufsize=-1,
350 close_fds=util.closefds,
345 close_fds=util.closefds,
351 stdout=subprocess.PIPE)
346 stdout=subprocess.PIPE)
352 return p
347 return p
353 return self._dorun(popen, cmd, *args, **kwargs)
348 return self._dorun(popen, cmd, *args, **kwargs)
354
349
355 def _run2(self, cmd, *args, **kwargs):
350 def _run2(self, cmd, *args, **kwargs):
356 return self._dorun(util.popen2, cmd, *args, **kwargs)
351 return self._dorun(util.popen2, cmd, *args, **kwargs)
357
352
358 def _run3(self, cmd, *args, **kwargs):
353 def _run3(self, cmd, *args, **kwargs):
359 return self._dorun(util.popen3, cmd, *args, **kwargs)
354 return self._dorun(util.popen3, cmd, *args, **kwargs)
360
355
361 def _dorun(self, openfunc, cmd, *args, **kwargs):
356 def _dorun(self, openfunc, cmd, *args, **kwargs):
362 cmdline = self._cmdline(cmd, *args, **kwargs)
357 cmdline = self._cmdline(cmd, *args, **kwargs)
363 self.ui.debug('running: %s\n' % (cmdline,))
358 self.ui.debug('running: %s\n' % (cmdline,))
364 self.prerun()
359 self.prerun()
365 try:
360 try:
366 return openfunc(cmdline)
361 return openfunc(cmdline)
367 finally:
362 finally:
368 self.postrun()
363 self.postrun()
369
364
370 def run(self, cmd, *args, **kwargs):
365 def run(self, cmd, *args, **kwargs):
371 p = self._run(cmd, *args, **kwargs)
366 p = self._run(cmd, *args, **kwargs)
372 output = p.communicate()[0]
367 output = p.communicate()[0]
373 self.ui.debug(output)
368 self.ui.debug(output)
374 return output, p.returncode
369 return output, p.returncode
375
370
376 def runlines(self, cmd, *args, **kwargs):
371 def runlines(self, cmd, *args, **kwargs):
377 p = self._run(cmd, *args, **kwargs)
372 p = self._run(cmd, *args, **kwargs)
378 output = p.stdout.readlines()
373 output = p.stdout.readlines()
379 p.wait()
374 p.wait()
380 self.ui.debug(''.join(output))
375 self.ui.debug(''.join(output))
381 return output, p.returncode
376 return output, p.returncode
382
377
383 def checkexit(self, status, output=''):
378 def checkexit(self, status, output=''):
384 if status:
379 if status:
385 if output:
380 if output:
386 self.ui.warn(_('%s error:\n') % self.command)
381 self.ui.warn(_('%s error:\n') % self.command)
387 self.ui.warn(output)
382 self.ui.warn(output)
388 msg = util.explainexit(status)[0]
383 msg = util.explainexit(status)[0]
389 raise error.Abort('%s %s' % (self.command, msg))
384 raise error.Abort('%s %s' % (self.command, msg))
390
385
391 def run0(self, cmd, *args, **kwargs):
386 def run0(self, cmd, *args, **kwargs):
392 output, status = self.run(cmd, *args, **kwargs)
387 output, status = self.run(cmd, *args, **kwargs)
393 self.checkexit(status, output)
388 self.checkexit(status, output)
394 return output
389 return output
395
390
396 def runlines0(self, cmd, *args, **kwargs):
391 def runlines0(self, cmd, *args, **kwargs):
397 output, status = self.runlines(cmd, *args, **kwargs)
392 output, status = self.runlines(cmd, *args, **kwargs)
398 self.checkexit(status, ''.join(output))
393 self.checkexit(status, ''.join(output))
399 return output
394 return output
400
395
401 @propertycache
396 @propertycache
402 def argmax(self):
397 def argmax(self):
403 # POSIX requires at least 4096 bytes for ARG_MAX
398 # POSIX requires at least 4096 bytes for ARG_MAX
404 argmax = 4096
399 argmax = 4096
405 try:
400 try:
406 argmax = os.sysconf("SC_ARG_MAX")
401 argmax = os.sysconf("SC_ARG_MAX")
407 except (AttributeError, ValueError):
402 except (AttributeError, ValueError):
408 pass
403 pass
409
404
410 # Windows shells impose their own limits on command line length,
405 # Windows shells impose their own limits on command line length,
411 # down to 2047 bytes for cmd.exe under Windows NT/2k and 2500 bytes
406 # down to 2047 bytes for cmd.exe under Windows NT/2k and 2500 bytes
412 # for older 4nt.exe. See http://support.microsoft.com/kb/830473 for
407 # for older 4nt.exe. See http://support.microsoft.com/kb/830473 for
413 # details about cmd.exe limitations.
408 # details about cmd.exe limitations.
414
409
415 # Since ARG_MAX is for command line _and_ environment, lower our limit
410 # Since ARG_MAX is for command line _and_ environment, lower our limit
416 # (and make happy Windows shells while doing this).
411 # (and make happy Windows shells while doing this).
417 return argmax // 2 - 1
412 return argmax // 2 - 1
418
413
419 def _limit_arglist(self, arglist, cmd, *args, **kwargs):
414 def _limit_arglist(self, arglist, cmd, *args, **kwargs):
420 cmdlen = len(self._cmdline(cmd, *args, **kwargs))
415 cmdlen = len(self._cmdline(cmd, *args, **kwargs))
421 limit = self.argmax - cmdlen
416 limit = self.argmax - cmdlen
422 bytes = 0
417 bytes = 0
423 fl = []
418 fl = []
424 for fn in arglist:
419 for fn in arglist:
425 b = len(fn) + 3
420 b = len(fn) + 3
426 if bytes + b < limit or len(fl) == 0:
421 if bytes + b < limit or len(fl) == 0:
427 fl.append(fn)
422 fl.append(fn)
428 bytes += b
423 bytes += b
429 else:
424 else:
430 yield fl
425 yield fl
431 fl = [fn]
426 fl = [fn]
432 bytes = b
427 bytes = b
433 if fl:
428 if fl:
434 yield fl
429 yield fl
435
430
436 def xargs(self, arglist, cmd, *args, **kwargs):
431 def xargs(self, arglist, cmd, *args, **kwargs):
437 for l in self._limit_arglist(arglist, cmd, *args, **kwargs):
432 for l in self._limit_arglist(arglist, cmd, *args, **kwargs):
438 self.run0(cmd, *(list(args) + l), **kwargs)
433 self.run0(cmd, *(list(args) + l), **kwargs)
439
434
440 class mapfile(dict):
435 class mapfile(dict):
441 def __init__(self, ui, path):
436 def __init__(self, ui, path):
442 super(mapfile, self).__init__()
437 super(mapfile, self).__init__()
443 self.ui = ui
438 self.ui = ui
444 self.path = path
439 self.path = path
445 self.fp = None
440 self.fp = None
446 self.order = []
441 self.order = []
447 self._read()
442 self._read()
448
443
449 def _read(self):
444 def _read(self):
450 if not self.path:
445 if not self.path:
451 return
446 return
452 try:
447 try:
453 fp = open(self.path, 'r')
448 fp = open(self.path, 'r')
454 except IOError as err:
449 except IOError as err:
455 if err.errno != errno.ENOENT:
450 if err.errno != errno.ENOENT:
456 raise
451 raise
457 return
452 return
458 for i, line in enumerate(util.iterfile(fp)):
453 for i, line in enumerate(util.iterfile(fp)):
459 line = line.splitlines()[0].rstrip()
454 line = line.splitlines()[0].rstrip()
460 if not line:
455 if not line:
461 # Ignore blank lines
456 # Ignore blank lines
462 continue
457 continue
463 try:
458 try:
464 key, value = line.rsplit(' ', 1)
459 key, value = line.rsplit(' ', 1)
465 except ValueError:
460 except ValueError:
466 raise error.Abort(
461 raise error.Abort(
467 _('syntax error in %s(%d): key/value pair expected')
462 _('syntax error in %s(%d): key/value pair expected')
468 % (self.path, i + 1))
463 % (self.path, i + 1))
469 if key not in self:
464 if key not in self:
470 self.order.append(key)
465 self.order.append(key)
471 super(mapfile, self).__setitem__(key, value)
466 super(mapfile, self).__setitem__(key, value)
472 fp.close()
467 fp.close()
473
468
474 def __setitem__(self, key, value):
469 def __setitem__(self, key, value):
475 if self.fp is None:
470 if self.fp is None:
476 try:
471 try:
477 self.fp = open(self.path, 'a')
472 self.fp = open(self.path, 'a')
478 except IOError as err:
473 except IOError as err:
479 raise error.Abort(
474 raise error.Abort(
480 _('could not open map file %r: %s') %
475 _('could not open map file %r: %s') %
481 (self.path, encoding.strtolocal(err.strerror)))
476 (self.path, encoding.strtolocal(err.strerror)))
482 self.fp.write('%s %s\n' % (key, value))
477 self.fp.write('%s %s\n' % (key, value))
483 self.fp.flush()
478 self.fp.flush()
484 super(mapfile, self).__setitem__(key, value)
479 super(mapfile, self).__setitem__(key, value)
485
480
486 def close(self):
481 def close(self):
487 if self.fp:
482 if self.fp:
488 self.fp.close()
483 self.fp.close()
489 self.fp = None
484 self.fp = None
490
485
491 def makedatetimestamp(t):
486 def makedatetimestamp(t):
492 """Like util.makedate() but for time t instead of current time"""
487 """Like util.makedate() but for time t instead of current time"""
493 delta = (datetime.datetime.utcfromtimestamp(t) -
488 delta = (datetime.datetime.utcfromtimestamp(t) -
494 datetime.datetime.fromtimestamp(t))
489 datetime.datetime.fromtimestamp(t))
495 tz = delta.days * 86400 + delta.seconds
490 tz = delta.days * 86400 + delta.seconds
496 return t, tz
491 return t, tz
General Comments 0
You need to be logged in to leave comments. Login now