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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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, |
|
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