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