##// END OF EJS Templates
setup: ignore failures to build optional inotify extension
Christian Boos -
r11468:1c1126b1 stable
parent child Browse files
Show More
@@ -1,313 +1,331 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # This is the mercurial setup script.
4 4 #
5 5 # 'python setup.py install', or
6 6 # 'python setup.py --help' for more options
7 7
8 8 import sys
9 9 if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
10 10 raise SystemExit("Mercurial requires Python 2.4 or later.")
11 11
12 12 # Solaris Python packaging brain damage
13 13 try:
14 14 import hashlib
15 15 sha = hashlib.sha1()
16 16 except:
17 17 try:
18 18 import sha
19 19 except:
20 20 raise SystemExit(
21 21 "Couldn't import standard hashlib (incomplete Python install).")
22 22
23 23 try:
24 24 import zlib
25 25 except:
26 26 raise SystemExit(
27 27 "Couldn't import standard zlib (incomplete Python install).")
28 28
29 29 try:
30 30 import bz2
31 31 except:
32 32 raise SystemExit(
33 33 "Couldn't import standard bz2 (incomplete Python install).")
34 34
35 35 import os, subprocess, time
36 36 import shutil
37 37 import tempfile
38 from distutils import log
38 39 from distutils.core import setup, Extension
39 40 from distutils.dist import Distribution
40 41 from distutils.command.build import build
42 from distutils.command.build_ext import build_ext
41 43 from distutils.command.build_py import build_py
42 44 from distutils.spawn import spawn, find_executable
43 45 from distutils.ccompiler import new_compiler
46 from distutils.errors import CCompilerError
44 47
45 48 scripts = ['hg']
46 49 if os.name == 'nt':
47 50 scripts.append('contrib/win32/hg.bat')
48 51
49 52 # simplified version of distutils.ccompiler.CCompiler.has_function
50 53 # that actually removes its temporary files.
51 54 def hasfunction(cc, funcname):
52 55 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
53 56 devnull = oldstderr = None
54 57 try:
55 58 try:
56 59 fname = os.path.join(tmpdir, 'funcname.c')
57 60 f = open(fname, 'w')
58 61 f.write('int main(void) {\n')
59 62 f.write(' %s();\n' % funcname)
60 63 f.write('}\n')
61 64 f.close()
62 65 # Redirect stderr to /dev/null to hide any error messages
63 66 # from the compiler.
64 67 # This will have to be changed if we ever have to check
65 68 # for a function on Windows.
66 69 devnull = open('/dev/null', 'w')
67 70 oldstderr = os.dup(sys.stderr.fileno())
68 71 os.dup2(devnull.fileno(), sys.stderr.fileno())
69 72 objects = cc.compile([fname], output_dir=tmpdir)
70 73 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
71 74 except:
72 75 return False
73 76 return True
74 77 finally:
75 78 if oldstderr is not None:
76 79 os.dup2(oldstderr, sys.stderr.fileno())
77 80 if devnull is not None:
78 81 devnull.close()
79 82 shutil.rmtree(tmpdir)
80 83
81 84 # py2exe needs to be installed to work
82 85 try:
83 86 import py2exe
84 87 py2exeloaded = True
85 88
86 89 # Help py2exe to find win32com.shell
87 90 try:
88 91 import modulefinder
89 92 import win32com
90 93 for p in win32com.__path__[1:]: # Take the path to win32comext
91 94 modulefinder.AddPackagePath("win32com", p)
92 95 pn = "win32com.shell"
93 96 __import__(pn)
94 97 m = sys.modules[pn]
95 98 for p in m.__path__[1:]:
96 99 modulefinder.AddPackagePath(pn, p)
97 100 except ImportError:
98 101 pass
99 102
100 103 except ImportError:
101 104 py2exeloaded = False
102 105 pass
103 106
104 107 def runcmd(cmd, env):
105 108 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
106 109 stderr=subprocess.PIPE, env=env)
107 110 out, err = p.communicate()
108 111 # If root is executing setup.py, but the repository is owned by
109 112 # another user (as in "sudo python setup.py install") we will get
110 113 # trust warnings since the .hg/hgrc file is untrusted. That is
111 114 # fine, we don't want to load it anyway. Python may warn about
112 115 # a missing __init__.py in mercurial/locale, we also ignore that.
113 116 err = [e for e in err.splitlines()
114 117 if not e.startswith('Not trusting file') \
115 118 and not e.startswith('warning: Not importing')]
116 119 if err:
117 120 return ''
118 121 return out
119 122
120 123 version = ''
121 124
122 125 if os.path.isdir('.hg'):
123 126 # Execute hg out of this directory with a custom environment which
124 127 # includes the pure Python modules in mercurial/pure. We also take
125 128 # care to not use any hgrc files and do no localization.
126 129 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
127 130 env = {'PYTHONPATH': os.pathsep.join(pypath),
128 131 'HGRCPATH': '',
129 132 'LANGUAGE': 'C'}
130 133 if 'LD_LIBRARY_PATH' in os.environ:
131 134 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
132 135 if 'SystemRoot' in os.environ:
133 136 # Copy SystemRoot into the custom environment for Python 2.6
134 137 # under Windows. Otherwise, the subprocess will fail with
135 138 # error 0xc0150004. See: http://bugs.python.org/issue3440
136 139 env['SystemRoot'] = os.environ['SystemRoot']
137 140 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
138 141 l = runcmd(cmd, env).split()
139 142 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
140 143 l.pop()
141 144 if len(l) > 1: # tag found
142 145 version = l[-1]
143 146 if l[0].endswith('+'): # propagate the dirty status to the tag
144 147 version += '+'
145 148 elif len(l) == 1: # no tag found
146 149 cmd = [sys.executable, 'hg', 'parents', '--template',
147 150 '{latesttag}+{latesttagdistance}-']
148 151 version = runcmd(cmd, env) + l[0]
149 152 if version.endswith('+'):
150 153 version += time.strftime('%Y%m%d')
151 154 elif os.path.exists('.hg_archival.txt'):
152 155 kw = dict([[t.strip() for t in l.split(':', 1)]
153 156 for l in open('.hg_archival.txt')])
154 157 if 'tag' in kw:
155 158 version = kw['tag']
156 159 elif 'latesttag' in kw:
157 160 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
158 161 else:
159 162 version = kw.get('node', '')[:12]
160 163
161 164 if version:
162 165 f = open("mercurial/__version__.py", "w")
163 166 f.write('# this file is autogenerated by setup.py\n')
164 167 f.write('version = "%s"\n' % version)
165 168 f.close()
166 169
167 170
168 171 try:
169 172 from mercurial import __version__
170 173 version = __version__.version
171 174 except ImportError:
172 175 version = 'unknown'
173 176
174 177 class hgbuildmo(build):
175 178
176 179 description = "build translations (.mo files)"
177 180
178 181 def run(self):
179 182 if not find_executable('msgfmt'):
180 183 self.warn("could not find msgfmt executable, no translations "
181 184 "will be built")
182 185 return
183 186
184 187 podir = 'i18n'
185 188 if not os.path.isdir(podir):
186 189 self.warn("could not find %s/ directory" % podir)
187 190 return
188 191
189 192 join = os.path.join
190 193 for po in os.listdir(podir):
191 194 if not po.endswith('.po'):
192 195 continue
193 196 pofile = join(podir, po)
194 197 modir = join('locale', po[:-3], 'LC_MESSAGES')
195 198 mofile = join(modir, 'hg.mo')
196 199 mobuildfile = join('mercurial', mofile)
197 200 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
198 201 if sys.platform != 'sunos5':
199 202 # msgfmt on Solaris does not know about -c
200 203 cmd.append('-c')
201 204 self.mkpath(join('mercurial', modir))
202 205 self.make_file([pofile], mobuildfile, spawn, (cmd,))
203 206
204 207 # Insert hgbuildmo first so that files in mercurial/locale/ are found
205 208 # when build_py is run next.
206 209 build.sub_commands.insert(0, ('build_mo', None))
207 210
208 211 Distribution.pure = 0
209 212 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
210 213 "code instead of C extensions"))
211 214
215 class hgbuildext(build_ext):
216
217 def build_extension(self, ext):
218 try:
219 build_ext.build_extension(self, ext)
220 except CCompilerError:
221 if not hasattr(ext, 'optional') or not ext.optional:
222 raise
223 log.warn("Failed to build optional extension '%s' (skipping)",
224 ext.name)
225
212 226 class hgbuildpy(build_py):
213 227
214 228 def finalize_options(self):
215 229 build_py.finalize_options(self)
216 230
217 231 if self.distribution.pure:
218 232 if self.py_modules is None:
219 233 self.py_modules = []
220 234 for ext in self.distribution.ext_modules:
221 235 if ext.name.startswith("mercurial."):
222 236 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
223 237 self.distribution.ext_modules = []
224 238
225 239 def find_modules(self):
226 240 modules = build_py.find_modules(self)
227 241 for module in modules:
228 242 if module[0] == "mercurial.pure":
229 243 if module[1] != "__init__":
230 244 yield ("mercurial", module[1], module[2])
231 245 else:
232 246 yield module
233 247
234 248 cmdclass = {'build_mo': hgbuildmo,
249 'build_ext': hgbuildext,
235 250 'build_py': hgbuildpy}
236 251
237 252 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
238 253 'hgext.highlight', 'hgext.zeroconf']
239 254
240 255 pymodules = []
241 256
242 257 extmodules = [
243 258 Extension('mercurial.base85', ['mercurial/base85.c']),
244 259 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
245 260 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
246 261 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
247 262 Extension('mercurial.parsers', ['mercurial/parsers.c']),
248 263 ]
249 264
250 265 # disable osutil.c under windows + python 2.4 (issue1364)
251 266 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
252 267 pymodules.append('mercurial.pure.osutil')
253 268 else:
254 269 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c']))
255 270
256 271 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
257 272 # The inotify extension is only usable with Linux 2.6 kernels.
258 273 # You also need a reasonably recent C library.
274 # In any case, if it fails to build the error will be skipped ('optional').
259 275 cc = new_compiler()
260 276 if hasfunction(cc, 'inotify_add_watch'):
261 extmodules.append(Extension('hgext.inotify.linux._inotify',
262 ['hgext/inotify/linux/_inotify.c']))
277 inotify = Extension('hgext.inotify.linux._inotify',
278 ['hgext/inotify/linux/_inotify.c'])
279 inotify.optional = True
280 extmodules.append(inotify)
263 281 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
264 282
265 283 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
266 284 'help/*.txt']}
267 285
268 286 def ordinarypath(p):
269 287 return p and p[0] != '.' and p[-1] != '~'
270 288
271 289 for root in ('templates',):
272 290 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
273 291 curdir = curdir.split(os.sep, 1)[1]
274 292 dirs[:] = filter(ordinarypath, dirs)
275 293 for f in filter(ordinarypath, files):
276 294 f = os.path.join(curdir, f)
277 295 packagedata['mercurial'].append(f)
278 296
279 297 datafiles = []
280 298 setupversion = version
281 299 extra = {}
282 300
283 301 if py2exeloaded:
284 302 extra['console'] = [
285 303 {'script':'hg',
286 304 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
287 305 'product_version':version}]
288 306
289 307 if os.name == 'nt':
290 308 # Windows binary file versions for exe/dll files must have the
291 309 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
292 310 setupversion = version.split('+', 1)[0]
293 311
294 312 setup(name='mercurial',
295 313 version=setupversion,
296 314 author='Matt Mackall',
297 315 author_email='mpm@selenic.com',
298 316 url='http://mercurial.selenic.com/',
299 317 description='Scalable distributed SCM',
300 318 license='GNU GPLv2+',
301 319 scripts=scripts,
302 320 packages=packages,
303 321 py_modules=pymodules,
304 322 ext_modules=extmodules,
305 323 data_files=datafiles,
306 324 package_data=packagedata,
307 325 cmdclass=cmdclass,
308 326 options=dict(py2exe=dict(packages=['hgext', 'email']),
309 327 bdist_mpkg=dict(zipdist=True,
310 328 license='COPYING',
311 329 readme='contrib/macosx/Readme.html',
312 330 welcome='contrib/macosx/Welcome.html')),
313 331 **extra)
General Comments 0
You need to be logged in to leave comments. Login now