##// END OF EJS Templates
hghave: handle Windows raising on popen() failure
Patrick Mezard -
r8213:ac9c4049 default
parent child Browse files
Show More
@@ -1,264 +1,268 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Test the running system for features availability. Exit with zero
2 """Test the running system for features availability. Exit with zero
3 if all features are there, non-zero otherwise. If a feature name is
3 if all features are there, non-zero otherwise. If a feature name is
4 prefixed with "no-", the absence of feature is tested.
4 prefixed with "no-", the absence of feature is tested.
5 """
5 """
6 import optparse
6 import optparse
7 import os
7 import os
8 import re
8 import re
9 import sys
9 import sys
10 import tempfile
10 import tempfile
11
11
12 tempprefix = 'hg-hghave-'
12 tempprefix = 'hg-hghave-'
13
13
14 def matchoutput(cmd, regexp, ignorestatus=False):
14 def matchoutput(cmd, regexp, ignorestatus=False):
15 """Return True if cmd executes successfully and its output
15 """Return True if cmd executes successfully and its output
16 is matched by the supplied regular expression.
16 is matched by the supplied regular expression.
17 """
17 """
18 r = re.compile(regexp)
18 r = re.compile(regexp)
19 fh = os.popen(cmd)
19 fh = os.popen(cmd)
20 s = fh.read()
20 s = fh.read()
21 ret = fh.close()
21 try:
22 ret = fh.close()
23 except IOError:
24 # Happen in Windows test environment
25 ret = 1
22 return (ignorestatus or ret is None) and r.search(s)
26 return (ignorestatus or ret is None) and r.search(s)
23
27
24 def has_baz():
28 def has_baz():
25 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
29 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
26
30
27 def has_bzr():
31 def has_bzr():
28 try:
32 try:
29 import bzrlib
33 import bzrlib
30 return bzrlib.__doc__ != None
34 return bzrlib.__doc__ != None
31 except ImportError:
35 except ImportError:
32 return False
36 return False
33
37
34 def has_bzr114():
38 def has_bzr114():
35 try:
39 try:
36 import bzrlib
40 import bzrlib
37 return (bzrlib.__doc__ != None
41 return (bzrlib.__doc__ != None
38 and bzrlib.version_info[:2] == (1, 14))
42 and bzrlib.version_info[:2] == (1, 14))
39 except ImportError:
43 except ImportError:
40 return False
44 return False
41
45
42 def has_cvs():
46 def has_cvs():
43 re = r'Concurrent Versions System.*?server'
47 re = r'Concurrent Versions System.*?server'
44 return matchoutput('cvs --version 2>&1', re)
48 return matchoutput('cvs --version 2>&1', re)
45
49
46 def has_cvsps():
50 def has_cvsps():
47 return matchoutput('cvsps -h -q 2>&1', r'cvsps version', True)
51 return matchoutput('cvsps -h -q 2>&1', r'cvsps version', True)
48
52
49 def has_darcs():
53 def has_darcs():
50 return matchoutput('darcs', r'darcs version', True)
54 return matchoutput('darcs', r'darcs version', True)
51
55
52 def has_mtn():
56 def has_mtn():
53 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
57 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
54 'mtn --version', r'monotone 0\.(\d|[12]\d|3[01])[^\d]', True)
58 'mtn --version', r'monotone 0\.(\d|[12]\d|3[01])[^\d]', True)
55
59
56 def has_eol_in_paths():
60 def has_eol_in_paths():
57 try:
61 try:
58 fd, path = tempfile.mkstemp(prefix=tempprefix, suffix='\n\r')
62 fd, path = tempfile.mkstemp(prefix=tempprefix, suffix='\n\r')
59 os.close(fd)
63 os.close(fd)
60 os.remove(path)
64 os.remove(path)
61 return True
65 return True
62 except:
66 except:
63 return False
67 return False
64
68
65 def has_executablebit():
69 def has_executablebit():
66 fd, path = tempfile.mkstemp(prefix=tempprefix)
70 fd, path = tempfile.mkstemp(prefix=tempprefix)
67 os.close(fd)
71 os.close(fd)
68 try:
72 try:
69 s = os.lstat(path).st_mode
73 s = os.lstat(path).st_mode
70 os.chmod(path, s | 0100)
74 os.chmod(path, s | 0100)
71 return (os.lstat(path).st_mode & 0100 != 0)
75 return (os.lstat(path).st_mode & 0100 != 0)
72 finally:
76 finally:
73 os.remove(path)
77 os.remove(path)
74
78
75 def has_icasefs():
79 def has_icasefs():
76 # Stolen from mercurial.util
80 # Stolen from mercurial.util
77 fd, path = tempfile.mkstemp(prefix=tempprefix)
81 fd, path = tempfile.mkstemp(prefix=tempprefix)
78 os.close(fd)
82 os.close(fd)
79 try:
83 try:
80 s1 = os.stat(path)
84 s1 = os.stat(path)
81 d, b = os.path.split(path)
85 d, b = os.path.split(path)
82 p2 = os.path.join(d, b.upper())
86 p2 = os.path.join(d, b.upper())
83 if path == p2:
87 if path == p2:
84 p2 = os.path.join(d, b.lower())
88 p2 = os.path.join(d, b.lower())
85 try:
89 try:
86 s2 = os.stat(p2)
90 s2 = os.stat(p2)
87 return s2 == s1
91 return s2 == s1
88 except:
92 except:
89 return False
93 return False
90 finally:
94 finally:
91 os.remove(path)
95 os.remove(path)
92
96
93 def has_inotify():
97 def has_inotify():
94 try:
98 try:
95 import hgext.inotify.linux.watcher
99 import hgext.inotify.linux.watcher
96 return True
100 return True
97 except ImportError:
101 except ImportError:
98 return False
102 return False
99
103
100 def has_fifo():
104 def has_fifo():
101 return hasattr(os, "mkfifo")
105 return hasattr(os, "mkfifo")
102
106
103 def has_hotshot():
107 def has_hotshot():
104 try:
108 try:
105 # hotshot.stats tests hotshot and many problematic dependencies
109 # hotshot.stats tests hotshot and many problematic dependencies
106 # like profile.
110 # like profile.
107 import hotshot.stats
111 import hotshot.stats
108 return True
112 return True
109 except ImportError:
113 except ImportError:
110 return False
114 return False
111
115
112 def has_lsprof():
116 def has_lsprof():
113 try:
117 try:
114 import _lsprof
118 import _lsprof
115 return True
119 return True
116 except ImportError:
120 except ImportError:
117 return False
121 return False
118
122
119 def has_git():
123 def has_git():
120 return matchoutput('git --version 2>&1', r'^git version')
124 return matchoutput('git --version 2>&1', r'^git version')
121
125
122 def has_svn():
126 def has_svn():
123 return matchoutput('svn --version 2>&1', r'^svn, version') and \
127 return matchoutput('svn --version 2>&1', r'^svn, version') and \
124 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
128 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
125
129
126 def has_svn_bindings():
130 def has_svn_bindings():
127 try:
131 try:
128 import svn.core
132 import svn.core
129 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
133 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
130 if version < (1, 4):
134 if version < (1, 4):
131 return False
135 return False
132 return True
136 return True
133 except ImportError:
137 except ImportError:
134 return False
138 return False
135
139
136 def has_p4():
140 def has_p4():
137 return matchoutput('p4 -V', r'Rev\. P4/') and matchoutput('p4d -V', r'Rev\. P4D/')
141 return matchoutput('p4 -V', r'Rev\. P4/') and matchoutput('p4d -V', r'Rev\. P4D/')
138
142
139 def has_symlink():
143 def has_symlink():
140 return hasattr(os, "symlink")
144 return hasattr(os, "symlink")
141
145
142 def has_tla():
146 def has_tla():
143 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
147 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
144
148
145 def has_unix_permissions():
149 def has_unix_permissions():
146 d = tempfile.mkdtemp(prefix=tempprefix, dir=".")
150 d = tempfile.mkdtemp(prefix=tempprefix, dir=".")
147 try:
151 try:
148 fname = os.path.join(d, 'foo')
152 fname = os.path.join(d, 'foo')
149 for umask in (077, 007, 022):
153 for umask in (077, 007, 022):
150 os.umask(umask)
154 os.umask(umask)
151 f = open(fname, 'w')
155 f = open(fname, 'w')
152 f.close()
156 f.close()
153 mode = os.stat(fname).st_mode
157 mode = os.stat(fname).st_mode
154 os.unlink(fname)
158 os.unlink(fname)
155 if mode & 0777 != ~umask & 0666:
159 if mode & 0777 != ~umask & 0666:
156 return False
160 return False
157 return True
161 return True
158 finally:
162 finally:
159 os.rmdir(d)
163 os.rmdir(d)
160
164
161 def has_pygments():
165 def has_pygments():
162 try:
166 try:
163 import pygments
167 import pygments
164 return True
168 return True
165 except ImportError:
169 except ImportError:
166 return False
170 return False
167
171
168 def has_outer_repo():
172 def has_outer_repo():
169 return matchoutput('hg root 2>&1', r'')
173 return matchoutput('hg root 2>&1', r'')
170
174
171 checks = {
175 checks = {
172 "baz": (has_baz, "GNU Arch baz client"),
176 "baz": (has_baz, "GNU Arch baz client"),
173 "bzr": (has_bzr, "Canonical's Bazaar client"),
177 "bzr": (has_bzr, "Canonical's Bazaar client"),
174 "bzr114": (has_bzr114, "Canonical's Bazaar client >= 1.14"),
178 "bzr114": (has_bzr114, "Canonical's Bazaar client >= 1.14"),
175 "cvs": (has_cvs, "cvs client/server"),
179 "cvs": (has_cvs, "cvs client/server"),
176 "cvsps": (has_cvsps, "cvsps utility"),
180 "cvsps": (has_cvsps, "cvsps utility"),
177 "darcs": (has_darcs, "darcs client"),
181 "darcs": (has_darcs, "darcs client"),
178 "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
182 "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
179 "execbit": (has_executablebit, "executable bit"),
183 "execbit": (has_executablebit, "executable bit"),
180 "fifo": (has_fifo, "named pipes"),
184 "fifo": (has_fifo, "named pipes"),
181 "git": (has_git, "git command line client"),
185 "git": (has_git, "git command line client"),
182 "hotshot": (has_hotshot, "python hotshot module"),
186 "hotshot": (has_hotshot, "python hotshot module"),
183 "icasefs": (has_icasefs, "case insensitive file system"),
187 "icasefs": (has_icasefs, "case insensitive file system"),
184 "inotify": (has_inotify, "inotify extension support"),
188 "inotify": (has_inotify, "inotify extension support"),
185 "lsprof": (has_lsprof, "python lsprof module"),
189 "lsprof": (has_lsprof, "python lsprof module"),
186 "mtn": (has_mtn, "monotone client (> 0.31)"),
190 "mtn": (has_mtn, "monotone client (> 0.31)"),
187 "outer-repo": (has_outer_repo, "outer repo"),
191 "outer-repo": (has_outer_repo, "outer repo"),
188 "p4": (has_p4, "Perforce server and client"),
192 "p4": (has_p4, "Perforce server and client"),
189 "pygments": (has_pygments, "Pygments source highlighting library"),
193 "pygments": (has_pygments, "Pygments source highlighting library"),
190 "svn": (has_svn, "subversion client and admin tools"),
194 "svn": (has_svn, "subversion client and admin tools"),
191 "svn-bindings": (has_svn_bindings, "subversion python bindings"),
195 "svn-bindings": (has_svn_bindings, "subversion python bindings"),
192 "symlink": (has_symlink, "symbolic links"),
196 "symlink": (has_symlink, "symbolic links"),
193 "tla": (has_tla, "GNU Arch tla client"),
197 "tla": (has_tla, "GNU Arch tla client"),
194 "unix-permissions": (has_unix_permissions, "unix-style permissions"),
198 "unix-permissions": (has_unix_permissions, "unix-style permissions"),
195 }
199 }
196
200
197 def list_features():
201 def list_features():
198 for name, feature in checks.iteritems():
202 for name, feature in checks.iteritems():
199 desc = feature[1]
203 desc = feature[1]
200 print name + ':', desc
204 print name + ':', desc
201
205
202 def test_features():
206 def test_features():
203 failed = 0
207 failed = 0
204 for name, feature in checks.iteritems():
208 for name, feature in checks.iteritems():
205 check, _ = feature
209 check, _ = feature
206 try:
210 try:
207 check()
211 check()
208 except Exception, e:
212 except Exception, e:
209 print "feature %s failed: %s" % (name, e)
213 print "feature %s failed: %s" % (name, e)
210 failed += 1
214 failed += 1
211 return failed
215 return failed
212
216
213 parser = optparse.OptionParser("%prog [options] [features]")
217 parser = optparse.OptionParser("%prog [options] [features]")
214 parser.add_option("--test-features", action="store_true",
218 parser.add_option("--test-features", action="store_true",
215 help="test available features")
219 help="test available features")
216 parser.add_option("--list-features", action="store_true",
220 parser.add_option("--list-features", action="store_true",
217 help="list available features")
221 help="list available features")
218 parser.add_option("-q", "--quiet", action="store_true",
222 parser.add_option("-q", "--quiet", action="store_true",
219 help="check features silently")
223 help="check features silently")
220
224
221 if __name__ == '__main__':
225 if __name__ == '__main__':
222 options, args = parser.parse_args()
226 options, args = parser.parse_args()
223 if options.list_features:
227 if options.list_features:
224 list_features()
228 list_features()
225 sys.exit(0)
229 sys.exit(0)
226
230
227 if options.test_features:
231 if options.test_features:
228 sys.exit(test_features())
232 sys.exit(test_features())
229
233
230 quiet = options.quiet
234 quiet = options.quiet
231
235
232 failures = 0
236 failures = 0
233
237
234 def error(msg):
238 def error(msg):
235 global failures
239 global failures
236 if not quiet:
240 if not quiet:
237 sys.stderr.write(msg + '\n')
241 sys.stderr.write(msg + '\n')
238 failures += 1
242 failures += 1
239
243
240 for feature in args:
244 for feature in args:
241 negate = feature.startswith('no-')
245 negate = feature.startswith('no-')
242 if negate:
246 if negate:
243 feature = feature[3:]
247 feature = feature[3:]
244
248
245 if feature not in checks:
249 if feature not in checks:
246 error('skipped: unknown feature: ' + feature)
250 error('skipped: unknown feature: ' + feature)
247 continue
251 continue
248
252
249 check, desc = checks[feature]
253 check, desc = checks[feature]
250 try:
254 try:
251 available = check()
255 available = check()
252 except Exception, e:
256 except Exception, e:
253 error('hghave check failed: ' + feature)
257 error('hghave check failed: ' + feature)
254 continue
258 continue
255
259
256 if not negate and not available:
260 if not negate and not available:
257 error('skipped: missing feature: ' + desc)
261 error('skipped: missing feature: ' + desc)
258 elif negate and available:
262 elif negate and available:
259 error('skipped: system supports %s' % desc)
263 error('skipped: system supports %s' % desc)
260
264
261 if failures != 0:
265 if failures != 0:
262 sys.exit(1)
266 sys.exit(1)
263
267
264
268
General Comments 0
You need to be logged in to leave comments. Login now