##// END OF EJS Templates
setup.py: do not install c extensions on pypy...
Joan Massich -
r24192:390410a6 default
parent child Browse files
Show More
@@ -1,646 +1,648
1 #
1 #
2 # This is the mercurial setup script.
2 # This is the mercurial setup script.
3 #
3 #
4 # 'python setup.py install', or
4 # 'python setup.py install', or
5 # 'python setup.py --help' for more options
5 # 'python setup.py --help' for more options
6
6
7 import sys, platform
7 import sys, platform
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
9 raise SystemExit("Mercurial requires Python 2.4 or later.")
9 raise SystemExit("Mercurial requires Python 2.4 or later.")
10
10
11 if sys.version_info[0] >= 3:
11 if sys.version_info[0] >= 3:
12 def b(s):
12 def b(s):
13 '''A helper function to emulate 2.6+ bytes literals using string
13 '''A helper function to emulate 2.6+ bytes literals using string
14 literals.'''
14 literals.'''
15 return s.encode('latin1')
15 return s.encode('latin1')
16 printf = eval('print')
16 printf = eval('print')
17 libdir_escape = 'unicode_escape'
17 libdir_escape = 'unicode_escape'
18 else:
18 else:
19 libdir_escape = 'string_escape'
19 libdir_escape = 'string_escape'
20 def b(s):
20 def b(s):
21 '''A helper function to emulate 2.6+ bytes literals using string
21 '''A helper function to emulate 2.6+ bytes literals using string
22 literals.'''
22 literals.'''
23 return s
23 return s
24 def printf(*args, **kwargs):
24 def printf(*args, **kwargs):
25 f = kwargs.get('file', sys.stdout)
25 f = kwargs.get('file', sys.stdout)
26 end = kwargs.get('end', '\n')
26 end = kwargs.get('end', '\n')
27 f.write(b(' ').join(args) + end)
27 f.write(b(' ').join(args) + end)
28
28
29 # Solaris Python packaging brain damage
29 # Solaris Python packaging brain damage
30 try:
30 try:
31 import hashlib
31 import hashlib
32 sha = hashlib.sha1()
32 sha = hashlib.sha1()
33 except ImportError:
33 except ImportError:
34 try:
34 try:
35 import sha
35 import sha
36 sha.sha # silence unused import warning
36 sha.sha # silence unused import warning
37 except ImportError:
37 except ImportError:
38 raise SystemExit(
38 raise SystemExit(
39 "Couldn't import standard hashlib (incomplete Python install).")
39 "Couldn't import standard hashlib (incomplete Python install).")
40
40
41 try:
41 try:
42 import zlib
42 import zlib
43 zlib.compressobj # silence unused import warning
43 zlib.compressobj # silence unused import warning
44 except ImportError:
44 except ImportError:
45 raise SystemExit(
45 raise SystemExit(
46 "Couldn't import standard zlib (incomplete Python install).")
46 "Couldn't import standard zlib (incomplete Python install).")
47
47
48 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
48 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
49 isironpython = False
49 isironpython = False
50 try:
50 try:
51 isironpython = (platform.python_implementation()
51 isironpython = (platform.python_implementation()
52 .lower().find("ironpython") != -1)
52 .lower().find("ironpython") != -1)
53 except AttributeError:
53 except AttributeError:
54 pass
54 pass
55
55
56 if isironpython:
56 if isironpython:
57 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
57 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
58 else:
58 else:
59 try:
59 try:
60 import bz2
60 import bz2
61 bz2.BZ2Compressor # silence unused import warning
61 bz2.BZ2Compressor # silence unused import warning
62 except ImportError:
62 except ImportError:
63 raise SystemExit(
63 raise SystemExit(
64 "Couldn't import standard bz2 (incomplete Python install).")
64 "Couldn't import standard bz2 (incomplete Python install).")
65
65
66 ispypy = "PyPy" in sys.version
67
66 import os, stat, subprocess, time
68 import os, stat, subprocess, time
67 import re
69 import re
68 import shutil
70 import shutil
69 import tempfile
71 import tempfile
70 from distutils import log
72 from distutils import log
71 from distutils.core import setup, Command, Extension
73 from distutils.core import setup, Command, Extension
72 from distutils.dist import Distribution
74 from distutils.dist import Distribution
73 from distutils.command.build import build
75 from distutils.command.build import build
74 from distutils.command.build_ext import build_ext
76 from distutils.command.build_ext import build_ext
75 from distutils.command.build_py import build_py
77 from distutils.command.build_py import build_py
76 from distutils.command.install_lib import install_lib
78 from distutils.command.install_lib import install_lib
77 from distutils.command.install_scripts import install_scripts
79 from distutils.command.install_scripts import install_scripts
78 from distutils.spawn import spawn, find_executable
80 from distutils.spawn import spawn, find_executable
79 from distutils import file_util
81 from distutils import file_util
80 from distutils.errors import CCompilerError, DistutilsExecError
82 from distutils.errors import CCompilerError, DistutilsExecError
81 from distutils.sysconfig import get_python_inc, get_config_var
83 from distutils.sysconfig import get_python_inc, get_config_var
82 from distutils.version import StrictVersion
84 from distutils.version import StrictVersion
83
85
84 convert2to3 = '--c2to3' in sys.argv
86 convert2to3 = '--c2to3' in sys.argv
85 if convert2to3:
87 if convert2to3:
86 try:
88 try:
87 from distutils.command.build_py import build_py_2to3 as build_py
89 from distutils.command.build_py import build_py_2to3 as build_py
88 from lib2to3.refactor import get_fixers_from_package as getfixers
90 from lib2to3.refactor import get_fixers_from_package as getfixers
89 except ImportError:
91 except ImportError:
90 if sys.version_info[0] < 3:
92 if sys.version_info[0] < 3:
91 raise SystemExit("--c2to3 is only compatible with python3.")
93 raise SystemExit("--c2to3 is only compatible with python3.")
92 raise
94 raise
93 sys.path.append('contrib')
95 sys.path.append('contrib')
94 elif sys.version_info[0] >= 3:
96 elif sys.version_info[0] >= 3:
95 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
97 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
96
98
97 scripts = ['hg']
99 scripts = ['hg']
98 if os.name == 'nt':
100 if os.name == 'nt':
99 scripts.append('contrib/win32/hg.bat')
101 scripts.append('contrib/win32/hg.bat')
100
102
101 # simplified version of distutils.ccompiler.CCompiler.has_function
103 # simplified version of distutils.ccompiler.CCompiler.has_function
102 # that actually removes its temporary files.
104 # that actually removes its temporary files.
103 def hasfunction(cc, funcname):
105 def hasfunction(cc, funcname):
104 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
106 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
105 devnull = oldstderr = None
107 devnull = oldstderr = None
106 try:
108 try:
107 try:
109 try:
108 fname = os.path.join(tmpdir, 'funcname.c')
110 fname = os.path.join(tmpdir, 'funcname.c')
109 f = open(fname, 'w')
111 f = open(fname, 'w')
110 f.write('int main(void) {\n')
112 f.write('int main(void) {\n')
111 f.write(' %s();\n' % funcname)
113 f.write(' %s();\n' % funcname)
112 f.write('}\n')
114 f.write('}\n')
113 f.close()
115 f.close()
114 # Redirect stderr to /dev/null to hide any error messages
116 # Redirect stderr to /dev/null to hide any error messages
115 # from the compiler.
117 # from the compiler.
116 # This will have to be changed if we ever have to check
118 # This will have to be changed if we ever have to check
117 # for a function on Windows.
119 # for a function on Windows.
118 devnull = open('/dev/null', 'w')
120 devnull = open('/dev/null', 'w')
119 oldstderr = os.dup(sys.stderr.fileno())
121 oldstderr = os.dup(sys.stderr.fileno())
120 os.dup2(devnull.fileno(), sys.stderr.fileno())
122 os.dup2(devnull.fileno(), sys.stderr.fileno())
121 objects = cc.compile([fname], output_dir=tmpdir)
123 objects = cc.compile([fname], output_dir=tmpdir)
122 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
124 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
123 except Exception:
125 except Exception:
124 return False
126 return False
125 return True
127 return True
126 finally:
128 finally:
127 if oldstderr is not None:
129 if oldstderr is not None:
128 os.dup2(oldstderr, sys.stderr.fileno())
130 os.dup2(oldstderr, sys.stderr.fileno())
129 if devnull is not None:
131 if devnull is not None:
130 devnull.close()
132 devnull.close()
131 shutil.rmtree(tmpdir)
133 shutil.rmtree(tmpdir)
132
134
133 # py2exe needs to be installed to work
135 # py2exe needs to be installed to work
134 try:
136 try:
135 import py2exe
137 import py2exe
136 py2exe.Distribution # silence unused import warning
138 py2exe.Distribution # silence unused import warning
137 py2exeloaded = True
139 py2exeloaded = True
138 # import py2exe's patched Distribution class
140 # import py2exe's patched Distribution class
139 from distutils.core import Distribution
141 from distutils.core import Distribution
140 except ImportError:
142 except ImportError:
141 py2exeloaded = False
143 py2exeloaded = False
142
144
143 def runcmd(cmd, env):
145 def runcmd(cmd, env):
144 if (sys.platform == 'plan9'
146 if (sys.platform == 'plan9'
145 and (sys.version_info[0] == 2 and sys.version_info[1] < 7)):
147 and (sys.version_info[0] == 2 and sys.version_info[1] < 7)):
146 # subprocess kludge to work around issues in half-baked Python
148 # subprocess kludge to work around issues in half-baked Python
147 # ports, notably bichued/python:
149 # ports, notably bichued/python:
148 _, out, err = os.popen3(cmd)
150 _, out, err = os.popen3(cmd)
149 return str(out), str(err)
151 return str(out), str(err)
150 else:
152 else:
151 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
153 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
152 stderr=subprocess.PIPE, env=env)
154 stderr=subprocess.PIPE, env=env)
153 out, err = p.communicate()
155 out, err = p.communicate()
154 return out, err
156 return out, err
155
157
156 def runhg(cmd, env):
158 def runhg(cmd, env):
157 out, err = runcmd(cmd, env)
159 out, err = runcmd(cmd, env)
158 # If root is executing setup.py, but the repository is owned by
160 # If root is executing setup.py, but the repository is owned by
159 # another user (as in "sudo python setup.py install") we will get
161 # another user (as in "sudo python setup.py install") we will get
160 # trust warnings since the .hg/hgrc file is untrusted. That is
162 # trust warnings since the .hg/hgrc file is untrusted. That is
161 # fine, we don't want to load it anyway. Python may warn about
163 # fine, we don't want to load it anyway. Python may warn about
162 # a missing __init__.py in mercurial/locale, we also ignore that.
164 # a missing __init__.py in mercurial/locale, we also ignore that.
163 err = [e for e in err.splitlines()
165 err = [e for e in err.splitlines()
164 if not e.startswith(b('not trusting file')) \
166 if not e.startswith(b('not trusting file')) \
165 and not e.startswith(b('warning: Not importing')) \
167 and not e.startswith(b('warning: Not importing')) \
166 and not e.startswith(b('obsolete feature not enabled'))]
168 and not e.startswith(b('obsolete feature not enabled'))]
167 if err:
169 if err:
168 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
170 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
169 printf(b('\n').join([b(' ') + e for e in err]), file=sys.stderr)
171 printf(b('\n').join([b(' ') + e for e in err]), file=sys.stderr)
170 return ''
172 return ''
171 return out
173 return out
172
174
173 version = ''
175 version = ''
174
176
175 # Execute hg out of this directory with a custom environment which
177 # Execute hg out of this directory with a custom environment which
176 # includes the pure Python modules in mercurial/pure. We also take
178 # includes the pure Python modules in mercurial/pure. We also take
177 # care to not use any hgrc files and do no localization.
179 # care to not use any hgrc files and do no localization.
178 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
180 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
179 env = {'PYTHONPATH': os.pathsep.join(pypath),
181 env = {'PYTHONPATH': os.pathsep.join(pypath),
180 'HGRCPATH': '',
182 'HGRCPATH': '',
181 'LANGUAGE': 'C'}
183 'LANGUAGE': 'C'}
182 if 'LD_LIBRARY_PATH' in os.environ:
184 if 'LD_LIBRARY_PATH' in os.environ:
183 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
185 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
184 if 'SystemRoot' in os.environ:
186 if 'SystemRoot' in os.environ:
185 # Copy SystemRoot into the custom environment for Python 2.6
187 # Copy SystemRoot into the custom environment for Python 2.6
186 # under Windows. Otherwise, the subprocess will fail with
188 # under Windows. Otherwise, the subprocess will fail with
187 # error 0xc0150004. See: http://bugs.python.org/issue3440
189 # error 0xc0150004. See: http://bugs.python.org/issue3440
188 env['SystemRoot'] = os.environ['SystemRoot']
190 env['SystemRoot'] = os.environ['SystemRoot']
189
191
190 if os.path.isdir('.hg'):
192 if os.path.isdir('.hg'):
191 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
193 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
192 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
194 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
193 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
195 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
194 if numerictags: # tag(s) found
196 if numerictags: # tag(s) found
195 version = numerictags[-1]
197 version = numerictags[-1]
196 if hgid.endswith('+'): # propagate the dirty status to the tag
198 if hgid.endswith('+'): # propagate the dirty status to the tag
197 version += '+'
199 version += '+'
198 else: # no tag found
200 else: # no tag found
199 ltagcmd = [sys.executable, 'hg', 'parents', '--template',
201 ltagcmd = [sys.executable, 'hg', 'parents', '--template',
200 '{latesttag}']
202 '{latesttag}']
201 ltag = runhg(ltagcmd, env)
203 ltag = runhg(ltagcmd, env)
202 changessincecmd = [sys.executable, 'hg', 'log', '-T', 'x\n', '-r',
204 changessincecmd = [sys.executable, 'hg', 'log', '-T', 'x\n', '-r',
203 "only(.,'%s')" % ltag]
205 "only(.,'%s')" % ltag]
204 changessince = len(runhg(changessincecmd, env).splitlines())
206 changessince = len(runhg(changessincecmd, env).splitlines())
205 version = '%s+%s-%s' % (ltag, changessince, hgid)
207 version = '%s+%s-%s' % (ltag, changessince, hgid)
206 if version.endswith('+'):
208 if version.endswith('+'):
207 version += time.strftime('%Y%m%d')
209 version += time.strftime('%Y%m%d')
208 elif os.path.exists('.hg_archival.txt'):
210 elif os.path.exists('.hg_archival.txt'):
209 kw = dict([[t.strip() for t in l.split(':', 1)]
211 kw = dict([[t.strip() for t in l.split(':', 1)]
210 for l in open('.hg_archival.txt')])
212 for l in open('.hg_archival.txt')])
211 if 'tag' in kw:
213 if 'tag' in kw:
212 version = kw['tag']
214 version = kw['tag']
213 elif 'latesttag' in kw:
215 elif 'latesttag' in kw:
214 if 'changessincelatesttag' in kw:
216 if 'changessincelatesttag' in kw:
215 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
217 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
216 else:
218 else:
217 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
219 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
218 else:
220 else:
219 version = kw.get('node', '')[:12]
221 version = kw.get('node', '')[:12]
220
222
221 if version:
223 if version:
222 f = open("mercurial/__version__.py", "w")
224 f = open("mercurial/__version__.py", "w")
223 f.write('# this file is autogenerated by setup.py\n')
225 f.write('# this file is autogenerated by setup.py\n')
224 f.write('version = "%s"\n' % version)
226 f.write('version = "%s"\n' % version)
225 f.close()
227 f.close()
226
228
227
229
228 try:
230 try:
229 from mercurial import __version__
231 from mercurial import __version__
230 version = __version__.version
232 version = __version__.version
231 except ImportError:
233 except ImportError:
232 version = 'unknown'
234 version = 'unknown'
233
235
234 class hgbuild(build):
236 class hgbuild(build):
235 # Insert hgbuildmo first so that files in mercurial/locale/ are found
237 # Insert hgbuildmo first so that files in mercurial/locale/ are found
236 # when build_py is run next.
238 # when build_py is run next.
237 sub_commands = [('build_mo', None),
239 sub_commands = [('build_mo', None),
238
240
239 # We also need build_ext before build_py. Otherwise, when 2to3 is
241 # We also need build_ext before build_py. Otherwise, when 2to3 is
240 # called (in build_py), it will not find osutil & friends,
242 # called (in build_py), it will not find osutil & friends,
241 # thinking that those modules are global and, consequently, making
243 # thinking that those modules are global and, consequently, making
242 # a mess, now that all module imports are global.
244 # a mess, now that all module imports are global.
243
245
244 ('build_ext', build.has_ext_modules),
246 ('build_ext', build.has_ext_modules),
245 ] + build.sub_commands
247 ] + build.sub_commands
246
248
247 class hgbuildmo(build):
249 class hgbuildmo(build):
248
250
249 description = "build translations (.mo files)"
251 description = "build translations (.mo files)"
250
252
251 def run(self):
253 def run(self):
252 if not find_executable('msgfmt'):
254 if not find_executable('msgfmt'):
253 self.warn("could not find msgfmt executable, no translations "
255 self.warn("could not find msgfmt executable, no translations "
254 "will be built")
256 "will be built")
255 return
257 return
256
258
257 podir = 'i18n'
259 podir = 'i18n'
258 if not os.path.isdir(podir):
260 if not os.path.isdir(podir):
259 self.warn("could not find %s/ directory" % podir)
261 self.warn("could not find %s/ directory" % podir)
260 return
262 return
261
263
262 join = os.path.join
264 join = os.path.join
263 for po in os.listdir(podir):
265 for po in os.listdir(podir):
264 if not po.endswith('.po'):
266 if not po.endswith('.po'):
265 continue
267 continue
266 pofile = join(podir, po)
268 pofile = join(podir, po)
267 modir = join('locale', po[:-3], 'LC_MESSAGES')
269 modir = join('locale', po[:-3], 'LC_MESSAGES')
268 mofile = join(modir, 'hg.mo')
270 mofile = join(modir, 'hg.mo')
269 mobuildfile = join('mercurial', mofile)
271 mobuildfile = join('mercurial', mofile)
270 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
272 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
271 if sys.platform != 'sunos5':
273 if sys.platform != 'sunos5':
272 # msgfmt on Solaris does not know about -c
274 # msgfmt on Solaris does not know about -c
273 cmd.append('-c')
275 cmd.append('-c')
274 self.mkpath(join('mercurial', modir))
276 self.mkpath(join('mercurial', modir))
275 self.make_file([pofile], mobuildfile, spawn, (cmd,))
277 self.make_file([pofile], mobuildfile, spawn, (cmd,))
276
278
277
279
278 class hgdist(Distribution):
280 class hgdist(Distribution):
279 pure = 0
281 pure = ispypy
280
282
281 global_options = Distribution.global_options + \
283 global_options = Distribution.global_options + \
282 [('pure', None, "use pure (slow) Python "
284 [('pure', None, "use pure (slow) Python "
283 "code instead of C extensions"),
285 "code instead of C extensions"),
284 ('c2to3', None, "(experimental!) convert "
286 ('c2to3', None, "(experimental!) convert "
285 "code with 2to3"),
287 "code with 2to3"),
286 ]
288 ]
287
289
288 def has_ext_modules(self):
290 def has_ext_modules(self):
289 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
291 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
290 # too late for some cases
292 # too late for some cases
291 return not self.pure and Distribution.has_ext_modules(self)
293 return not self.pure and Distribution.has_ext_modules(self)
292
294
293 class hgbuildext(build_ext):
295 class hgbuildext(build_ext):
294
296
295 def build_extension(self, ext):
297 def build_extension(self, ext):
296 try:
298 try:
297 build_ext.build_extension(self, ext)
299 build_ext.build_extension(self, ext)
298 except CCompilerError:
300 except CCompilerError:
299 if not getattr(ext, 'optional', False):
301 if not getattr(ext, 'optional', False):
300 raise
302 raise
301 log.warn("Failed to build optional extension '%s' (skipping)",
303 log.warn("Failed to build optional extension '%s' (skipping)",
302 ext.name)
304 ext.name)
303
305
304 class hgbuildpy(build_py):
306 class hgbuildpy(build_py):
305 if convert2to3:
307 if convert2to3:
306 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
308 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
307 getfixers("hgfixes")))
309 getfixers("hgfixes")))
308
310
309 def finalize_options(self):
311 def finalize_options(self):
310 build_py.finalize_options(self)
312 build_py.finalize_options(self)
311
313
312 if self.distribution.pure:
314 if self.distribution.pure:
313 if self.py_modules is None:
315 if self.py_modules is None:
314 self.py_modules = []
316 self.py_modules = []
315 for ext in self.distribution.ext_modules:
317 for ext in self.distribution.ext_modules:
316 if ext.name.startswith("mercurial."):
318 if ext.name.startswith("mercurial."):
317 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
319 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
318 self.distribution.ext_modules = []
320 self.distribution.ext_modules = []
319 else:
321 else:
320 h = os.path.join(get_python_inc(), 'Python.h')
322 h = os.path.join(get_python_inc(), 'Python.h')
321 if not os.path.exists(h):
323 if not os.path.exists(h):
322 raise SystemExit('Python headers are required to build '
324 raise SystemExit('Python headers are required to build '
323 'Mercurial but weren\'t found in %s' % h)
325 'Mercurial but weren\'t found in %s' % h)
324
326
325 def find_modules(self):
327 def find_modules(self):
326 modules = build_py.find_modules(self)
328 modules = build_py.find_modules(self)
327 for module in modules:
329 for module in modules:
328 if module[0] == "mercurial.pure":
330 if module[0] == "mercurial.pure":
329 if module[1] != "__init__":
331 if module[1] != "__init__":
330 yield ("mercurial", module[1], module[2])
332 yield ("mercurial", module[1], module[2])
331 else:
333 else:
332 yield module
334 yield module
333
335
334 class buildhgextindex(Command):
336 class buildhgextindex(Command):
335 description = 'generate prebuilt index of hgext (for frozen package)'
337 description = 'generate prebuilt index of hgext (for frozen package)'
336 user_options = []
338 user_options = []
337 _indexfilename = 'hgext/__index__.py'
339 _indexfilename = 'hgext/__index__.py'
338
340
339 def initialize_options(self):
341 def initialize_options(self):
340 pass
342 pass
341
343
342 def finalize_options(self):
344 def finalize_options(self):
343 pass
345 pass
344
346
345 def run(self):
347 def run(self):
346 if os.path.exists(self._indexfilename):
348 if os.path.exists(self._indexfilename):
347 f = open(self._indexfilename, 'w')
349 f = open(self._indexfilename, 'w')
348 f.write('# empty\n')
350 f.write('# empty\n')
349 f.close()
351 f.close()
350
352
351 # here no extension enabled, disabled() lists up everything
353 # here no extension enabled, disabled() lists up everything
352 code = ('import pprint; from mercurial import extensions; '
354 code = ('import pprint; from mercurial import extensions; '
353 'pprint.pprint(extensions.disabled())')
355 'pprint.pprint(extensions.disabled())')
354 out, err = runcmd([sys.executable, '-c', code], env)
356 out, err = runcmd([sys.executable, '-c', code], env)
355 if err:
357 if err:
356 raise DistutilsExecError(err)
358 raise DistutilsExecError(err)
357
359
358 f = open(self._indexfilename, 'w')
360 f = open(self._indexfilename, 'w')
359 f.write('# this file is autogenerated by setup.py\n')
361 f.write('# this file is autogenerated by setup.py\n')
360 f.write('docs = ')
362 f.write('docs = ')
361 f.write(out)
363 f.write(out)
362 f.close()
364 f.close()
363
365
364 class buildhgexe(build_ext):
366 class buildhgexe(build_ext):
365 description = 'compile hg.exe from mercurial/exewrapper.c'
367 description = 'compile hg.exe from mercurial/exewrapper.c'
366
368
367 def build_extensions(self):
369 def build_extensions(self):
368 if os.name != 'nt':
370 if os.name != 'nt':
369 return
371 return
370 if isinstance(self.compiler, HackedMingw32CCompiler):
372 if isinstance(self.compiler, HackedMingw32CCompiler):
371 self.compiler.compiler_so = self.compiler.compiler # no -mdll
373 self.compiler.compiler_so = self.compiler.compiler # no -mdll
372 self.compiler.dll_libraries = [] # no -lmsrvc90
374 self.compiler.dll_libraries = [] # no -lmsrvc90
373 hv = sys.hexversion
375 hv = sys.hexversion
374 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
376 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
375 f = open('mercurial/hgpythonlib.h', 'wb')
377 f = open('mercurial/hgpythonlib.h', 'wb')
376 f.write('/* this file is autogenerated by setup.py */\n')
378 f.write('/* this file is autogenerated by setup.py */\n')
377 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
379 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
378 f.close()
380 f.close()
379 objects = self.compiler.compile(['mercurial/exewrapper.c'],
381 objects = self.compiler.compile(['mercurial/exewrapper.c'],
380 output_dir=self.build_temp)
382 output_dir=self.build_temp)
381 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
383 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
382 target = os.path.join(dir, 'hg')
384 target = os.path.join(dir, 'hg')
383 self.compiler.link_executable(objects, target,
385 self.compiler.link_executable(objects, target,
384 libraries=[],
386 libraries=[],
385 output_dir=self.build_temp)
387 output_dir=self.build_temp)
386
388
387 class hginstalllib(install_lib):
389 class hginstalllib(install_lib):
388 '''
390 '''
389 This is a specialization of install_lib that replaces the copy_file used
391 This is a specialization of install_lib that replaces the copy_file used
390 there so that it supports setting the mode of files after copying them,
392 there so that it supports setting the mode of files after copying them,
391 instead of just preserving the mode that the files originally had. If your
393 instead of just preserving the mode that the files originally had. If your
392 system has a umask of something like 027, preserving the permissions when
394 system has a umask of something like 027, preserving the permissions when
393 copying will lead to a broken install.
395 copying will lead to a broken install.
394
396
395 Note that just passing keep_permissions=False to copy_file would be
397 Note that just passing keep_permissions=False to copy_file would be
396 insufficient, as it might still be applying a umask.
398 insufficient, as it might still be applying a umask.
397 '''
399 '''
398
400
399 def run(self):
401 def run(self):
400 realcopyfile = file_util.copy_file
402 realcopyfile = file_util.copy_file
401 def copyfileandsetmode(*args, **kwargs):
403 def copyfileandsetmode(*args, **kwargs):
402 src, dst = args[0], args[1]
404 src, dst = args[0], args[1]
403 dst, copied = realcopyfile(*args, **kwargs)
405 dst, copied = realcopyfile(*args, **kwargs)
404 if copied:
406 if copied:
405 st = os.stat(src)
407 st = os.stat(src)
406 # Persist executable bit (apply it to group and other if user
408 # Persist executable bit (apply it to group and other if user
407 # has it)
409 # has it)
408 if st[stat.ST_MODE] & stat.S_IXUSR:
410 if st[stat.ST_MODE] & stat.S_IXUSR:
409 setmode = 0755
411 setmode = 0755
410 else:
412 else:
411 setmode = 0644
413 setmode = 0644
412 os.chmod(dst, (stat.S_IMODE(st[stat.ST_MODE]) & ~0777) |
414 os.chmod(dst, (stat.S_IMODE(st[stat.ST_MODE]) & ~0777) |
413 setmode)
415 setmode)
414 file_util.copy_file = copyfileandsetmode
416 file_util.copy_file = copyfileandsetmode
415 try:
417 try:
416 install_lib.run(self)
418 install_lib.run(self)
417 finally:
419 finally:
418 file_util.copy_file = realcopyfile
420 file_util.copy_file = realcopyfile
419
421
420 class hginstallscripts(install_scripts):
422 class hginstallscripts(install_scripts):
421 '''
423 '''
422 This is a specialization of install_scripts that replaces the @LIBDIR@ with
424 This is a specialization of install_scripts that replaces the @LIBDIR@ with
423 the configured directory for modules. If possible, the path is made relative
425 the configured directory for modules. If possible, the path is made relative
424 to the directory for scripts.
426 to the directory for scripts.
425 '''
427 '''
426
428
427 def initialize_options(self):
429 def initialize_options(self):
428 install_scripts.initialize_options(self)
430 install_scripts.initialize_options(self)
429
431
430 self.install_lib = None
432 self.install_lib = None
431
433
432 def finalize_options(self):
434 def finalize_options(self):
433 install_scripts.finalize_options(self)
435 install_scripts.finalize_options(self)
434 self.set_undefined_options('install',
436 self.set_undefined_options('install',
435 ('install_lib', 'install_lib'))
437 ('install_lib', 'install_lib'))
436
438
437 def run(self):
439 def run(self):
438 install_scripts.run(self)
440 install_scripts.run(self)
439
441
440 if (os.path.splitdrive(self.install_dir)[0] !=
442 if (os.path.splitdrive(self.install_dir)[0] !=
441 os.path.splitdrive(self.install_lib)[0]):
443 os.path.splitdrive(self.install_lib)[0]):
442 # can't make relative paths from one drive to another, so use an
444 # can't make relative paths from one drive to another, so use an
443 # absolute path instead
445 # absolute path instead
444 libdir = self.install_lib
446 libdir = self.install_lib
445 else:
447 else:
446 common = os.path.commonprefix((self.install_dir, self.install_lib))
448 common = os.path.commonprefix((self.install_dir, self.install_lib))
447 rest = self.install_dir[len(common):]
449 rest = self.install_dir[len(common):]
448 uplevel = len([n for n in os.path.split(rest) if n])
450 uplevel = len([n for n in os.path.split(rest) if n])
449
451
450 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
452 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
451
453
452 for outfile in self.outfiles:
454 for outfile in self.outfiles:
453 fp = open(outfile, 'rb')
455 fp = open(outfile, 'rb')
454 data = fp.read()
456 data = fp.read()
455 fp.close()
457 fp.close()
456
458
457 # skip binary files
459 # skip binary files
458 if b('\0') in data:
460 if b('\0') in data:
459 continue
461 continue
460
462
461 data = data.replace(b('@LIBDIR@'), libdir.encode(libdir_escape))
463 data = data.replace(b('@LIBDIR@'), libdir.encode(libdir_escape))
462 fp = open(outfile, 'wb')
464 fp = open(outfile, 'wb')
463 fp.write(data)
465 fp.write(data)
464 fp.close()
466 fp.close()
465
467
466 cmdclass = {'build': hgbuild,
468 cmdclass = {'build': hgbuild,
467 'build_mo': hgbuildmo,
469 'build_mo': hgbuildmo,
468 'build_ext': hgbuildext,
470 'build_ext': hgbuildext,
469 'build_py': hgbuildpy,
471 'build_py': hgbuildpy,
470 'build_hgextindex': buildhgextindex,
472 'build_hgextindex': buildhgextindex,
471 'install_lib': hginstalllib,
473 'install_lib': hginstalllib,
472 'install_scripts': hginstallscripts,
474 'install_scripts': hginstallscripts,
473 'build_hgexe': buildhgexe,
475 'build_hgexe': buildhgexe,
474 }
476 }
475
477
476 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
478 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
477 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
479 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
478 'hgext.largefiles']
480 'hgext.largefiles']
479
481
480 pymodules = []
482 pymodules = []
481
483
482 common_depends = ['mercurial/util.h']
484 common_depends = ['mercurial/util.h']
483
485
484 extmodules = [
486 extmodules = [
485 Extension('mercurial.base85', ['mercurial/base85.c'],
487 Extension('mercurial.base85', ['mercurial/base85.c'],
486 depends=common_depends),
488 depends=common_depends),
487 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
489 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
488 depends=common_depends),
490 depends=common_depends),
489 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
491 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
490 depends=common_depends),
492 depends=common_depends),
491 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
493 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
492 depends=common_depends),
494 depends=common_depends),
493 Extension('mercurial.parsers', ['mercurial/dirs.c',
495 Extension('mercurial.parsers', ['mercurial/dirs.c',
494 'mercurial/parsers.c',
496 'mercurial/parsers.c',
495 'mercurial/pathencode.c'],
497 'mercurial/pathencode.c'],
496 depends=common_depends),
498 depends=common_depends),
497 ]
499 ]
498
500
499 osutil_ldflags = []
501 osutil_ldflags = []
500
502
501 if sys.platform == 'darwin':
503 if sys.platform == 'darwin':
502 osutil_ldflags += ['-framework', 'ApplicationServices']
504 osutil_ldflags += ['-framework', 'ApplicationServices']
503
505
504 # disable osutil.c under windows + python 2.4 (issue1364)
506 # disable osutil.c under windows + python 2.4 (issue1364)
505 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
507 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
506 pymodules.append('mercurial.pure.osutil')
508 pymodules.append('mercurial.pure.osutil')
507 else:
509 else:
508 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
510 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
509 extra_link_args=osutil_ldflags,
511 extra_link_args=osutil_ldflags,
510 depends=common_depends))
512 depends=common_depends))
511
513
512 try:
514 try:
513 from distutils import cygwinccompiler
515 from distutils import cygwinccompiler
514
516
515 # the -mno-cygwin option has been deprecated for years
517 # the -mno-cygwin option has been deprecated for years
516 compiler = cygwinccompiler.Mingw32CCompiler
518 compiler = cygwinccompiler.Mingw32CCompiler
517
519
518 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
520 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
519 def __init__(self, *args, **kwargs):
521 def __init__(self, *args, **kwargs):
520 compiler.__init__(self, *args, **kwargs)
522 compiler.__init__(self, *args, **kwargs)
521 for i in 'compiler compiler_so linker_exe linker_so'.split():
523 for i in 'compiler compiler_so linker_exe linker_so'.split():
522 try:
524 try:
523 getattr(self, i).remove('-mno-cygwin')
525 getattr(self, i).remove('-mno-cygwin')
524 except ValueError:
526 except ValueError:
525 pass
527 pass
526
528
527 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
529 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
528 except ImportError:
530 except ImportError:
529 # the cygwinccompiler package is not available on some Python
531 # the cygwinccompiler package is not available on some Python
530 # distributions like the ones from the optware project for Synology
532 # distributions like the ones from the optware project for Synology
531 # DiskStation boxes
533 # DiskStation boxes
532 class HackedMingw32CCompiler(object):
534 class HackedMingw32CCompiler(object):
533 pass
535 pass
534
536
535 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
537 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
536 'help/*.txt',
538 'help/*.txt',
537 'default.d/*.rc',
539 'default.d/*.rc',
538 'dummycert.pem']}
540 'dummycert.pem']}
539
541
540 def ordinarypath(p):
542 def ordinarypath(p):
541 return p and p[0] != '.' and p[-1] != '~'
543 return p and p[0] != '.' and p[-1] != '~'
542
544
543 for root in ('templates',):
545 for root in ('templates',):
544 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
546 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
545 curdir = curdir.split(os.sep, 1)[1]
547 curdir = curdir.split(os.sep, 1)[1]
546 dirs[:] = filter(ordinarypath, dirs)
548 dirs[:] = filter(ordinarypath, dirs)
547 for f in filter(ordinarypath, files):
549 for f in filter(ordinarypath, files):
548 f = os.path.join(curdir, f)
550 f = os.path.join(curdir, f)
549 packagedata['mercurial'].append(f)
551 packagedata['mercurial'].append(f)
550
552
551 datafiles = []
553 datafiles = []
552 setupversion = version
554 setupversion = version
553 extra = {}
555 extra = {}
554
556
555 if py2exeloaded:
557 if py2exeloaded:
556 extra['console'] = [
558 extra['console'] = [
557 {'script':'hg',
559 {'script':'hg',
558 'copyright':'Copyright (C) 2005-2015 Matt Mackall and others',
560 'copyright':'Copyright (C) 2005-2015 Matt Mackall and others',
559 'product_version':version}]
561 'product_version':version}]
560 # sub command of 'build' because 'py2exe' does not handle sub_commands
562 # sub command of 'build' because 'py2exe' does not handle sub_commands
561 build.sub_commands.insert(0, ('build_hgextindex', None))
563 build.sub_commands.insert(0, ('build_hgextindex', None))
562
564
563 if os.name == 'nt':
565 if os.name == 'nt':
564 # Windows binary file versions for exe/dll files must have the
566 # Windows binary file versions for exe/dll files must have the
565 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
567 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
566 setupversion = version.split('+', 1)[0]
568 setupversion = version.split('+', 1)[0]
567
569
568 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
570 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
569 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
571 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
570 if version:
572 if version:
571 version = version[0]
573 version = version[0]
572 xcode4 = (version.startswith('Xcode') and
574 xcode4 = (version.startswith('Xcode') and
573 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
575 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
574 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
576 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
575 else:
577 else:
576 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
578 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
577 # installed, but instead with only command-line tools. Assume
579 # installed, but instead with only command-line tools. Assume
578 # that only happens on >= Lion, thus no PPC support.
580 # that only happens on >= Lion, thus no PPC support.
579 xcode4 = True
581 xcode4 = True
580 xcode51 = False
582 xcode51 = False
581
583
582 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
584 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
583 # distutils.sysconfig
585 # distutils.sysconfig
584 if xcode4:
586 if xcode4:
585 os.environ['ARCHFLAGS'] = ''
587 os.environ['ARCHFLAGS'] = ''
586
588
587 # XCode 5.1 changes clang such that it now fails to compile if the
589 # XCode 5.1 changes clang such that it now fails to compile if the
588 # -mno-fused-madd flag is passed, but the version of Python shipped with
590 # -mno-fused-madd flag is passed, but the version of Python shipped with
589 # OS X 10.9 Mavericks includes this flag. This causes problems in all
591 # OS X 10.9 Mavericks includes this flag. This causes problems in all
590 # C extension modules, and a bug has been filed upstream at
592 # C extension modules, and a bug has been filed upstream at
591 # http://bugs.python.org/issue21244. We also need to patch this here
593 # http://bugs.python.org/issue21244. We also need to patch this here
592 # so Mercurial can continue to compile in the meantime.
594 # so Mercurial can continue to compile in the meantime.
593 if xcode51:
595 if xcode51:
594 cflags = get_config_var('CFLAGS')
596 cflags = get_config_var('CFLAGS')
595 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
597 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
596 os.environ['CFLAGS'] = (
598 os.environ['CFLAGS'] = (
597 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
599 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
598
600
599 setup(name='mercurial',
601 setup(name='mercurial',
600 version=setupversion,
602 version=setupversion,
601 author='Matt Mackall and many others',
603 author='Matt Mackall and many others',
602 author_email='mercurial@selenic.com',
604 author_email='mercurial@selenic.com',
603 url='http://mercurial.selenic.com/',
605 url='http://mercurial.selenic.com/',
604 download_url='http://mercurial.selenic.com/release/',
606 download_url='http://mercurial.selenic.com/release/',
605 description=('Fast scalable distributed SCM (revision control, version '
607 description=('Fast scalable distributed SCM (revision control, version '
606 'control) system'),
608 'control) system'),
607 long_description=('Mercurial is a distributed SCM tool written in Python.'
609 long_description=('Mercurial is a distributed SCM tool written in Python.'
608 ' It is used by a number of large projects that require'
610 ' It is used by a number of large projects that require'
609 ' fast, reliable distributed revision control, such as '
611 ' fast, reliable distributed revision control, such as '
610 'Mozilla.'),
612 'Mozilla.'),
611 license='GNU GPLv2 or any later version',
613 license='GNU GPLv2 or any later version',
612 classifiers=[
614 classifiers=[
613 'Development Status :: 6 - Mature',
615 'Development Status :: 6 - Mature',
614 'Environment :: Console',
616 'Environment :: Console',
615 'Intended Audience :: Developers',
617 'Intended Audience :: Developers',
616 'Intended Audience :: System Administrators',
618 'Intended Audience :: System Administrators',
617 'License :: OSI Approved :: GNU General Public License (GPL)',
619 'License :: OSI Approved :: GNU General Public License (GPL)',
618 'Natural Language :: Danish',
620 'Natural Language :: Danish',
619 'Natural Language :: English',
621 'Natural Language :: English',
620 'Natural Language :: German',
622 'Natural Language :: German',
621 'Natural Language :: Italian',
623 'Natural Language :: Italian',
622 'Natural Language :: Japanese',
624 'Natural Language :: Japanese',
623 'Natural Language :: Portuguese (Brazilian)',
625 'Natural Language :: Portuguese (Brazilian)',
624 'Operating System :: Microsoft :: Windows',
626 'Operating System :: Microsoft :: Windows',
625 'Operating System :: OS Independent',
627 'Operating System :: OS Independent',
626 'Operating System :: POSIX',
628 'Operating System :: POSIX',
627 'Programming Language :: C',
629 'Programming Language :: C',
628 'Programming Language :: Python',
630 'Programming Language :: Python',
629 'Topic :: Software Development :: Version Control',
631 'Topic :: Software Development :: Version Control',
630 ],
632 ],
631 scripts=scripts,
633 scripts=scripts,
632 packages=packages,
634 packages=packages,
633 py_modules=pymodules,
635 py_modules=pymodules,
634 ext_modules=extmodules,
636 ext_modules=extmodules,
635 data_files=datafiles,
637 data_files=datafiles,
636 package_data=packagedata,
638 package_data=packagedata,
637 cmdclass=cmdclass,
639 cmdclass=cmdclass,
638 distclass=hgdist,
640 distclass=hgdist,
639 options={'py2exe': {'packages': ['hgext', 'email']},
641 options={'py2exe': {'packages': ['hgext', 'email']},
640 'bdist_mpkg': {'zipdist': False,
642 'bdist_mpkg': {'zipdist': False,
641 'license': 'COPYING',
643 'license': 'COPYING',
642 'readme': 'contrib/macosx/Readme.html',
644 'readme': 'contrib/macosx/Readme.html',
643 'welcome': 'contrib/macosx/Welcome.html',
645 'welcome': 'contrib/macosx/Welcome.html',
644 },
646 },
645 },
647 },
646 **extra)
648 **extra)
General Comments 0
You need to be logged in to leave comments. Login now