##// END OF EJS Templates
removed unused imports
Martin Geisler -
r8656:284fda4c default
parent child Browse files
Show More
@@ -1,131 +1,130 b''
1 # perf.py - performance test routines
1 # perf.py - performance test routines
2
2
3 from mercurial.i18n import _
4 from mercurial import cmdutil, match, commands
3 from mercurial import cmdutil, match, commands
5 import time, os, sys
4 import time, os, sys
6
5
7 def timer(func):
6 def timer(func):
8 results = []
7 results = []
9 begin = time.time()
8 begin = time.time()
10 count = 0
9 count = 0
11 while 1:
10 while 1:
12 ostart = os.times()
11 ostart = os.times()
13 cstart = time.time()
12 cstart = time.time()
14 r = func()
13 r = func()
15 cstop = time.time()
14 cstop = time.time()
16 ostop = os.times()
15 ostop = os.times()
17 count += 1
16 count += 1
18 a, b = ostart, ostop
17 a, b = ostart, ostop
19 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
18 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
20 if cstop - begin > 3 and count >= 100:
19 if cstop - begin > 3 and count >= 100:
21 break
20 break
22 if cstop - begin > 10 and count >= 3:
21 if cstop - begin > 10 and count >= 3:
23 break
22 break
24 if r:
23 if r:
25 sys.stderr.write("! result: %s\n" % r)
24 sys.stderr.write("! result: %s\n" % r)
26 m = min(results)
25 m = min(results)
27 sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n"
26 sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n"
28 % (m[0], m[1] + m[2], m[1], m[2], count))
27 % (m[0], m[1] + m[2], m[1], m[2], count))
29
28
30 def perfwalk(ui, repo, *pats):
29 def perfwalk(ui, repo, *pats):
31 try:
30 try:
32 m = cmdutil.match(repo, pats, {})
31 m = cmdutil.match(repo, pats, {})
33 timer(lambda: len(list(repo.dirstate.walk(m, True, False))))
32 timer(lambda: len(list(repo.dirstate.walk(m, True, False))))
34 except:
33 except:
35 try:
34 try:
36 m = cmdutil.match(repo, pats, {})
35 m = cmdutil.match(repo, pats, {})
37 timer(lambda: len([b for a,b,c in repo.dirstate.statwalk([], m)]))
36 timer(lambda: len([b for a,b,c in repo.dirstate.statwalk([], m)]))
38 except:
37 except:
39 timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
38 timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
40
39
41 def perfstatus(ui, repo, *pats):
40 def perfstatus(ui, repo, *pats):
42 #m = match.always(repo.root, repo.getcwd())
41 #m = match.always(repo.root, repo.getcwd())
43 #timer(lambda: sum(map(len, repo.dirstate.status(m, False, False, False))))
42 #timer(lambda: sum(map(len, repo.dirstate.status(m, False, False, False))))
44 timer(lambda: sum(map(len, repo.status())))
43 timer(lambda: sum(map(len, repo.status())))
45
44
46 def perfheads(ui, repo):
45 def perfheads(ui, repo):
47 timer(lambda: len(repo.changelog.heads()))
46 timer(lambda: len(repo.changelog.heads()))
48
47
49 def perftags(ui, repo):
48 def perftags(ui, repo):
50 import mercurial.changelog, mercurial.manifest
49 import mercurial.changelog, mercurial.manifest
51 def t():
50 def t():
52 repo.changelog = mercurial.changelog.changelog(repo.sopener)
51 repo.changelog = mercurial.changelog.changelog(repo.sopener)
53 repo.manifest = mercurial.manifest.manifest(repo.sopener)
52 repo.manifest = mercurial.manifest.manifest(repo.sopener)
54 repo.tagscache = None
53 repo.tagscache = None
55 return len(repo.tags())
54 return len(repo.tags())
56 timer(t)
55 timer(t)
57
56
58 def perfdirstate(ui, repo):
57 def perfdirstate(ui, repo):
59 "a" in repo.dirstate
58 "a" in repo.dirstate
60 def d():
59 def d():
61 repo.dirstate.invalidate()
60 repo.dirstate.invalidate()
62 "a" in repo.dirstate
61 "a" in repo.dirstate
63 timer(d)
62 timer(d)
64
63
65 def perfdirstatedirs(ui, repo):
64 def perfdirstatedirs(ui, repo):
66 "a" in repo.dirstate
65 "a" in repo.dirstate
67 def d():
66 def d():
68 "a" in repo.dirstate._dirs
67 "a" in repo.dirstate._dirs
69 del repo.dirstate._dirs
68 del repo.dirstate._dirs
70 timer(d)
69 timer(d)
71
70
72 def perfmanifest(ui, repo):
71 def perfmanifest(ui, repo):
73 def d():
72 def d():
74 t = repo.manifest.tip()
73 t = repo.manifest.tip()
75 m = repo.manifest.read(t)
74 m = repo.manifest.read(t)
76 repo.manifest.mapcache = None
75 repo.manifest.mapcache = None
77 repo.manifest._cache = None
76 repo.manifest._cache = None
78 timer(d)
77 timer(d)
79
78
80 def perfindex(ui, repo):
79 def perfindex(ui, repo):
81 import mercurial.changelog
80 import mercurial.changelog
82 def d():
81 def d():
83 t = repo.changelog.tip()
82 t = repo.changelog.tip()
84 repo.changelog = mercurial.changelog.changelog(repo.sopener)
83 repo.changelog = mercurial.changelog.changelog(repo.sopener)
85 repo.changelog._loadindexmap()
84 repo.changelog._loadindexmap()
86 timer(d)
85 timer(d)
87
86
88 def perfstartup(ui, repo):
87 def perfstartup(ui, repo):
89 cmd = sys.argv[0]
88 cmd = sys.argv[0]
90 def d():
89 def d():
91 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
90 os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
92 timer(d)
91 timer(d)
93
92
94 def perfparents(ui, repo):
93 def perfparents(ui, repo):
95 nl = [repo.changelog.node(i) for i in xrange(1000)]
94 nl = [repo.changelog.node(i) for i in xrange(1000)]
96 def d():
95 def d():
97 for n in nl:
96 for n in nl:
98 repo.changelog.parents(n)
97 repo.changelog.parents(n)
99 timer(d)
98 timer(d)
100
99
101 def perflookup(ui, repo, rev):
100 def perflookup(ui, repo, rev):
102 timer(lambda: len(repo.lookup(rev)))
101 timer(lambda: len(repo.lookup(rev)))
103
102
104 def perflog(ui, repo):
103 def perflog(ui, repo):
105 ui.pushbuffer()
104 ui.pushbuffer()
106 timer(lambda: commands.log(ui, repo, rev=[], date='', user=''))
105 timer(lambda: commands.log(ui, repo, rev=[], date='', user=''))
107 ui.popbuffer()
106 ui.popbuffer()
108
107
109 def perftemplating(ui, repo):
108 def perftemplating(ui, repo):
110 ui.pushbuffer()
109 ui.pushbuffer()
111 timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
110 timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
112 template='{date|shortdate} [{rev}:{node|short}]'
111 template='{date|shortdate} [{rev}:{node|short}]'
113 ' {author|person}: {desc|firstline}\n'))
112 ' {author|person}: {desc|firstline}\n'))
114 ui.popbuffer()
113 ui.popbuffer()
115
114
116 cmdtable = {
115 cmdtable = {
117 'perflookup': (perflookup, []),
116 'perflookup': (perflookup, []),
118 'perfparents': (perfparents, []),
117 'perfparents': (perfparents, []),
119 'perfstartup': (perfstartup, []),
118 'perfstartup': (perfstartup, []),
120 'perfstatus': (perfstatus, []),
119 'perfstatus': (perfstatus, []),
121 'perfwalk': (perfwalk, []),
120 'perfwalk': (perfwalk, []),
122 'perfmanifest': (perfmanifest, []),
121 'perfmanifest': (perfmanifest, []),
123 'perfindex': (perfindex, []),
122 'perfindex': (perfindex, []),
124 'perfheads': (perfheads, []),
123 'perfheads': (perfheads, []),
125 'perftags': (perftags, []),
124 'perftags': (perftags, []),
126 'perfdirstate': (perfdirstate, []),
125 'perfdirstate': (perfdirstate, []),
127 'perfdirstatedirs': (perfdirstate, []),
126 'perfdirstatedirs': (perfdirstate, []),
128 'perflog': (perflog, []),
127 'perflog': (perflog, []),
129 'perftemplating': (perftemplating, []),
128 'perftemplating': (perftemplating, []),
130 }
129 }
131
130
@@ -1,368 +1,368 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, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 import base64, errno
8 import base64, errno
9 import os
9 import os
10 import cPickle as pickle
10 import cPickle as pickle
11 from mercurial import util, strutil
11 from mercurial import util
12 from mercurial.i18n import _
12 from mercurial.i18n import _
13
13
14 def encodeargs(args):
14 def encodeargs(args):
15 def encodearg(s):
15 def encodearg(s):
16 lines = base64.encodestring(s)
16 lines = base64.encodestring(s)
17 lines = [l.splitlines()[0] for l in lines]
17 lines = [l.splitlines()[0] for l in lines]
18 return ''.join(lines)
18 return ''.join(lines)
19
19
20 s = pickle.dumps(args)
20 s = pickle.dumps(args)
21 return encodearg(s)
21 return encodearg(s)
22
22
23 def decodeargs(s):
23 def decodeargs(s):
24 s = base64.decodestring(s)
24 s = base64.decodestring(s)
25 return pickle.loads(s)
25 return pickle.loads(s)
26
26
27 class MissingTool(Exception): pass
27 class MissingTool(Exception): pass
28
28
29 def checktool(exe, name=None, abort=True):
29 def checktool(exe, name=None, abort=True):
30 name = name or exe
30 name = name or exe
31 if not util.find_exe(exe):
31 if not util.find_exe(exe):
32 exc = abort and util.Abort or MissingTool
32 exc = abort and util.Abort or MissingTool
33 raise exc(_('cannot find required "%s" tool') % name)
33 raise exc(_('cannot find required "%s" tool') % name)
34
34
35 class NoRepo(Exception): pass
35 class NoRepo(Exception): pass
36
36
37 SKIPREV = 'SKIP'
37 SKIPREV = 'SKIP'
38
38
39 class commit(object):
39 class commit(object):
40 def __init__(self, author, date, desc, parents, branch=None, rev=None,
40 def __init__(self, author, date, desc, parents, branch=None, rev=None,
41 extra={}):
41 extra={}):
42 self.author = author or 'unknown'
42 self.author = author or 'unknown'
43 self.date = date or '0 0'
43 self.date = date or '0 0'
44 self.desc = desc
44 self.desc = desc
45 self.parents = parents
45 self.parents = parents
46 self.branch = branch
46 self.branch = branch
47 self.rev = rev
47 self.rev = rev
48 self.extra = extra
48 self.extra = extra
49
49
50 class converter_source(object):
50 class converter_source(object):
51 """Conversion source interface"""
51 """Conversion source interface"""
52
52
53 def __init__(self, ui, path=None, rev=None):
53 def __init__(self, ui, path=None, rev=None):
54 """Initialize conversion source (or raise NoRepo("message")
54 """Initialize conversion source (or raise NoRepo("message")
55 exception if path is not a valid repository)"""
55 exception if path is not a valid repository)"""
56 self.ui = ui
56 self.ui = ui
57 self.path = path
57 self.path = path
58 self.rev = rev
58 self.rev = rev
59
59
60 self.encoding = 'utf-8'
60 self.encoding = 'utf-8'
61
61
62 def before(self):
62 def before(self):
63 pass
63 pass
64
64
65 def after(self):
65 def after(self):
66 pass
66 pass
67
67
68 def setrevmap(self, revmap):
68 def setrevmap(self, revmap):
69 """set the map of already-converted revisions"""
69 """set the map of already-converted revisions"""
70 pass
70 pass
71
71
72 def getheads(self):
72 def getheads(self):
73 """Return a list of this repository's heads"""
73 """Return a list of this repository's heads"""
74 raise NotImplementedError()
74 raise NotImplementedError()
75
75
76 def getfile(self, name, rev):
76 def getfile(self, name, rev):
77 """Return file contents as a string. rev is the identifier returned
77 """Return file contents as a string. rev is the identifier returned
78 by a previous call to getchanges(). Raise IOError to indicate that
78 by a previous call to getchanges(). Raise IOError to indicate that
79 name was deleted in rev.
79 name was deleted in rev.
80 """
80 """
81 raise NotImplementedError()
81 raise NotImplementedError()
82
82
83 def getmode(self, name, rev):
83 def getmode(self, name, rev):
84 """Return file mode, eg. '', 'x', or 'l'. rev is the identifier
84 """Return file mode, eg. '', 'x', or 'l'. rev is the identifier
85 returned by a previous call to getchanges().
85 returned by a previous call to getchanges().
86 """
86 """
87 raise NotImplementedError()
87 raise NotImplementedError()
88
88
89 def getchanges(self, version):
89 def getchanges(self, version):
90 """Returns a tuple of (files, copies).
90 """Returns a tuple of (files, copies).
91
91
92 files is a sorted list of (filename, id) tuples for all files
92 files is a sorted list of (filename, id) tuples for all files
93 changed between version and its first parent returned by
93 changed between version and its first parent returned by
94 getcommit(). id is the source revision id of the file.
94 getcommit(). id is the source revision id of the file.
95
95
96 copies is a dictionary of dest: source
96 copies is a dictionary of dest: source
97 """
97 """
98 raise NotImplementedError()
98 raise NotImplementedError()
99
99
100 def getcommit(self, version):
100 def getcommit(self, version):
101 """Return the commit object for version"""
101 """Return the commit object for version"""
102 raise NotImplementedError()
102 raise NotImplementedError()
103
103
104 def gettags(self):
104 def gettags(self):
105 """Return the tags as a dictionary of name: revision"""
105 """Return the tags as a dictionary of name: revision"""
106 raise NotImplementedError()
106 raise NotImplementedError()
107
107
108 def recode(self, s, encoding=None):
108 def recode(self, s, encoding=None):
109 if not encoding:
109 if not encoding:
110 encoding = self.encoding or 'utf-8'
110 encoding = self.encoding or 'utf-8'
111
111
112 if isinstance(s, unicode):
112 if isinstance(s, unicode):
113 return s.encode("utf-8")
113 return s.encode("utf-8")
114 try:
114 try:
115 return s.decode(encoding).encode("utf-8")
115 return s.decode(encoding).encode("utf-8")
116 except:
116 except:
117 try:
117 try:
118 return s.decode("latin-1").encode("utf-8")
118 return s.decode("latin-1").encode("utf-8")
119 except:
119 except:
120 return s.decode(encoding, "replace").encode("utf-8")
120 return s.decode(encoding, "replace").encode("utf-8")
121
121
122 def getchangedfiles(self, rev, i):
122 def getchangedfiles(self, rev, i):
123 """Return the files changed by rev compared to parent[i].
123 """Return the files changed by rev compared to parent[i].
124
124
125 i is an index selecting one of the parents of rev. The return
125 i is an index selecting one of the parents of rev. The return
126 value should be the list of files that are different in rev and
126 value should be the list of files that are different in rev and
127 this parent.
127 this parent.
128
128
129 If rev has no parents, i is None.
129 If rev has no parents, i is None.
130
130
131 This function is only needed to support --filemap
131 This function is only needed to support --filemap
132 """
132 """
133 raise NotImplementedError()
133 raise NotImplementedError()
134
134
135 def converted(self, rev, sinkrev):
135 def converted(self, rev, sinkrev):
136 '''Notify the source that a revision has been converted.'''
136 '''Notify the source that a revision has been converted.'''
137 pass
137 pass
138
138
139
139
140 class converter_sink(object):
140 class converter_sink(object):
141 """Conversion sink (target) interface"""
141 """Conversion sink (target) interface"""
142
142
143 def __init__(self, ui, path):
143 def __init__(self, ui, path):
144 """Initialize conversion sink (or raise NoRepo("message")
144 """Initialize conversion sink (or raise NoRepo("message")
145 exception if path is not a valid repository)
145 exception if path is not a valid repository)
146
146
147 created is a list of paths to remove if a fatal error occurs
147 created is a list of paths to remove if a fatal error occurs
148 later"""
148 later"""
149 self.ui = ui
149 self.ui = ui
150 self.path = path
150 self.path = path
151 self.created = []
151 self.created = []
152
152
153 def getheads(self):
153 def getheads(self):
154 """Return a list of this repository's heads"""
154 """Return a list of this repository's heads"""
155 raise NotImplementedError()
155 raise NotImplementedError()
156
156
157 def revmapfile(self):
157 def revmapfile(self):
158 """Path to a file that will contain lines
158 """Path to a file that will contain lines
159 source_rev_id sink_rev_id
159 source_rev_id sink_rev_id
160 mapping equivalent revision identifiers for each system."""
160 mapping equivalent revision identifiers for each system."""
161 raise NotImplementedError()
161 raise NotImplementedError()
162
162
163 def authorfile(self):
163 def authorfile(self):
164 """Path to a file that will contain lines
164 """Path to a file that will contain lines
165 srcauthor=dstauthor
165 srcauthor=dstauthor
166 mapping equivalent authors identifiers for each system."""
166 mapping equivalent authors identifiers for each system."""
167 return None
167 return None
168
168
169 def putcommit(self, files, copies, parents, commit, source):
169 def putcommit(self, files, copies, parents, commit, source):
170 """Create a revision with all changed files listed in 'files'
170 """Create a revision with all changed files listed in 'files'
171 and having listed parents. 'commit' is a commit object containing
171 and having listed parents. 'commit' is a commit object containing
172 at a minimum the author, date, and message for this changeset.
172 at a minimum the author, date, and message for this changeset.
173 'files' is a list of (path, version) tuples, 'copies'is a dictionary
173 'files' is a list of (path, version) tuples, 'copies'is a dictionary
174 mapping destinations to sources, and 'source' is the source repository.
174 mapping destinations to sources, and 'source' is the source repository.
175 Only getfile() and getmode() should be called on 'source'.
175 Only getfile() and getmode() should be called on 'source'.
176
176
177 Note that the sink repository is not told to update itself to
177 Note that the sink repository is not told to update itself to
178 a particular revision (or even what that revision would be)
178 a particular revision (or even what that revision would be)
179 before it receives the file data.
179 before it receives the file data.
180 """
180 """
181 raise NotImplementedError()
181 raise NotImplementedError()
182
182
183 def puttags(self, tags):
183 def puttags(self, tags):
184 """Put tags into sink.
184 """Put tags into sink.
185 tags: {tagname: sink_rev_id, ...}"""
185 tags: {tagname: sink_rev_id, ...}"""
186 raise NotImplementedError()
186 raise NotImplementedError()
187
187
188 def setbranch(self, branch, pbranches):
188 def setbranch(self, branch, pbranches):
189 """Set the current branch name. Called before the first putcommit
189 """Set the current branch name. Called before the first putcommit
190 on the branch.
190 on the branch.
191 branch: branch name for subsequent commits
191 branch: branch name for subsequent commits
192 pbranches: (converted parent revision, parent branch) tuples"""
192 pbranches: (converted parent revision, parent branch) tuples"""
193 pass
193 pass
194
194
195 def setfilemapmode(self, active):
195 def setfilemapmode(self, active):
196 """Tell the destination that we're using a filemap
196 """Tell the destination that we're using a filemap
197
197
198 Some converter_sources (svn in particular) can claim that a file
198 Some converter_sources (svn in particular) can claim that a file
199 was changed in a revision, even if there was no change. This method
199 was changed in a revision, even if there was no change. This method
200 tells the destination that we're using a filemap and that it should
200 tells the destination that we're using a filemap and that it should
201 filter empty revisions.
201 filter empty revisions.
202 """
202 """
203 pass
203 pass
204
204
205 def before(self):
205 def before(self):
206 pass
206 pass
207
207
208 def after(self):
208 def after(self):
209 pass
209 pass
210
210
211
211
212 class commandline(object):
212 class commandline(object):
213 def __init__(self, ui, command):
213 def __init__(self, ui, command):
214 self.ui = ui
214 self.ui = ui
215 self.command = command
215 self.command = command
216
216
217 def prerun(self):
217 def prerun(self):
218 pass
218 pass
219
219
220 def postrun(self):
220 def postrun(self):
221 pass
221 pass
222
222
223 def _cmdline(self, cmd, *args, **kwargs):
223 def _cmdline(self, cmd, *args, **kwargs):
224 cmdline = [self.command, cmd] + list(args)
224 cmdline = [self.command, cmd] + list(args)
225 for k, v in kwargs.iteritems():
225 for k, v in kwargs.iteritems():
226 if len(k) == 1:
226 if len(k) == 1:
227 cmdline.append('-' + k)
227 cmdline.append('-' + k)
228 else:
228 else:
229 cmdline.append('--' + k.replace('_', '-'))
229 cmdline.append('--' + k.replace('_', '-'))
230 try:
230 try:
231 if len(k) == 1:
231 if len(k) == 1:
232 cmdline.append('' + v)
232 cmdline.append('' + v)
233 else:
233 else:
234 cmdline[-1] += '=' + v
234 cmdline[-1] += '=' + v
235 except TypeError:
235 except TypeError:
236 pass
236 pass
237 cmdline = [util.shellquote(arg) for arg in cmdline]
237 cmdline = [util.shellquote(arg) for arg in cmdline]
238 if not self.ui.debugflag:
238 if not self.ui.debugflag:
239 cmdline += ['2>', util.nulldev]
239 cmdline += ['2>', util.nulldev]
240 cmdline += ['<', util.nulldev]
240 cmdline += ['<', util.nulldev]
241 cmdline = ' '.join(cmdline)
241 cmdline = ' '.join(cmdline)
242 return cmdline
242 return cmdline
243
243
244 def _run(self, cmd, *args, **kwargs):
244 def _run(self, cmd, *args, **kwargs):
245 cmdline = self._cmdline(cmd, *args, **kwargs)
245 cmdline = self._cmdline(cmd, *args, **kwargs)
246 self.ui.debug(_('running: %s\n') % (cmdline,))
246 self.ui.debug(_('running: %s\n') % (cmdline,))
247 self.prerun()
247 self.prerun()
248 try:
248 try:
249 return util.popen(cmdline)
249 return util.popen(cmdline)
250 finally:
250 finally:
251 self.postrun()
251 self.postrun()
252
252
253 def run(self, cmd, *args, **kwargs):
253 def run(self, cmd, *args, **kwargs):
254 fp = self._run(cmd, *args, **kwargs)
254 fp = self._run(cmd, *args, **kwargs)
255 output = fp.read()
255 output = fp.read()
256 self.ui.debug(output)
256 self.ui.debug(output)
257 return output, fp.close()
257 return output, fp.close()
258
258
259 def runlines(self, cmd, *args, **kwargs):
259 def runlines(self, cmd, *args, **kwargs):
260 fp = self._run(cmd, *args, **kwargs)
260 fp = self._run(cmd, *args, **kwargs)
261 output = fp.readlines()
261 output = fp.readlines()
262 self.ui.debug(''.join(output))
262 self.ui.debug(''.join(output))
263 return output, fp.close()
263 return output, fp.close()
264
264
265 def checkexit(self, status, output=''):
265 def checkexit(self, status, output=''):
266 if status:
266 if status:
267 if output:
267 if output:
268 self.ui.warn(_('%s error:\n') % self.command)
268 self.ui.warn(_('%s error:\n') % self.command)
269 self.ui.warn(output)
269 self.ui.warn(output)
270 msg = util.explain_exit(status)[0]
270 msg = util.explain_exit(status)[0]
271 raise util.Abort(_('%s %s') % (self.command, msg))
271 raise util.Abort(_('%s %s') % (self.command, msg))
272
272
273 def run0(self, cmd, *args, **kwargs):
273 def run0(self, cmd, *args, **kwargs):
274 output, status = self.run(cmd, *args, **kwargs)
274 output, status = self.run(cmd, *args, **kwargs)
275 self.checkexit(status, output)
275 self.checkexit(status, output)
276 return output
276 return output
277
277
278 def runlines0(self, cmd, *args, **kwargs):
278 def runlines0(self, cmd, *args, **kwargs):
279 output, status = self.runlines(cmd, *args, **kwargs)
279 output, status = self.runlines(cmd, *args, **kwargs)
280 self.checkexit(status, ''.join(output))
280 self.checkexit(status, ''.join(output))
281 return output
281 return output
282
282
283 def getargmax(self):
283 def getargmax(self):
284 if '_argmax' in self.__dict__:
284 if '_argmax' in self.__dict__:
285 return self._argmax
285 return self._argmax
286
286
287 # POSIX requires at least 4096 bytes for ARG_MAX
287 # POSIX requires at least 4096 bytes for ARG_MAX
288 self._argmax = 4096
288 self._argmax = 4096
289 try:
289 try:
290 self._argmax = os.sysconf("SC_ARG_MAX")
290 self._argmax = os.sysconf("SC_ARG_MAX")
291 except:
291 except:
292 pass
292 pass
293
293
294 # Windows shells impose their own limits on command line length,
294 # Windows shells impose their own limits on command line length,
295 # down to 2047 bytes for cmd.exe under Windows NT/2k and 2500 bytes
295 # down to 2047 bytes for cmd.exe under Windows NT/2k and 2500 bytes
296 # for older 4nt.exe. See http://support.microsoft.com/kb/830473 for
296 # for older 4nt.exe. See http://support.microsoft.com/kb/830473 for
297 # details about cmd.exe limitations.
297 # details about cmd.exe limitations.
298
298
299 # Since ARG_MAX is for command line _and_ environment, lower our limit
299 # Since ARG_MAX is for command line _and_ environment, lower our limit
300 # (and make happy Windows shells while doing this).
300 # (and make happy Windows shells while doing this).
301
301
302 self._argmax = self._argmax/2 - 1
302 self._argmax = self._argmax/2 - 1
303 return self._argmax
303 return self._argmax
304
304
305 def limit_arglist(self, arglist, cmd, *args, **kwargs):
305 def limit_arglist(self, arglist, cmd, *args, **kwargs):
306 limit = self.getargmax() - len(self._cmdline(cmd, *args, **kwargs))
306 limit = self.getargmax() - len(self._cmdline(cmd, *args, **kwargs))
307 bytes = 0
307 bytes = 0
308 fl = []
308 fl = []
309 for fn in arglist:
309 for fn in arglist:
310 b = len(fn) + 3
310 b = len(fn) + 3
311 if bytes + b < limit or len(fl) == 0:
311 if bytes + b < limit or len(fl) == 0:
312 fl.append(fn)
312 fl.append(fn)
313 bytes += b
313 bytes += b
314 else:
314 else:
315 yield fl
315 yield fl
316 fl = [fn]
316 fl = [fn]
317 bytes = b
317 bytes = b
318 if fl:
318 if fl:
319 yield fl
319 yield fl
320
320
321 def xargs(self, arglist, cmd, *args, **kwargs):
321 def xargs(self, arglist, cmd, *args, **kwargs):
322 for l in self.limit_arglist(arglist, cmd, *args, **kwargs):
322 for l in self.limit_arglist(arglist, cmd, *args, **kwargs):
323 self.run0(cmd, *(list(args) + l), **kwargs)
323 self.run0(cmd, *(list(args) + l), **kwargs)
324
324
325 class mapfile(dict):
325 class mapfile(dict):
326 def __init__(self, ui, path):
326 def __init__(self, ui, path):
327 super(mapfile, self).__init__()
327 super(mapfile, self).__init__()
328 self.ui = ui
328 self.ui = ui
329 self.path = path
329 self.path = path
330 self.fp = None
330 self.fp = None
331 self.order = []
331 self.order = []
332 self._read()
332 self._read()
333
333
334 def _read(self):
334 def _read(self):
335 if not self.path:
335 if not self.path:
336 return
336 return
337 try:
337 try:
338 fp = open(self.path, 'r')
338 fp = open(self.path, 'r')
339 except IOError, err:
339 except IOError, err:
340 if err.errno != errno.ENOENT:
340 if err.errno != errno.ENOENT:
341 raise
341 raise
342 return
342 return
343 for i, line in enumerate(fp):
343 for i, line in enumerate(fp):
344 try:
344 try:
345 key, value = line[:-1].rsplit(' ', 1)
345 key, value = line[:-1].rsplit(' ', 1)
346 except ValueError:
346 except ValueError:
347 raise util.Abort(_('syntax error in %s(%d): key/value pair expected')
347 raise util.Abort(_('syntax error in %s(%d): key/value pair expected')
348 % (self.path, i+1))
348 % (self.path, i+1))
349 if key not in self:
349 if key not in self:
350 self.order.append(key)
350 self.order.append(key)
351 super(mapfile, self).__setitem__(key, value)
351 super(mapfile, self).__setitem__(key, value)
352 fp.close()
352 fp.close()
353
353
354 def __setitem__(self, key, value):
354 def __setitem__(self, key, value):
355 if self.fp is None:
355 if self.fp is None:
356 try:
356 try:
357 self.fp = open(self.path, 'a')
357 self.fp = open(self.path, 'a')
358 except IOError, err:
358 except IOError, err:
359 raise util.Abort(_('could not open map file %r: %s') %
359 raise util.Abort(_('could not open map file %r: %s') %
360 (self.path, err.strerror))
360 (self.path, err.strerror))
361 self.fp.write('%s %s\n' % (key, value))
361 self.fp.write('%s %s\n' % (key, value))
362 self.fp.flush()
362 self.fp.flush()
363 super(mapfile, self).__setitem__(key, value)
363 super(mapfile, self).__setitem__(key, value)
364
364
365 def close(self):
365 def close(self):
366 if self.fp:
366 if self.fp:
367 self.fp.close()
367 self.fp.close()
368 self.fp = None
368 self.fp = None
@@ -1,110 +1,110 b''
1 # __init__.py - inotify-based status acceleration for Linux
1 # __init__.py - inotify-based status acceleration for Linux
2 #
2 #
3 # Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com>
3 # Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com>
4 # Copyright 2007, 2008 Brendan Cully <brendan@kublai.com>
4 # Copyright 2007, 2008 Brendan Cully <brendan@kublai.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2, incorporated herein by reference.
7 # GNU General Public License version 2, incorporated herein by reference.
8
8
9 '''inotify-based status acceleration for Linux systems
9 '''inotify-based status acceleration for Linux systems
10 '''
10 '''
11
11
12 # todo: socket permissions
12 # todo: socket permissions
13
13
14 from mercurial.i18n import _
14 from mercurial.i18n import _
15 from mercurial import cmdutil, util
15 from mercurial import cmdutil, util
16 import os, server
16 import server
17 from weakref import proxy
17 from weakref import proxy
18 from client import client, QueryFailed
18 from client import client, QueryFailed
19
19
20 def serve(ui, repo, **opts):
20 def serve(ui, repo, **opts):
21 '''start an inotify server for this repository'''
21 '''start an inotify server for this repository'''
22 timeout = opts.get('timeout')
22 timeout = opts.get('timeout')
23 if timeout:
23 if timeout:
24 timeout = float(timeout) * 1e3
24 timeout = float(timeout) * 1e3
25
25
26 class service:
26 class service:
27 def init(self):
27 def init(self):
28 try:
28 try:
29 self.master = server.master(ui, repo, timeout)
29 self.master = server.master(ui, repo, timeout)
30 except server.AlreadyStartedException, inst:
30 except server.AlreadyStartedException, inst:
31 raise util.Abort(str(inst))
31 raise util.Abort(str(inst))
32
32
33 def run(self):
33 def run(self):
34 try:
34 try:
35 self.master.run()
35 self.master.run()
36 finally:
36 finally:
37 self.master.shutdown()
37 self.master.shutdown()
38
38
39 service = service()
39 service = service()
40 cmdutil.service(opts, initfn=service.init, runfn=service.run)
40 cmdutil.service(opts, initfn=service.init, runfn=service.run)
41
41
42 def debuginotify(ui, repo, **opts):
42 def debuginotify(ui, repo, **opts):
43 '''debugging information for inotify extension
43 '''debugging information for inotify extension
44
44
45 Prints the list of directories being watched by the inotify server.
45 Prints the list of directories being watched by the inotify server.
46 '''
46 '''
47 cli = client(ui, repo)
47 cli = client(ui, repo)
48 response = cli.debugquery()
48 response = cli.debugquery()
49
49
50 ui.write(_('directories being watched:\n'))
50 ui.write(_('directories being watched:\n'))
51 for path in response:
51 for path in response:
52 ui.write((' %s/\n') % path)
52 ui.write((' %s/\n') % path)
53
53
54 def reposetup(ui, repo):
54 def reposetup(ui, repo):
55 if not hasattr(repo, 'dirstate'):
55 if not hasattr(repo, 'dirstate'):
56 return
56 return
57
57
58 # XXX: weakref until hg stops relying on __del__
58 # XXX: weakref until hg stops relying on __del__
59 repo = proxy(repo)
59 repo = proxy(repo)
60
60
61 class inotifydirstate(repo.dirstate.__class__):
61 class inotifydirstate(repo.dirstate.__class__):
62
62
63 # We'll set this to false after an unsuccessful attempt so that
63 # We'll set this to false after an unsuccessful attempt so that
64 # next calls of status() within the same instance don't try again
64 # next calls of status() within the same instance don't try again
65 # to start an inotify server if it won't start.
65 # to start an inotify server if it won't start.
66 _inotifyon = True
66 _inotifyon = True
67
67
68 def status(self, match, ignored, clean, unknown=True):
68 def status(self, match, ignored, clean, unknown=True):
69 files = match.files()
69 files = match.files()
70 if '.' in files:
70 if '.' in files:
71 files = []
71 files = []
72 if self._inotifyon and not ignored:
72 if self._inotifyon and not ignored:
73 cli = client(ui, repo)
73 cli = client(ui, repo)
74 try:
74 try:
75 result = cli.statusquery(files, match, False,
75 result = cli.statusquery(files, match, False,
76 clean, unknown)
76 clean, unknown)
77 except QueryFailed, instr:
77 except QueryFailed, instr:
78 ui.debug(str(instr))
78 ui.debug(str(instr))
79 # don't retry within the same hg instance
79 # don't retry within the same hg instance
80 inotifydirstate._inotifyon = False
80 inotifydirstate._inotifyon = False
81 pass
81 pass
82 else:
82 else:
83 if ui.config('inotify', 'debug'):
83 if ui.config('inotify', 'debug'):
84 r2 = super(inotifydirstate, self).status(
84 r2 = super(inotifydirstate, self).status(
85 match, False, clean, unknown)
85 match, False, clean, unknown)
86 for c,a,b in zip('LMARDUIC', result, r2):
86 for c,a,b in zip('LMARDUIC', result, r2):
87 for f in a:
87 for f in a:
88 if f not in b:
88 if f not in b:
89 ui.warn('*** inotify: %s +%s\n' % (c, f))
89 ui.warn('*** inotify: %s +%s\n' % (c, f))
90 for f in b:
90 for f in b:
91 if f not in a:
91 if f not in a:
92 ui.warn('*** inotify: %s -%s\n' % (c, f))
92 ui.warn('*** inotify: %s -%s\n' % (c, f))
93 result = r2
93 result = r2
94 return result
94 return result
95 return super(inotifydirstate, self).status(
95 return super(inotifydirstate, self).status(
96 match, ignored, clean, unknown)
96 match, ignored, clean, unknown)
97
97
98 repo.dirstate.__class__ = inotifydirstate
98 repo.dirstate.__class__ = inotifydirstate
99
99
100 cmdtable = {
100 cmdtable = {
101 'debuginotify':
101 'debuginotify':
102 (debuginotify, [], ('hg debuginotify')),
102 (debuginotify, [], ('hg debuginotify')),
103 '^inserve':
103 '^inserve':
104 (serve,
104 (serve,
105 [('d', 'daemon', None, _('run server in background')),
105 [('d', 'daemon', None, _('run server in background')),
106 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
106 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
107 ('t', 'idle-timeout', '', _('minutes to sit idle before exiting')),
107 ('t', 'idle-timeout', '', _('minutes to sit idle before exiting')),
108 ('', 'pid-file', '', _('name of file to write process ID to'))],
108 ('', 'pid-file', '', _('name of file to write process ID to'))],
109 _('hg inserve [OPT]...')),
109 _('hg inserve [OPT]...')),
110 }
110 }
@@ -1,346 +1,346 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
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, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import errno, getpass, os, re, socket, sys, tempfile, traceback
9 import errno, getpass, os, socket, sys, tempfile, traceback
10 import config, util, error
10 import config, util, error
11
11
12 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True,
12 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True,
13 '0': False, 'no': False, 'false': False, 'off': False}
13 '0': False, 'no': False, 'false': False, 'off': False}
14
14
15 class ui(object):
15 class ui(object):
16 def __init__(self, src=None):
16 def __init__(self, src=None):
17 self._buffers = []
17 self._buffers = []
18 self.quiet = self.verbose = self.debugflag = self._traceback = False
18 self.quiet = self.verbose = self.debugflag = self._traceback = False
19 self._reportuntrusted = True
19 self._reportuntrusted = True
20 self._ocfg = config.config() # overlay
20 self._ocfg = config.config() # overlay
21 self._tcfg = config.config() # trusted
21 self._tcfg = config.config() # trusted
22 self._ucfg = config.config() # untrusted
22 self._ucfg = config.config() # untrusted
23 self._trustusers = set()
23 self._trustusers = set()
24 self._trustgroups = set()
24 self._trustgroups = set()
25
25
26 if src:
26 if src:
27 self._tcfg = src._tcfg.copy()
27 self._tcfg = src._tcfg.copy()
28 self._ucfg = src._ucfg.copy()
28 self._ucfg = src._ucfg.copy()
29 self._ocfg = src._ocfg.copy()
29 self._ocfg = src._ocfg.copy()
30 self._trustusers = src._trustusers.copy()
30 self._trustusers = src._trustusers.copy()
31 self._trustgroups = src._trustgroups.copy()
31 self._trustgroups = src._trustgroups.copy()
32 self.fixconfig()
32 self.fixconfig()
33 else:
33 else:
34 # we always trust global config files
34 # we always trust global config files
35 for f in util.rcpath():
35 for f in util.rcpath():
36 self.readconfig(f, trust=True)
36 self.readconfig(f, trust=True)
37
37
38 def copy(self):
38 def copy(self):
39 return self.__class__(self)
39 return self.__class__(self)
40
40
41 def _is_trusted(self, fp, f):
41 def _is_trusted(self, fp, f):
42 st = util.fstat(fp)
42 st = util.fstat(fp)
43 if util.isowner(fp, st):
43 if util.isowner(fp, st):
44 return True
44 return True
45
45
46 tusers, tgroups = self._trustusers, self._trustgroups
46 tusers, tgroups = self._trustusers, self._trustgroups
47 if '*' in tusers or '*' in tgroups:
47 if '*' in tusers or '*' in tgroups:
48 return True
48 return True
49
49
50 user = util.username(st.st_uid)
50 user = util.username(st.st_uid)
51 group = util.groupname(st.st_gid)
51 group = util.groupname(st.st_gid)
52 if user in tusers or group in tgroups or user == util.username():
52 if user in tusers or group in tgroups or user == util.username():
53 return True
53 return True
54
54
55 if self._reportuntrusted:
55 if self._reportuntrusted:
56 self.warn(_('Not trusting file %s from untrusted '
56 self.warn(_('Not trusting file %s from untrusted '
57 'user %s, group %s\n') % (f, user, group))
57 'user %s, group %s\n') % (f, user, group))
58 return False
58 return False
59
59
60 def readconfig(self, filename, root=None, trust=False,
60 def readconfig(self, filename, root=None, trust=False,
61 sections=None, remap=None):
61 sections=None, remap=None):
62 try:
62 try:
63 fp = open(filename)
63 fp = open(filename)
64 except IOError:
64 except IOError:
65 if not sections: # ignore unless we were looking for something
65 if not sections: # ignore unless we were looking for something
66 return
66 return
67 raise
67 raise
68
68
69 cfg = config.config()
69 cfg = config.config()
70 trusted = sections or trust or self._is_trusted(fp, filename)
70 trusted = sections or trust or self._is_trusted(fp, filename)
71
71
72 try:
72 try:
73 cfg.read(filename, fp, sections=sections, remap=remap)
73 cfg.read(filename, fp, sections=sections, remap=remap)
74 except error.ConfigError, inst:
74 except error.ConfigError, inst:
75 if trusted:
75 if trusted:
76 raise
76 raise
77 self.warn(_("Ignored: %s\n") % str(inst))
77 self.warn(_("Ignored: %s\n") % str(inst))
78
78
79 if trusted:
79 if trusted:
80 self._tcfg.update(cfg)
80 self._tcfg.update(cfg)
81 self._tcfg.update(self._ocfg)
81 self._tcfg.update(self._ocfg)
82 self._ucfg.update(cfg)
82 self._ucfg.update(cfg)
83 self._ucfg.update(self._ocfg)
83 self._ucfg.update(self._ocfg)
84
84
85 if root is None:
85 if root is None:
86 root = os.path.expanduser('~')
86 root = os.path.expanduser('~')
87 self.fixconfig(root=root)
87 self.fixconfig(root=root)
88
88
89 def fixconfig(self, root=None):
89 def fixconfig(self, root=None):
90 # translate paths relative to root (or home) into absolute paths
90 # translate paths relative to root (or home) into absolute paths
91 root = root or os.getcwd()
91 root = root or os.getcwd()
92 for c in self._tcfg, self._ucfg, self._ocfg:
92 for c in self._tcfg, self._ucfg, self._ocfg:
93 for n, p in c.items('paths'):
93 for n, p in c.items('paths'):
94 if p and "://" not in p and not os.path.isabs(p):
94 if p and "://" not in p and not os.path.isabs(p):
95 c.set("paths", n, os.path.normpath(os.path.join(root, p)))
95 c.set("paths", n, os.path.normpath(os.path.join(root, p)))
96
96
97 # update ui options
97 # update ui options
98 self.debugflag = self.configbool('ui', 'debug')
98 self.debugflag = self.configbool('ui', 'debug')
99 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
99 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
100 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
100 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
101 if self.verbose and self.quiet:
101 if self.verbose and self.quiet:
102 self.quiet = self.verbose = False
102 self.quiet = self.verbose = False
103 self._reportuntrusted = self.configbool("ui", "report_untrusted", True)
103 self._reportuntrusted = self.configbool("ui", "report_untrusted", True)
104 self._traceback = self.configbool('ui', 'traceback', False)
104 self._traceback = self.configbool('ui', 'traceback', False)
105
105
106 # update trust information
106 # update trust information
107 self._trustusers.update(self.configlist('trusted', 'users'))
107 self._trustusers.update(self.configlist('trusted', 'users'))
108 self._trustgroups.update(self.configlist('trusted', 'groups'))
108 self._trustgroups.update(self.configlist('trusted', 'groups'))
109
109
110 def setconfig(self, section, name, value):
110 def setconfig(self, section, name, value):
111 for cfg in (self._ocfg, self._tcfg, self._ucfg):
111 for cfg in (self._ocfg, self._tcfg, self._ucfg):
112 cfg.set(section, name, value)
112 cfg.set(section, name, value)
113 self.fixconfig()
113 self.fixconfig()
114
114
115 def _data(self, untrusted):
115 def _data(self, untrusted):
116 return untrusted and self._ucfg or self._tcfg
116 return untrusted and self._ucfg or self._tcfg
117
117
118 def configsource(self, section, name, untrusted=False):
118 def configsource(self, section, name, untrusted=False):
119 return self._data(untrusted).source(section, name) or 'none'
119 return self._data(untrusted).source(section, name) or 'none'
120
120
121 def config(self, section, name, default=None, untrusted=False):
121 def config(self, section, name, default=None, untrusted=False):
122 value = self._data(untrusted).get(section, name, default)
122 value = self._data(untrusted).get(section, name, default)
123 if self.debugflag and not untrusted and self._reportuntrusted:
123 if self.debugflag and not untrusted and self._reportuntrusted:
124 uvalue = self._ucfg.get(section, name)
124 uvalue = self._ucfg.get(section, name)
125 if uvalue is not None and uvalue != value:
125 if uvalue is not None and uvalue != value:
126 self.debug(_("ignoring untrusted configuration option "
126 self.debug(_("ignoring untrusted configuration option "
127 "%s.%s = %s\n") % (section, name, uvalue))
127 "%s.%s = %s\n") % (section, name, uvalue))
128 return value
128 return value
129
129
130 def configbool(self, section, name, default=False, untrusted=False):
130 def configbool(self, section, name, default=False, untrusted=False):
131 v = self.config(section, name, None, untrusted)
131 v = self.config(section, name, None, untrusted)
132 if v is None:
132 if v is None:
133 return default
133 return default
134 if v.lower() not in _booleans:
134 if v.lower() not in _booleans:
135 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
135 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
136 % (section, name, v))
136 % (section, name, v))
137 return _booleans[v.lower()]
137 return _booleans[v.lower()]
138
138
139 def configlist(self, section, name, default=None, untrusted=False):
139 def configlist(self, section, name, default=None, untrusted=False):
140 """Return a list of comma/space separated strings"""
140 """Return a list of comma/space separated strings"""
141 result = self.config(section, name, untrusted=untrusted)
141 result = self.config(section, name, untrusted=untrusted)
142 if result is None:
142 if result is None:
143 result = default or []
143 result = default or []
144 if isinstance(result, basestring):
144 if isinstance(result, basestring):
145 result = result.replace(",", " ").split()
145 result = result.replace(",", " ").split()
146 return result
146 return result
147
147
148 def has_section(self, section, untrusted=False):
148 def has_section(self, section, untrusted=False):
149 '''tell whether section exists in config.'''
149 '''tell whether section exists in config.'''
150 return section in self._data(untrusted)
150 return section in self._data(untrusted)
151
151
152 def configitems(self, section, untrusted=False):
152 def configitems(self, section, untrusted=False):
153 items = self._data(untrusted).items(section)
153 items = self._data(untrusted).items(section)
154 if self.debugflag and not untrusted and self._reportuntrusted:
154 if self.debugflag and not untrusted and self._reportuntrusted:
155 for k, v in self._ucfg.items(section):
155 for k, v in self._ucfg.items(section):
156 if self._tcfg.get(section, k) != v:
156 if self._tcfg.get(section, k) != v:
157 self.debug(_("ignoring untrusted configuration option "
157 self.debug(_("ignoring untrusted configuration option "
158 "%s.%s = %s\n") % (section, k, v))
158 "%s.%s = %s\n") % (section, k, v))
159 return items
159 return items
160
160
161 def walkconfig(self, untrusted=False):
161 def walkconfig(self, untrusted=False):
162 cfg = self._data(untrusted)
162 cfg = self._data(untrusted)
163 for section in cfg.sections():
163 for section in cfg.sections():
164 for name, value in self.configitems(section, untrusted):
164 for name, value in self.configitems(section, untrusted):
165 yield section, name, str(value).replace('\n', '\\n')
165 yield section, name, str(value).replace('\n', '\\n')
166
166
167 def username(self):
167 def username(self):
168 """Return default username to be used in commits.
168 """Return default username to be used in commits.
169
169
170 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
170 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
171 and stop searching if one of these is set.
171 and stop searching if one of these is set.
172 If not found and ui.askusername is True, ask the user, else use
172 If not found and ui.askusername is True, ask the user, else use
173 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
173 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
174 """
174 """
175 user = os.environ.get("HGUSER")
175 user = os.environ.get("HGUSER")
176 if user is None:
176 if user is None:
177 user = self.config("ui", "username")
177 user = self.config("ui", "username")
178 if user is None:
178 if user is None:
179 user = os.environ.get("EMAIL")
179 user = os.environ.get("EMAIL")
180 if user is None and self.configbool("ui", "askusername"):
180 if user is None and self.configbool("ui", "askusername"):
181 user = self.prompt(_("enter a commit username:"), default=None)
181 user = self.prompt(_("enter a commit username:"), default=None)
182 if user is None:
182 if user is None:
183 try:
183 try:
184 user = '%s@%s' % (util.getuser(), socket.getfqdn())
184 user = '%s@%s' % (util.getuser(), socket.getfqdn())
185 self.warn(_("No username found, using '%s' instead\n") % user)
185 self.warn(_("No username found, using '%s' instead\n") % user)
186 except KeyError:
186 except KeyError:
187 pass
187 pass
188 if not user:
188 if not user:
189 raise util.Abort(_("Please specify a username."))
189 raise util.Abort(_("Please specify a username."))
190 if "\n" in user:
190 if "\n" in user:
191 raise util.Abort(_("username %s contains a newline\n") % repr(user))
191 raise util.Abort(_("username %s contains a newline\n") % repr(user))
192 return user
192 return user
193
193
194 def shortuser(self, user):
194 def shortuser(self, user):
195 """Return a short representation of a user name or email address."""
195 """Return a short representation of a user name or email address."""
196 if not self.verbose: user = util.shortuser(user)
196 if not self.verbose: user = util.shortuser(user)
197 return user
197 return user
198
198
199 def _path(self, loc):
199 def _path(self, loc):
200 p = self.config('paths', loc)
200 p = self.config('paths', loc)
201 if p and '%%' in p:
201 if p and '%%' in p:
202 self.warn('(deprecated \'%%\' in path %s=%s from %s)\n' %
202 self.warn('(deprecated \'%%\' in path %s=%s from %s)\n' %
203 (loc, p, self.configsource('paths', loc)))
203 (loc, p, self.configsource('paths', loc)))
204 p = p.replace('%%', '%')
204 p = p.replace('%%', '%')
205 return p
205 return p
206
206
207 def expandpath(self, loc, default=None):
207 def expandpath(self, loc, default=None):
208 """Return repository location relative to cwd or from [paths]"""
208 """Return repository location relative to cwd or from [paths]"""
209 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
209 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
210 return loc
210 return loc
211
211
212 path = self._path(loc)
212 path = self._path(loc)
213 if not path and default is not None:
213 if not path and default is not None:
214 path = self._path(default)
214 path = self._path(default)
215 return path or loc
215 return path or loc
216
216
217 def pushbuffer(self):
217 def pushbuffer(self):
218 self._buffers.append([])
218 self._buffers.append([])
219
219
220 def popbuffer(self):
220 def popbuffer(self):
221 return "".join(self._buffers.pop())
221 return "".join(self._buffers.pop())
222
222
223 def write(self, *args):
223 def write(self, *args):
224 if self._buffers:
224 if self._buffers:
225 self._buffers[-1].extend([str(a) for a in args])
225 self._buffers[-1].extend([str(a) for a in args])
226 else:
226 else:
227 for a in args:
227 for a in args:
228 sys.stdout.write(str(a))
228 sys.stdout.write(str(a))
229
229
230 def write_err(self, *args):
230 def write_err(self, *args):
231 try:
231 try:
232 if not sys.stdout.closed: sys.stdout.flush()
232 if not sys.stdout.closed: sys.stdout.flush()
233 for a in args:
233 for a in args:
234 sys.stderr.write(str(a))
234 sys.stderr.write(str(a))
235 # stderr may be buffered under win32 when redirected to files,
235 # stderr may be buffered under win32 when redirected to files,
236 # including stdout.
236 # including stdout.
237 if not sys.stderr.closed: sys.stderr.flush()
237 if not sys.stderr.closed: sys.stderr.flush()
238 except IOError, inst:
238 except IOError, inst:
239 if inst.errno != errno.EPIPE:
239 if inst.errno != errno.EPIPE:
240 raise
240 raise
241
241
242 def flush(self):
242 def flush(self):
243 try: sys.stdout.flush()
243 try: sys.stdout.flush()
244 except: pass
244 except: pass
245 try: sys.stderr.flush()
245 try: sys.stderr.flush()
246 except: pass
246 except: pass
247
247
248 def interactive(self):
248 def interactive(self):
249 i = self.configbool("ui", "interactive", None)
249 i = self.configbool("ui", "interactive", None)
250 if i is None:
250 if i is None:
251 return sys.stdin.isatty()
251 return sys.stdin.isatty()
252 return i
252 return i
253
253
254 def _readline(self, prompt=''):
254 def _readline(self, prompt=''):
255 if sys.stdin.isatty():
255 if sys.stdin.isatty():
256 try:
256 try:
257 # magically add command line editing support, where
257 # magically add command line editing support, where
258 # available
258 # available
259 import readline
259 import readline
260 # force demandimport to really load the module
260 # force demandimport to really load the module
261 readline.read_history_file
261 readline.read_history_file
262 # windows sometimes raises something other than ImportError
262 # windows sometimes raises something other than ImportError
263 except Exception:
263 except Exception:
264 pass
264 pass
265 line = raw_input(prompt)
265 line = raw_input(prompt)
266 # When stdin is in binary mode on Windows, it can cause
266 # When stdin is in binary mode on Windows, it can cause
267 # raw_input() to emit an extra trailing carriage return
267 # raw_input() to emit an extra trailing carriage return
268 if os.linesep == '\r\n' and line and line[-1] == '\r':
268 if os.linesep == '\r\n' and line and line[-1] == '\r':
269 line = line[:-1]
269 line = line[:-1]
270 return line
270 return line
271
271
272 def prompt(self, msg, choices=None, default="y"):
272 def prompt(self, msg, choices=None, default="y"):
273 """Prompt user with msg, read response, and ensure it matches
273 """Prompt user with msg, read response, and ensure it matches
274 one of the provided choices. choices is a sequence of acceptable
274 one of the provided choices. choices is a sequence of acceptable
275 responses with the format: ('&None', 'E&xec', 'Sym&link')
275 responses with the format: ('&None', 'E&xec', 'Sym&link')
276 No sequence implies no response checking. Responses are case
276 No sequence implies no response checking. Responses are case
277 insensitive. If ui is not interactive, the default is returned.
277 insensitive. If ui is not interactive, the default is returned.
278 """
278 """
279 if not self.interactive():
279 if not self.interactive():
280 self.note(msg, ' ', default, "\n")
280 self.note(msg, ' ', default, "\n")
281 return default
281 return default
282 while True:
282 while True:
283 try:
283 try:
284 r = self._readline(msg + ' ')
284 r = self._readline(msg + ' ')
285 if not r:
285 if not r:
286 return default
286 return default
287 if not choices:
287 if not choices:
288 return r
288 return r
289 resps = [s[s.index('&')+1].lower() for s in choices]
289 resps = [s[s.index('&')+1].lower() for s in choices]
290 if r.lower() in resps:
290 if r.lower() in resps:
291 return r.lower()
291 return r.lower()
292 else:
292 else:
293 self.write(_("unrecognized response\n"))
293 self.write(_("unrecognized response\n"))
294 except EOFError:
294 except EOFError:
295 raise util.Abort(_('response expected'))
295 raise util.Abort(_('response expected'))
296
296
297 def getpass(self, prompt=None, default=None):
297 def getpass(self, prompt=None, default=None):
298 if not self.interactive(): return default
298 if not self.interactive(): return default
299 try:
299 try:
300 return getpass.getpass(prompt or _('password: '))
300 return getpass.getpass(prompt or _('password: '))
301 except EOFError:
301 except EOFError:
302 raise util.Abort(_('response expected'))
302 raise util.Abort(_('response expected'))
303 def status(self, *msg):
303 def status(self, *msg):
304 if not self.quiet: self.write(*msg)
304 if not self.quiet: self.write(*msg)
305 def warn(self, *msg):
305 def warn(self, *msg):
306 self.write_err(*msg)
306 self.write_err(*msg)
307 def note(self, *msg):
307 def note(self, *msg):
308 if self.verbose: self.write(*msg)
308 if self.verbose: self.write(*msg)
309 def debug(self, *msg):
309 def debug(self, *msg):
310 if self.debugflag: self.write(*msg)
310 if self.debugflag: self.write(*msg)
311 def edit(self, text, user):
311 def edit(self, text, user):
312 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
312 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
313 text=True)
313 text=True)
314 try:
314 try:
315 f = os.fdopen(fd, "w")
315 f = os.fdopen(fd, "w")
316 f.write(text)
316 f.write(text)
317 f.close()
317 f.close()
318
318
319 editor = self.geteditor()
319 editor = self.geteditor()
320
320
321 util.system("%s \"%s\"" % (editor, name),
321 util.system("%s \"%s\"" % (editor, name),
322 environ={'HGUSER': user},
322 environ={'HGUSER': user},
323 onerr=util.Abort, errprefix=_("edit failed"))
323 onerr=util.Abort, errprefix=_("edit failed"))
324
324
325 f = open(name)
325 f = open(name)
326 t = f.read()
326 t = f.read()
327 f.close()
327 f.close()
328 finally:
328 finally:
329 os.unlink(name)
329 os.unlink(name)
330
330
331 return t
331 return t
332
332
333 def traceback(self):
333 def traceback(self):
334 '''print exception traceback if traceback printing enabled.
334 '''print exception traceback if traceback printing enabled.
335 only to call in exception handler. returns true if traceback
335 only to call in exception handler. returns true if traceback
336 printed.'''
336 printed.'''
337 if self._traceback:
337 if self._traceback:
338 traceback.print_exc()
338 traceback.print_exc()
339 return self._traceback
339 return self._traceback
340
340
341 def geteditor(self):
341 def geteditor(self):
342 '''return editor to use'''
342 '''return editor to use'''
343 return (os.environ.get("HGEDITOR") or
343 return (os.environ.get("HGEDITOR") or
344 self.config("ui", "editor") or
344 self.config("ui", "editor") or
345 os.environ.get("VISUAL") or
345 os.environ.get("VISUAL") or
346 os.environ.get("EDITOR", "vi"))
346 os.environ.get("EDITOR", "vi"))
@@ -1,279 +1,278 b''
1 # win32.py - utility functions that use win32 API
1 # win32.py - utility functions that use win32 API
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, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 """Utility functions that use win32 API.
8 """Utility functions that use win32 API.
9
9
10 Mark Hammond's win32all package allows better functionality on
10 Mark Hammond's win32all package allows better functionality on
11 Windows. This module overrides definitions in util.py. If not
11 Windows. This module overrides definitions in util.py. If not
12 available, import of this module will fail, and generic code will be
12 available, import of this module will fail, and generic code will be
13 used.
13 used.
14 """
14 """
15
15
16 import win32api
16 import win32api
17
17
18 import errno, os, sys, pywintypes, win32con, win32file, win32process
18 import errno, os, sys, pywintypes, win32con, win32file, win32process
19 import cStringIO, winerror
19 import winerror
20 import osutil, encoding
20 import osutil, encoding
21 import util
22 from win32com.shell import shell,shellcon
21 from win32com.shell import shell,shellcon
23
22
24 class WinError(Exception):
23 class WinError(Exception):
25 winerror_map = {
24 winerror_map = {
26 winerror.ERROR_ACCESS_DENIED: errno.EACCES,
25 winerror.ERROR_ACCESS_DENIED: errno.EACCES,
27 winerror.ERROR_ACCOUNT_DISABLED: errno.EACCES,
26 winerror.ERROR_ACCOUNT_DISABLED: errno.EACCES,
28 winerror.ERROR_ACCOUNT_RESTRICTION: errno.EACCES,
27 winerror.ERROR_ACCOUNT_RESTRICTION: errno.EACCES,
29 winerror.ERROR_ALREADY_ASSIGNED: errno.EBUSY,
28 winerror.ERROR_ALREADY_ASSIGNED: errno.EBUSY,
30 winerror.ERROR_ALREADY_EXISTS: errno.EEXIST,
29 winerror.ERROR_ALREADY_EXISTS: errno.EEXIST,
31 winerror.ERROR_ARITHMETIC_OVERFLOW: errno.ERANGE,
30 winerror.ERROR_ARITHMETIC_OVERFLOW: errno.ERANGE,
32 winerror.ERROR_BAD_COMMAND: errno.EIO,
31 winerror.ERROR_BAD_COMMAND: errno.EIO,
33 winerror.ERROR_BAD_DEVICE: errno.ENODEV,
32 winerror.ERROR_BAD_DEVICE: errno.ENODEV,
34 winerror.ERROR_BAD_DRIVER_LEVEL: errno.ENXIO,
33 winerror.ERROR_BAD_DRIVER_LEVEL: errno.ENXIO,
35 winerror.ERROR_BAD_EXE_FORMAT: errno.ENOEXEC,
34 winerror.ERROR_BAD_EXE_FORMAT: errno.ENOEXEC,
36 winerror.ERROR_BAD_FORMAT: errno.ENOEXEC,
35 winerror.ERROR_BAD_FORMAT: errno.ENOEXEC,
37 winerror.ERROR_BAD_LENGTH: errno.EINVAL,
36 winerror.ERROR_BAD_LENGTH: errno.EINVAL,
38 winerror.ERROR_BAD_PATHNAME: errno.ENOENT,
37 winerror.ERROR_BAD_PATHNAME: errno.ENOENT,
39 winerror.ERROR_BAD_PIPE: errno.EPIPE,
38 winerror.ERROR_BAD_PIPE: errno.EPIPE,
40 winerror.ERROR_BAD_UNIT: errno.ENODEV,
39 winerror.ERROR_BAD_UNIT: errno.ENODEV,
41 winerror.ERROR_BAD_USERNAME: errno.EINVAL,
40 winerror.ERROR_BAD_USERNAME: errno.EINVAL,
42 winerror.ERROR_BROKEN_PIPE: errno.EPIPE,
41 winerror.ERROR_BROKEN_PIPE: errno.EPIPE,
43 winerror.ERROR_BUFFER_OVERFLOW: errno.ENAMETOOLONG,
42 winerror.ERROR_BUFFER_OVERFLOW: errno.ENAMETOOLONG,
44 winerror.ERROR_BUSY: errno.EBUSY,
43 winerror.ERROR_BUSY: errno.EBUSY,
45 winerror.ERROR_BUSY_DRIVE: errno.EBUSY,
44 winerror.ERROR_BUSY_DRIVE: errno.EBUSY,
46 winerror.ERROR_CALL_NOT_IMPLEMENTED: errno.ENOSYS,
45 winerror.ERROR_CALL_NOT_IMPLEMENTED: errno.ENOSYS,
47 winerror.ERROR_CANNOT_MAKE: errno.EACCES,
46 winerror.ERROR_CANNOT_MAKE: errno.EACCES,
48 winerror.ERROR_CANTOPEN: errno.EIO,
47 winerror.ERROR_CANTOPEN: errno.EIO,
49 winerror.ERROR_CANTREAD: errno.EIO,
48 winerror.ERROR_CANTREAD: errno.EIO,
50 winerror.ERROR_CANTWRITE: errno.EIO,
49 winerror.ERROR_CANTWRITE: errno.EIO,
51 winerror.ERROR_CRC: errno.EIO,
50 winerror.ERROR_CRC: errno.EIO,
52 winerror.ERROR_CURRENT_DIRECTORY: errno.EACCES,
51 winerror.ERROR_CURRENT_DIRECTORY: errno.EACCES,
53 winerror.ERROR_DEVICE_IN_USE: errno.EBUSY,
52 winerror.ERROR_DEVICE_IN_USE: errno.EBUSY,
54 winerror.ERROR_DEV_NOT_EXIST: errno.ENODEV,
53 winerror.ERROR_DEV_NOT_EXIST: errno.ENODEV,
55 winerror.ERROR_DIRECTORY: errno.EINVAL,
54 winerror.ERROR_DIRECTORY: errno.EINVAL,
56 winerror.ERROR_DIR_NOT_EMPTY: errno.ENOTEMPTY,
55 winerror.ERROR_DIR_NOT_EMPTY: errno.ENOTEMPTY,
57 winerror.ERROR_DISK_CHANGE: errno.EIO,
56 winerror.ERROR_DISK_CHANGE: errno.EIO,
58 winerror.ERROR_DISK_FULL: errno.ENOSPC,
57 winerror.ERROR_DISK_FULL: errno.ENOSPC,
59 winerror.ERROR_DRIVE_LOCKED: errno.EBUSY,
58 winerror.ERROR_DRIVE_LOCKED: errno.EBUSY,
60 winerror.ERROR_ENVVAR_NOT_FOUND: errno.EINVAL,
59 winerror.ERROR_ENVVAR_NOT_FOUND: errno.EINVAL,
61 winerror.ERROR_EXE_MARKED_INVALID: errno.ENOEXEC,
60 winerror.ERROR_EXE_MARKED_INVALID: errno.ENOEXEC,
62 winerror.ERROR_FILENAME_EXCED_RANGE: errno.ENAMETOOLONG,
61 winerror.ERROR_FILENAME_EXCED_RANGE: errno.ENAMETOOLONG,
63 winerror.ERROR_FILE_EXISTS: errno.EEXIST,
62 winerror.ERROR_FILE_EXISTS: errno.EEXIST,
64 winerror.ERROR_FILE_INVALID: errno.ENODEV,
63 winerror.ERROR_FILE_INVALID: errno.ENODEV,
65 winerror.ERROR_FILE_NOT_FOUND: errno.ENOENT,
64 winerror.ERROR_FILE_NOT_FOUND: errno.ENOENT,
66 winerror.ERROR_GEN_FAILURE: errno.EIO,
65 winerror.ERROR_GEN_FAILURE: errno.EIO,
67 winerror.ERROR_HANDLE_DISK_FULL: errno.ENOSPC,
66 winerror.ERROR_HANDLE_DISK_FULL: errno.ENOSPC,
68 winerror.ERROR_INSUFFICIENT_BUFFER: errno.ENOMEM,
67 winerror.ERROR_INSUFFICIENT_BUFFER: errno.ENOMEM,
69 winerror.ERROR_INVALID_ACCESS: errno.EACCES,
68 winerror.ERROR_INVALID_ACCESS: errno.EACCES,
70 winerror.ERROR_INVALID_ADDRESS: errno.EFAULT,
69 winerror.ERROR_INVALID_ADDRESS: errno.EFAULT,
71 winerror.ERROR_INVALID_BLOCK: errno.EFAULT,
70 winerror.ERROR_INVALID_BLOCK: errno.EFAULT,
72 winerror.ERROR_INVALID_DATA: errno.EINVAL,
71 winerror.ERROR_INVALID_DATA: errno.EINVAL,
73 winerror.ERROR_INVALID_DRIVE: errno.ENODEV,
72 winerror.ERROR_INVALID_DRIVE: errno.ENODEV,
74 winerror.ERROR_INVALID_EXE_SIGNATURE: errno.ENOEXEC,
73 winerror.ERROR_INVALID_EXE_SIGNATURE: errno.ENOEXEC,
75 winerror.ERROR_INVALID_FLAGS: errno.EINVAL,
74 winerror.ERROR_INVALID_FLAGS: errno.EINVAL,
76 winerror.ERROR_INVALID_FUNCTION: errno.ENOSYS,
75 winerror.ERROR_INVALID_FUNCTION: errno.ENOSYS,
77 winerror.ERROR_INVALID_HANDLE: errno.EBADF,
76 winerror.ERROR_INVALID_HANDLE: errno.EBADF,
78 winerror.ERROR_INVALID_LOGON_HOURS: errno.EACCES,
77 winerror.ERROR_INVALID_LOGON_HOURS: errno.EACCES,
79 winerror.ERROR_INVALID_NAME: errno.EINVAL,
78 winerror.ERROR_INVALID_NAME: errno.EINVAL,
80 winerror.ERROR_INVALID_OWNER: errno.EINVAL,
79 winerror.ERROR_INVALID_OWNER: errno.EINVAL,
81 winerror.ERROR_INVALID_PARAMETER: errno.EINVAL,
80 winerror.ERROR_INVALID_PARAMETER: errno.EINVAL,
82 winerror.ERROR_INVALID_PASSWORD: errno.EPERM,
81 winerror.ERROR_INVALID_PASSWORD: errno.EPERM,
83 winerror.ERROR_INVALID_PRIMARY_GROUP: errno.EINVAL,
82 winerror.ERROR_INVALID_PRIMARY_GROUP: errno.EINVAL,
84 winerror.ERROR_INVALID_SIGNAL_NUMBER: errno.EINVAL,
83 winerror.ERROR_INVALID_SIGNAL_NUMBER: errno.EINVAL,
85 winerror.ERROR_INVALID_TARGET_HANDLE: errno.EIO,
84 winerror.ERROR_INVALID_TARGET_HANDLE: errno.EIO,
86 winerror.ERROR_INVALID_WORKSTATION: errno.EACCES,
85 winerror.ERROR_INVALID_WORKSTATION: errno.EACCES,
87 winerror.ERROR_IO_DEVICE: errno.EIO,
86 winerror.ERROR_IO_DEVICE: errno.EIO,
88 winerror.ERROR_IO_INCOMPLETE: errno.EINTR,
87 winerror.ERROR_IO_INCOMPLETE: errno.EINTR,
89 winerror.ERROR_LOCKED: errno.EBUSY,
88 winerror.ERROR_LOCKED: errno.EBUSY,
90 winerror.ERROR_LOCK_VIOLATION: errno.EACCES,
89 winerror.ERROR_LOCK_VIOLATION: errno.EACCES,
91 winerror.ERROR_LOGON_FAILURE: errno.EACCES,
90 winerror.ERROR_LOGON_FAILURE: errno.EACCES,
92 winerror.ERROR_MAPPED_ALIGNMENT: errno.EINVAL,
91 winerror.ERROR_MAPPED_ALIGNMENT: errno.EINVAL,
93 winerror.ERROR_META_EXPANSION_TOO_LONG: errno.E2BIG,
92 winerror.ERROR_META_EXPANSION_TOO_LONG: errno.E2BIG,
94 winerror.ERROR_MORE_DATA: errno.EPIPE,
93 winerror.ERROR_MORE_DATA: errno.EPIPE,
95 winerror.ERROR_NEGATIVE_SEEK: errno.ESPIPE,
94 winerror.ERROR_NEGATIVE_SEEK: errno.ESPIPE,
96 winerror.ERROR_NOACCESS: errno.EFAULT,
95 winerror.ERROR_NOACCESS: errno.EFAULT,
97 winerror.ERROR_NONE_MAPPED: errno.EINVAL,
96 winerror.ERROR_NONE_MAPPED: errno.EINVAL,
98 winerror.ERROR_NOT_ENOUGH_MEMORY: errno.ENOMEM,
97 winerror.ERROR_NOT_ENOUGH_MEMORY: errno.ENOMEM,
99 winerror.ERROR_NOT_READY: errno.EAGAIN,
98 winerror.ERROR_NOT_READY: errno.EAGAIN,
100 winerror.ERROR_NOT_SAME_DEVICE: errno.EXDEV,
99 winerror.ERROR_NOT_SAME_DEVICE: errno.EXDEV,
101 winerror.ERROR_NO_DATA: errno.EPIPE,
100 winerror.ERROR_NO_DATA: errno.EPIPE,
102 winerror.ERROR_NO_MORE_SEARCH_HANDLES: errno.EIO,
101 winerror.ERROR_NO_MORE_SEARCH_HANDLES: errno.EIO,
103 winerror.ERROR_NO_PROC_SLOTS: errno.EAGAIN,
102 winerror.ERROR_NO_PROC_SLOTS: errno.EAGAIN,
104 winerror.ERROR_NO_SUCH_PRIVILEGE: errno.EACCES,
103 winerror.ERROR_NO_SUCH_PRIVILEGE: errno.EACCES,
105 winerror.ERROR_OPEN_FAILED: errno.EIO,
104 winerror.ERROR_OPEN_FAILED: errno.EIO,
106 winerror.ERROR_OPEN_FILES: errno.EBUSY,
105 winerror.ERROR_OPEN_FILES: errno.EBUSY,
107 winerror.ERROR_OPERATION_ABORTED: errno.EINTR,
106 winerror.ERROR_OPERATION_ABORTED: errno.EINTR,
108 winerror.ERROR_OUTOFMEMORY: errno.ENOMEM,
107 winerror.ERROR_OUTOFMEMORY: errno.ENOMEM,
109 winerror.ERROR_PASSWORD_EXPIRED: errno.EACCES,
108 winerror.ERROR_PASSWORD_EXPIRED: errno.EACCES,
110 winerror.ERROR_PATH_BUSY: errno.EBUSY,
109 winerror.ERROR_PATH_BUSY: errno.EBUSY,
111 winerror.ERROR_PATH_NOT_FOUND: errno.ENOENT,
110 winerror.ERROR_PATH_NOT_FOUND: errno.ENOENT,
112 winerror.ERROR_PIPE_BUSY: errno.EBUSY,
111 winerror.ERROR_PIPE_BUSY: errno.EBUSY,
113 winerror.ERROR_PIPE_CONNECTED: errno.EPIPE,
112 winerror.ERROR_PIPE_CONNECTED: errno.EPIPE,
114 winerror.ERROR_PIPE_LISTENING: errno.EPIPE,
113 winerror.ERROR_PIPE_LISTENING: errno.EPIPE,
115 winerror.ERROR_PIPE_NOT_CONNECTED: errno.EPIPE,
114 winerror.ERROR_PIPE_NOT_CONNECTED: errno.EPIPE,
116 winerror.ERROR_PRIVILEGE_NOT_HELD: errno.EACCES,
115 winerror.ERROR_PRIVILEGE_NOT_HELD: errno.EACCES,
117 winerror.ERROR_READ_FAULT: errno.EIO,
116 winerror.ERROR_READ_FAULT: errno.EIO,
118 winerror.ERROR_SEEK: errno.EIO,
117 winerror.ERROR_SEEK: errno.EIO,
119 winerror.ERROR_SEEK_ON_DEVICE: errno.ESPIPE,
118 winerror.ERROR_SEEK_ON_DEVICE: errno.ESPIPE,
120 winerror.ERROR_SHARING_BUFFER_EXCEEDED: errno.ENFILE,
119 winerror.ERROR_SHARING_BUFFER_EXCEEDED: errno.ENFILE,
121 winerror.ERROR_SHARING_VIOLATION: errno.EACCES,
120 winerror.ERROR_SHARING_VIOLATION: errno.EACCES,
122 winerror.ERROR_STACK_OVERFLOW: errno.ENOMEM,
121 winerror.ERROR_STACK_OVERFLOW: errno.ENOMEM,
123 winerror.ERROR_SWAPERROR: errno.ENOENT,
122 winerror.ERROR_SWAPERROR: errno.ENOENT,
124 winerror.ERROR_TOO_MANY_MODULES: errno.EMFILE,
123 winerror.ERROR_TOO_MANY_MODULES: errno.EMFILE,
125 winerror.ERROR_TOO_MANY_OPEN_FILES: errno.EMFILE,
124 winerror.ERROR_TOO_MANY_OPEN_FILES: errno.EMFILE,
126 winerror.ERROR_UNRECOGNIZED_MEDIA: errno.ENXIO,
125 winerror.ERROR_UNRECOGNIZED_MEDIA: errno.ENXIO,
127 winerror.ERROR_UNRECOGNIZED_VOLUME: errno.ENODEV,
126 winerror.ERROR_UNRECOGNIZED_VOLUME: errno.ENODEV,
128 winerror.ERROR_WAIT_NO_CHILDREN: errno.ECHILD,
127 winerror.ERROR_WAIT_NO_CHILDREN: errno.ECHILD,
129 winerror.ERROR_WRITE_FAULT: errno.EIO,
128 winerror.ERROR_WRITE_FAULT: errno.EIO,
130 winerror.ERROR_WRITE_PROTECT: errno.EROFS,
129 winerror.ERROR_WRITE_PROTECT: errno.EROFS,
131 }
130 }
132
131
133 def __init__(self, err):
132 def __init__(self, err):
134 try:
133 try:
135 # unpack a pywintypes.error tuple
134 # unpack a pywintypes.error tuple
136 self.win_errno, self.win_function, self.win_strerror = err
135 self.win_errno, self.win_function, self.win_strerror = err
137 except ValueError:
136 except ValueError:
138 # get attributes from a WindowsError
137 # get attributes from a WindowsError
139 self.win_errno = err.winerror
138 self.win_errno = err.winerror
140 self.win_function = None
139 self.win_function = None
141 self.win_strerror = err.strerror
140 self.win_strerror = err.strerror
142 self.win_strerror = self.win_strerror.rstrip('.')
141 self.win_strerror = self.win_strerror.rstrip('.')
143
142
144 class WinIOError(WinError, IOError):
143 class WinIOError(WinError, IOError):
145 def __init__(self, err, filename=None):
144 def __init__(self, err, filename=None):
146 WinError.__init__(self, err)
145 WinError.__init__(self, err)
147 IOError.__init__(self, self.winerror_map.get(self.win_errno, 0),
146 IOError.__init__(self, self.winerror_map.get(self.win_errno, 0),
148 self.win_strerror)
147 self.win_strerror)
149 self.filename = filename
148 self.filename = filename
150
149
151 class WinOSError(WinError, OSError):
150 class WinOSError(WinError, OSError):
152 def __init__(self, err):
151 def __init__(self, err):
153 WinError.__init__(self, err)
152 WinError.__init__(self, err)
154 OSError.__init__(self, self.winerror_map.get(self.win_errno, 0),
153 OSError.__init__(self, self.winerror_map.get(self.win_errno, 0),
155 self.win_strerror)
154 self.win_strerror)
156
155
157 def os_link(src, dst):
156 def os_link(src, dst):
158 try:
157 try:
159 win32file.CreateHardLink(dst, src)
158 win32file.CreateHardLink(dst, src)
160 # CreateHardLink sometimes succeeds on mapped drives but
159 # CreateHardLink sometimes succeeds on mapped drives but
161 # following nlinks() returns 1. Check it now and bail out.
160 # following nlinks() returns 1. Check it now and bail out.
162 if nlinks(src) < 2:
161 if nlinks(src) < 2:
163 try:
162 try:
164 win32file.DeleteFile(dst)
163 win32file.DeleteFile(dst)
165 except:
164 except:
166 pass
165 pass
167 # Fake hardlinking error
166 # Fake hardlinking error
168 raise WinOSError((18, 'CreateHardLink', 'The system cannot '
167 raise WinOSError((18, 'CreateHardLink', 'The system cannot '
169 'move the file to a different disk drive'))
168 'move the file to a different disk drive'))
170 except pywintypes.error, details:
169 except pywintypes.error, details:
171 raise WinOSError(details)
170 raise WinOSError(details)
172 except NotImplementedError: # Another fake error win Win98
171 except NotImplementedError: # Another fake error win Win98
173 raise WinOSError((18, 'CreateHardLink', 'Hardlinking not supported'))
172 raise WinOSError((18, 'CreateHardLink', 'Hardlinking not supported'))
174
173
175 def nlinks(pathname):
174 def nlinks(pathname):
176 """Return number of hardlinks for the given file."""
175 """Return number of hardlinks for the given file."""
177 try:
176 try:
178 fh = win32file.CreateFile(pathname,
177 fh = win32file.CreateFile(pathname,
179 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
178 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
180 None, win32file.OPEN_EXISTING, 0, None)
179 None, win32file.OPEN_EXISTING, 0, None)
181 res = win32file.GetFileInformationByHandle(fh)
180 res = win32file.GetFileInformationByHandle(fh)
182 fh.Close()
181 fh.Close()
183 return res[7]
182 return res[7]
184 except pywintypes.error:
183 except pywintypes.error:
185 return os.lstat(pathname).st_nlink
184 return os.lstat(pathname).st_nlink
186
185
187 def testpid(pid):
186 def testpid(pid):
188 '''return True if pid is still running or unable to
187 '''return True if pid is still running or unable to
189 determine, False otherwise'''
188 determine, False otherwise'''
190 try:
189 try:
191 handle = win32api.OpenProcess(
190 handle = win32api.OpenProcess(
192 win32con.PROCESS_QUERY_INFORMATION, False, pid)
191 win32con.PROCESS_QUERY_INFORMATION, False, pid)
193 if handle:
192 if handle:
194 status = win32process.GetExitCodeProcess(handle)
193 status = win32process.GetExitCodeProcess(handle)
195 return status == win32con.STILL_ACTIVE
194 return status == win32con.STILL_ACTIVE
196 except pywintypes.error, details:
195 except pywintypes.error, details:
197 return details[0] != winerror.ERROR_INVALID_PARAMETER
196 return details[0] != winerror.ERROR_INVALID_PARAMETER
198 return True
197 return True
199
198
200 def lookup_reg(key, valname=None, scope=None):
199 def lookup_reg(key, valname=None, scope=None):
201 ''' Look up a key/value name in the Windows registry.
200 ''' Look up a key/value name in the Windows registry.
202
201
203 valname: value name. If unspecified, the default value for the key
202 valname: value name. If unspecified, the default value for the key
204 is used.
203 is used.
205 scope: optionally specify scope for registry lookup, this can be
204 scope: optionally specify scope for registry lookup, this can be
206 a sequence of scopes to look up in order. Default (CURRENT_USER,
205 a sequence of scopes to look up in order. Default (CURRENT_USER,
207 LOCAL_MACHINE).
206 LOCAL_MACHINE).
208 '''
207 '''
209 try:
208 try:
210 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
209 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
211 QueryValueEx, OpenKey
210 QueryValueEx, OpenKey
212 except ImportError:
211 except ImportError:
213 return None
212 return None
214
213
215 if scope is None:
214 if scope is None:
216 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
215 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
217 elif not isinstance(scope, (list, tuple)):
216 elif not isinstance(scope, (list, tuple)):
218 scope = (scope,)
217 scope = (scope,)
219 for s in scope:
218 for s in scope:
220 try:
219 try:
221 val = QueryValueEx(OpenKey(s, key), valname)[0]
220 val = QueryValueEx(OpenKey(s, key), valname)[0]
222 # never let a Unicode string escape into the wild
221 # never let a Unicode string escape into the wild
223 return encoding.tolocal(val.encode('UTF-8'))
222 return encoding.tolocal(val.encode('UTF-8'))
224 except EnvironmentError:
223 except EnvironmentError:
225 pass
224 pass
226
225
227 def system_rcpath_win32():
226 def system_rcpath_win32():
228 '''return default os-specific hgrc search path'''
227 '''return default os-specific hgrc search path'''
229 proc = win32api.GetCurrentProcess()
228 proc = win32api.GetCurrentProcess()
230 try:
229 try:
231 # This will fail on windows < NT
230 # This will fail on windows < NT
232 filename = win32process.GetModuleFileNameEx(proc, 0)
231 filename = win32process.GetModuleFileNameEx(proc, 0)
233 except:
232 except:
234 filename = win32api.GetModuleFileName(0)
233 filename = win32api.GetModuleFileName(0)
235 # Use mercurial.ini found in directory with hg.exe
234 # Use mercurial.ini found in directory with hg.exe
236 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
235 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
237 if os.path.isfile(progrc):
236 if os.path.isfile(progrc):
238 return [progrc]
237 return [progrc]
239 # else look for a system rcpath in the registry
238 # else look for a system rcpath in the registry
240 try:
239 try:
241 value = win32api.RegQueryValue(
240 value = win32api.RegQueryValue(
242 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
241 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
243 rcpath = []
242 rcpath = []
244 for p in value.split(os.pathsep):
243 for p in value.split(os.pathsep):
245 if p.lower().endswith('mercurial.ini'):
244 if p.lower().endswith('mercurial.ini'):
246 rcpath.append(p)
245 rcpath.append(p)
247 elif os.path.isdir(p):
246 elif os.path.isdir(p):
248 for f, kind in osutil.listdir(p):
247 for f, kind in osutil.listdir(p):
249 if f.endswith('.rc'):
248 if f.endswith('.rc'):
250 rcpath.append(os.path.join(p, f))
249 rcpath.append(os.path.join(p, f))
251 return rcpath
250 return rcpath
252 except pywintypes.error:
251 except pywintypes.error:
253 return []
252 return []
254
253
255 def user_rcpath_win32():
254 def user_rcpath_win32():
256 '''return os-specific hgrc search path to the user dir'''
255 '''return os-specific hgrc search path to the user dir'''
257 userdir = os.path.expanduser('~')
256 userdir = os.path.expanduser('~')
258 if sys.getwindowsversion()[3] != 2 and userdir == '~':
257 if sys.getwindowsversion()[3] != 2 and userdir == '~':
259 # We are on win < nt: fetch the APPDATA directory location and use
258 # We are on win < nt: fetch the APPDATA directory location and use
260 # the parent directory as the user home dir.
259 # the parent directory as the user home dir.
261 appdir = shell.SHGetPathFromIDList(
260 appdir = shell.SHGetPathFromIDList(
262 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
261 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
263 userdir = os.path.dirname(appdir)
262 userdir = os.path.dirname(appdir)
264 return [os.path.join(userdir, 'mercurial.ini'),
263 return [os.path.join(userdir, 'mercurial.ini'),
265 os.path.join(userdir, '.hgrc')]
264 os.path.join(userdir, '.hgrc')]
266
265
267 def getuser():
266 def getuser():
268 '''return name of current user'''
267 '''return name of current user'''
269 return win32api.GetUserName()
268 return win32api.GetUserName()
270
269
271 def set_signal_handler_win32():
270 def set_signal_handler_win32():
272 """Register a termination handler for console events including
271 """Register a termination handler for console events including
273 CTRL+C. python signal handlers do not work well with socket
272 CTRL+C. python signal handlers do not work well with socket
274 operations.
273 operations.
275 """
274 """
276 def handler(event):
275 def handler(event):
277 win32process.ExitProcess(1)
276 win32process.ExitProcess(1)
278 win32api.SetConsoleCtrlHandler(handler)
277 win32api.SetConsoleCtrlHandler(handler)
279
278
@@ -1,54 +1,54 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 import sys, struct
3 import struct
4 from mercurial import bdiff, mpatch
4 from mercurial import bdiff, mpatch
5
5
6 def test1(a, b):
6 def test1(a, b):
7 d = bdiff.bdiff(a, b)
7 d = bdiff.bdiff(a, b)
8 c = a
8 c = a
9 if d:
9 if d:
10 c = mpatch.patches(a, [d])
10 c = mpatch.patches(a, [d])
11 if c != b:
11 if c != b:
12 print "***", repr(a), repr(b)
12 print "***", repr(a), repr(b)
13 print "bad:"
13 print "bad:"
14 print repr(c)[:200]
14 print repr(c)[:200]
15 print repr(d)
15 print repr(d)
16
16
17 def test(a, b):
17 def test(a, b):
18 print "***", repr(a), repr(b)
18 print "***", repr(a), repr(b)
19 test1(a, b)
19 test1(a, b)
20 test1(b, a)
20 test1(b, a)
21
21
22 test("a\nc\n\n\n\n", "a\nb\n\n\n")
22 test("a\nc\n\n\n\n", "a\nb\n\n\n")
23 test("a\nb\nc\n", "a\nc\n")
23 test("a\nb\nc\n", "a\nc\n")
24 test("", "")
24 test("", "")
25 test("a\nb\nc", "a\nb\nc")
25 test("a\nb\nc", "a\nb\nc")
26 test("a\nb\nc\nd\n", "a\nd\n")
26 test("a\nb\nc\nd\n", "a\nd\n")
27 test("a\nb\nc\nd\n", "a\nc\ne\n")
27 test("a\nb\nc\nd\n", "a\nc\ne\n")
28 test("a\nb\nc\n", "a\nc\n")
28 test("a\nb\nc\n", "a\nc\n")
29 test("a\n", "c\na\nb\n")
29 test("a\n", "c\na\nb\n")
30 test("a\n", "")
30 test("a\n", "")
31 test("a\n", "b\nc\n")
31 test("a\n", "b\nc\n")
32 test("a\n", "c\na\n")
32 test("a\n", "c\na\n")
33 test("", "adjfkjdjksdhfksj")
33 test("", "adjfkjdjksdhfksj")
34 test("", "ab")
34 test("", "ab")
35 test("", "abc")
35 test("", "abc")
36 test("a", "a")
36 test("a", "a")
37 test("ab", "ab")
37 test("ab", "ab")
38 test("abc", "abc")
38 test("abc", "abc")
39 test("a\n", "a\n")
39 test("a\n", "a\n")
40 test("a\nb", "a\nb")
40 test("a\nb", "a\nb")
41
41
42 #issue1295
42 #issue1295
43 def showdiff(a, b):
43 def showdiff(a, b):
44 bin = bdiff.bdiff(a, b)
44 bin = bdiff.bdiff(a, b)
45 pos = 0
45 pos = 0
46 while pos < len(bin):
46 while pos < len(bin):
47 p1, p2, l = struct.unpack(">lll", bin[pos:pos + 12])
47 p1, p2, l = struct.unpack(">lll", bin[pos:pos + 12])
48 pos += 12
48 pos += 12
49 print p1, p2, repr(bin[pos:pos + l])
49 print p1, p2, repr(bin[pos:pos + l])
50 pos += l
50 pos += l
51 showdiff("x\n\nx\n\nx\n\nx\n\nz\n", "x\n\nx\n\ny\n\nx\n\nx\n\nz\n")
51 showdiff("x\n\nx\n\nx\n\nx\n\nz\n", "x\n\nx\n\ny\n\nx\n\nx\n\nz\n")
52 showdiff("x\n\nx\n\nx\n\nx\n\nz\n", "x\n\nx\n\ny\n\nx\n\ny\n\nx\n\nz\n")
52 showdiff("x\n\nx\n\nx\n\nx\n\nz\n", "x\n\nx\n\ny\n\nx\n\ny\n\nx\n\nz\n")
53
53
54 print "done"
54 print "done"
@@ -1,74 +1,73 b''
1 import os
1 import os
2 from mercurial import hg, ui, merge
2 from mercurial import hg, ui, merge
3 from hgext import graphlog
4
3
5 u = ui.ui()
4 u = ui.ui()
6
5
7 repo = hg.repository(u, 'test1', create=1)
6 repo = hg.repository(u, 'test1', create=1)
8 os.chdir('test1')
7 os.chdir('test1')
9
8
10 def commit(text, time):
9 def commit(text, time):
11 repo.commit(text=text, date="%d 0" % time)
10 repo.commit(text=text, date="%d 0" % time)
12
11
13 def addcommit(name, time):
12 def addcommit(name, time):
14 f = file(name, 'w')
13 f = file(name, 'w')
15 f.write('%s\n' % name)
14 f.write('%s\n' % name)
16 f.close()
15 f.close()
17 repo.add([name])
16 repo.add([name])
18 commit(name, time)
17 commit(name, time)
19
18
20 def update(rev):
19 def update(rev):
21 merge.update(repo, rev, False, True, False)
20 merge.update(repo, rev, False, True, False)
22
21
23 def merge_(rev):
22 def merge_(rev):
24 merge.update(repo, rev, True, False, False)
23 merge.update(repo, rev, True, False, False)
25
24
26 if __name__ == '__main__':
25 if __name__ == '__main__':
27 addcommit("A", 0)
26 addcommit("A", 0)
28 addcommit("B", 1)
27 addcommit("B", 1)
29
28
30 update(0)
29 update(0)
31 addcommit("C", 2)
30 addcommit("C", 2)
32
31
33 merge_(1)
32 merge_(1)
34 commit("D", 3)
33 commit("D", 3)
35
34
36 update(2)
35 update(2)
37 addcommit("E", 4)
36 addcommit("E", 4)
38 addcommit("F", 5)
37 addcommit("F", 5)
39
38
40 update(3)
39 update(3)
41 addcommit("G", 6)
40 addcommit("G", 6)
42
41
43 merge_(5)
42 merge_(5)
44 commit("H", 7)
43 commit("H", 7)
45
44
46 update(5)
45 update(5)
47 addcommit("I", 8)
46 addcommit("I", 8)
48
47
49 # Ancestors
48 # Ancestors
50 print 'Ancestors of 5'
49 print 'Ancestors of 5'
51 for r in repo.changelog.ancestors(5):
50 for r in repo.changelog.ancestors(5):
52 print r,
51 print r,
53
52
54 print '\nAncestors of 6 and 5'
53 print '\nAncestors of 6 and 5'
55 for r in repo.changelog.ancestors(6, 5):
54 for r in repo.changelog.ancestors(6, 5):
56 print r,
55 print r,
57
56
58 print '\nAncestors of 5 and 4'
57 print '\nAncestors of 5 and 4'
59 for r in repo.changelog.ancestors(5, 4):
58 for r in repo.changelog.ancestors(5, 4):
60 print r,
59 print r,
61
60
62 # Descendants
61 # Descendants
63 print '\n\nDescendants of 5'
62 print '\n\nDescendants of 5'
64 for r in repo.changelog.descendants(5):
63 for r in repo.changelog.descendants(5):
65 print r,
64 print r,
66
65
67 print '\nDescendants of 5 and 3'
66 print '\nDescendants of 5 and 3'
68 for r in repo.changelog.descendants(5, 3):
67 for r in repo.changelog.descendants(5, 3):
69 print r,
68 print r,
70
69
71 print '\nDescendants of 5 and 4'
70 print '\nDescendants of 5 and 4'
72 for r in repo.changelog.descendants(5, 4):
71 for r in repo.changelog.descendants(5, 4):
73 print r,
72 print r,
74
73
@@ -1,55 +1,55 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 from mercurial import ui, util, dispatch, error
3 from mercurial import ui, dispatch, error
4
4
5 testui = ui.ui()
5 testui = ui.ui()
6 parsed = dispatch._parseconfig(testui, [
6 parsed = dispatch._parseconfig(testui, [
7 'values.string=string value',
7 'values.string=string value',
8 'values.bool1=true',
8 'values.bool1=true',
9 'values.bool2=false',
9 'values.bool2=false',
10 'lists.list1=foo',
10 'lists.list1=foo',
11 'lists.list2=foo bar baz',
11 'lists.list2=foo bar baz',
12 'lists.list3=alice, bob',
12 'lists.list3=alice, bob',
13 'lists.list4=foo bar baz alice, bob',
13 'lists.list4=foo bar baz alice, bob',
14 ])
14 ])
15
15
16 print repr(testui.configitems('values'))
16 print repr(testui.configitems('values'))
17 print repr(testui.configitems('lists'))
17 print repr(testui.configitems('lists'))
18 print "---"
18 print "---"
19 print repr(testui.config('values', 'string'))
19 print repr(testui.config('values', 'string'))
20 print repr(testui.config('values', 'bool1'))
20 print repr(testui.config('values', 'bool1'))
21 print repr(testui.config('values', 'bool2'))
21 print repr(testui.config('values', 'bool2'))
22 print repr(testui.config('values', 'unknown'))
22 print repr(testui.config('values', 'unknown'))
23 print "---"
23 print "---"
24 try:
24 try:
25 print repr(testui.configbool('values', 'string'))
25 print repr(testui.configbool('values', 'string'))
26 except error.ConfigError, inst:
26 except error.ConfigError, inst:
27 print inst
27 print inst
28 print repr(testui.configbool('values', 'bool1'))
28 print repr(testui.configbool('values', 'bool1'))
29 print repr(testui.configbool('values', 'bool2'))
29 print repr(testui.configbool('values', 'bool2'))
30 print repr(testui.configbool('values', 'bool2', True))
30 print repr(testui.configbool('values', 'bool2', True))
31 print repr(testui.configbool('values', 'unknown'))
31 print repr(testui.configbool('values', 'unknown'))
32 print repr(testui.configbool('values', 'unknown', True))
32 print repr(testui.configbool('values', 'unknown', True))
33 print "---"
33 print "---"
34 print repr(testui.configlist('lists', 'list1'))
34 print repr(testui.configlist('lists', 'list1'))
35 print repr(testui.configlist('lists', 'list2'))
35 print repr(testui.configlist('lists', 'list2'))
36 print repr(testui.configlist('lists', 'list3'))
36 print repr(testui.configlist('lists', 'list3'))
37 print repr(testui.configlist('lists', 'list4'))
37 print repr(testui.configlist('lists', 'list4'))
38 print repr(testui.configlist('lists', 'list4', ['foo']))
38 print repr(testui.configlist('lists', 'list4', ['foo']))
39 print repr(testui.configlist('lists', 'unknown'))
39 print repr(testui.configlist('lists', 'unknown'))
40 print repr(testui.configlist('lists', 'unknown', ''))
40 print repr(testui.configlist('lists', 'unknown', ''))
41 print repr(testui.configlist('lists', 'unknown', 'foo'))
41 print repr(testui.configlist('lists', 'unknown', 'foo'))
42 print repr(testui.configlist('lists', 'unknown', ['foo']))
42 print repr(testui.configlist('lists', 'unknown', ['foo']))
43 print repr(testui.configlist('lists', 'unknown', 'foo bar'))
43 print repr(testui.configlist('lists', 'unknown', 'foo bar'))
44 print repr(testui.configlist('lists', 'unknown', 'foo, bar'))
44 print repr(testui.configlist('lists', 'unknown', 'foo, bar'))
45 print repr(testui.configlist('lists', 'unknown', ['foo bar']))
45 print repr(testui.configlist('lists', 'unknown', ['foo bar']))
46 print repr(testui.configlist('lists', 'unknown', ['foo', 'bar']))
46 print repr(testui.configlist('lists', 'unknown', ['foo', 'bar']))
47
47
48 print repr(testui.config('values', 'String'))
48 print repr(testui.config('values', 'String'))
49
49
50 def function():
50 def function():
51 pass
51 pass
52
52
53 # values that aren't strings should work
53 # values that aren't strings should work
54 testui.setconfig('hook', 'commit', function)
54 testui.setconfig('hook', 'commit', function)
55 print function == testui.config('hook', 'commit')
55 print function == testui.config('hook', 'commit')
@@ -1,53 +1,52 b''
1 import os
1 import os
2 import os.path
3 from mercurial import hg, ui
2 from mercurial import hg, ui
4 from mercurial.util import walkrepos
3 from mercurial.util import walkrepos
5 from os import mkdir, chdir
4 from os import mkdir, chdir
6 from os.path import join as pjoin
5 from os.path import join as pjoin
7
6
8 u = ui.ui()
7 u = ui.ui()
9 sym = hasattr(os, 'symlink') and hasattr(os.path, 'samestat')
8 sym = hasattr(os, 'symlink') and hasattr(os.path, 'samestat')
10
9
11 hg.repository(u, 'top1', create=1)
10 hg.repository(u, 'top1', create=1)
12 mkdir('subdir')
11 mkdir('subdir')
13 chdir('subdir')
12 chdir('subdir')
14 hg.repository(u, 'sub1', create=1)
13 hg.repository(u, 'sub1', create=1)
15 mkdir('subsubdir')
14 mkdir('subsubdir')
16 chdir('subsubdir')
15 chdir('subsubdir')
17 hg.repository(u, 'subsub1', create=1)
16 hg.repository(u, 'subsub1', create=1)
18 chdir(os.path.pardir)
17 chdir(os.path.pardir)
19 if sym:
18 if sym:
20 os.symlink(os.path.pardir, 'circle')
19 os.symlink(os.path.pardir, 'circle')
21 os.symlink(pjoin('subsubdir', 'subsub1'), 'subsub1')
20 os.symlink(pjoin('subsubdir', 'subsub1'), 'subsub1')
22
21
23 def runtest():
22 def runtest():
24 reposet = frozenset(walkrepos('.', followsym=True))
23 reposet = frozenset(walkrepos('.', followsym=True))
25 if sym and (len(reposet) != 3):
24 if sym and (len(reposet) != 3):
26 print "reposet = %r" % (reposet,)
25 print "reposet = %r" % (reposet,)
27 print "Found %d repositories when I should have found 3" % (len(reposet),)
26 print "Found %d repositories when I should have found 3" % (len(reposet),)
28 if (not sym) and (len(reposet) != 2):
27 if (not sym) and (len(reposet) != 2):
29 print "reposet = %r" % (reposet,)
28 print "reposet = %r" % (reposet,)
30 print "Found %d repositories when I should have found 2" % (len(reposet),)
29 print "Found %d repositories when I should have found 2" % (len(reposet),)
31 sub1set = frozenset((pjoin('.', 'sub1'),
30 sub1set = frozenset((pjoin('.', 'sub1'),
32 pjoin('.', 'circle', 'subdir', 'sub1')))
31 pjoin('.', 'circle', 'subdir', 'sub1')))
33 if len(sub1set & reposet) != 1:
32 if len(sub1set & reposet) != 1:
34 print "sub1set = %r" % (sub1set,)
33 print "sub1set = %r" % (sub1set,)
35 print "reposet = %r" % (reposet,)
34 print "reposet = %r" % (reposet,)
36 print "sub1set and reposet should have exactly one path in common."
35 print "sub1set and reposet should have exactly one path in common."
37 sub2set = frozenset((pjoin('.', 'subsub1'),
36 sub2set = frozenset((pjoin('.', 'subsub1'),
38 pjoin('.', 'subsubdir', 'subsub1')))
37 pjoin('.', 'subsubdir', 'subsub1')))
39 if len(sub2set & reposet) != 1:
38 if len(sub2set & reposet) != 1:
40 print "sub2set = %r" % (sub2set,)
39 print "sub2set = %r" % (sub2set,)
41 print "reposet = %r" % (reposet,)
40 print "reposet = %r" % (reposet,)
42 print "sub1set and reposet should have exactly one path in common."
41 print "sub1set and reposet should have exactly one path in common."
43 sub3 = pjoin('.', 'circle', 'top1')
42 sub3 = pjoin('.', 'circle', 'top1')
44 if sym and not (sub3 in reposet):
43 if sym and not (sub3 in reposet):
45 print "reposet = %r" % (reposet,)
44 print "reposet = %r" % (reposet,)
46 print "Symbolic links are supported and %s is not in reposet" % (sub3,)
45 print "Symbolic links are supported and %s is not in reposet" % (sub3,)
47
46
48 runtest()
47 runtest()
49 if sym:
48 if sym:
50 # Simulate not having symlinks.
49 # Simulate not having symlinks.
51 del os.path.samestat
50 del os.path.samestat
52 sym = False
51 sym = False
53 runtest()
52 runtest()
General Comments 0
You need to be logged in to leave comments. Login now