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