##// END OF EJS Templates
setup: compile hg.exe...
Adrian Buehlmann -
r17061:f20e4d76 default
parent child Browse files
Show More
@@ -1,498 +1,513
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 else:
16 else:
17 def b(s):
17 def b(s):
18 '''A helper function to emulate 2.6+ bytes literals using string
18 '''A helper function to emulate 2.6+ bytes literals using string
19 literals.'''
19 literals.'''
20 return s
20 return s
21
21
22 # Solaris Python packaging brain damage
22 # Solaris Python packaging brain damage
23 try:
23 try:
24 import hashlib
24 import hashlib
25 sha = hashlib.sha1()
25 sha = hashlib.sha1()
26 except ImportError:
26 except ImportError:
27 try:
27 try:
28 import sha
28 import sha
29 except ImportError:
29 except ImportError:
30 raise SystemExit(
30 raise SystemExit(
31 "Couldn't import standard hashlib (incomplete Python install).")
31 "Couldn't import standard hashlib (incomplete Python install).")
32
32
33 try:
33 try:
34 import zlib
34 import zlib
35 except ImportError:
35 except ImportError:
36 raise SystemExit(
36 raise SystemExit(
37 "Couldn't import standard zlib (incomplete Python install).")
37 "Couldn't import standard zlib (incomplete Python install).")
38
38
39 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
39 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 isironpython = False
40 isironpython = False
41 try:
41 try:
42 isironpython = (platform.python_implementation()
42 isironpython = (platform.python_implementation()
43 .lower().find("ironpython") != -1)
43 .lower().find("ironpython") != -1)
44 except AttributeError:
44 except AttributeError:
45 pass
45 pass
46
46
47 if isironpython:
47 if isironpython:
48 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
48 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
49 else:
49 else:
50 try:
50 try:
51 import bz2
51 import bz2
52 except ImportError:
52 except ImportError:
53 raise SystemExit(
53 raise SystemExit(
54 "Couldn't import standard bz2 (incomplete Python install).")
54 "Couldn't import standard bz2 (incomplete Python install).")
55
55
56 import os, subprocess, time
56 import os, subprocess, time
57 import shutil
57 import shutil
58 import tempfile
58 import tempfile
59 from distutils import log
59 from distutils import log
60 from distutils.core import setup, Command, Extension
60 from distutils.core import setup, Command, Extension
61 from distutils.dist import Distribution
61 from distutils.dist import Distribution
62 from distutils.command.build import build
62 from distutils.command.build import build
63 from distutils.command.build_ext import build_ext
63 from distutils.command.build_ext import build_ext
64 from distutils.command.build_py import build_py
64 from distutils.command.build_py import build_py
65 from distutils.command.install_scripts import install_scripts
65 from distutils.command.install_scripts import install_scripts
66 from distutils.spawn import spawn, find_executable
66 from distutils.spawn import spawn, find_executable
67 from distutils.ccompiler import new_compiler
67 from distutils.ccompiler import new_compiler
68 from distutils.errors import CCompilerError, DistutilsExecError
68 from distutils.errors import CCompilerError, DistutilsExecError
69 from distutils.sysconfig import get_python_inc
69 from distutils.sysconfig import get_python_inc
70 from distutils.version import StrictVersion
70 from distutils.version import StrictVersion
71
71
72 convert2to3 = '--c2to3' in sys.argv
72 convert2to3 = '--c2to3' in sys.argv
73 if convert2to3:
73 if convert2to3:
74 try:
74 try:
75 from distutils.command.build_py import build_py_2to3 as build_py
75 from distutils.command.build_py import build_py_2to3 as build_py
76 from lib2to3.refactor import get_fixers_from_package as getfixers
76 from lib2to3.refactor import get_fixers_from_package as getfixers
77 except ImportError:
77 except ImportError:
78 if sys.version_info[0] < 3:
78 if sys.version_info[0] < 3:
79 raise SystemExit("--c2to3 is only compatible with python3.")
79 raise SystemExit("--c2to3 is only compatible with python3.")
80 raise
80 raise
81 sys.path.append('contrib')
81 sys.path.append('contrib')
82 elif sys.version_info[0] >= 3:
82 elif sys.version_info[0] >= 3:
83 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
83 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
84
84
85 scripts = ['hg']
85 scripts = ['hg']
86 if os.name == 'nt':
86 if os.name == 'nt':
87 scripts.append('contrib/win32/hg.bat')
87 scripts.append('contrib/win32/hg.bat')
88
88
89 # simplified version of distutils.ccompiler.CCompiler.has_function
89 # simplified version of distutils.ccompiler.CCompiler.has_function
90 # that actually removes its temporary files.
90 # that actually removes its temporary files.
91 def hasfunction(cc, funcname):
91 def hasfunction(cc, funcname):
92 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
92 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
93 devnull = oldstderr = None
93 devnull = oldstderr = None
94 try:
94 try:
95 try:
95 try:
96 fname = os.path.join(tmpdir, 'funcname.c')
96 fname = os.path.join(tmpdir, 'funcname.c')
97 f = open(fname, 'w')
97 f = open(fname, 'w')
98 f.write('int main(void) {\n')
98 f.write('int main(void) {\n')
99 f.write(' %s();\n' % funcname)
99 f.write(' %s();\n' % funcname)
100 f.write('}\n')
100 f.write('}\n')
101 f.close()
101 f.close()
102 # Redirect stderr to /dev/null to hide any error messages
102 # Redirect stderr to /dev/null to hide any error messages
103 # from the compiler.
103 # from the compiler.
104 # This will have to be changed if we ever have to check
104 # This will have to be changed if we ever have to check
105 # for a function on Windows.
105 # for a function on Windows.
106 devnull = open('/dev/null', 'w')
106 devnull = open('/dev/null', 'w')
107 oldstderr = os.dup(sys.stderr.fileno())
107 oldstderr = os.dup(sys.stderr.fileno())
108 os.dup2(devnull.fileno(), sys.stderr.fileno())
108 os.dup2(devnull.fileno(), sys.stderr.fileno())
109 objects = cc.compile([fname], output_dir=tmpdir)
109 objects = cc.compile([fname], output_dir=tmpdir)
110 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
110 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
111 except Exception:
111 except Exception:
112 return False
112 return False
113 return True
113 return True
114 finally:
114 finally:
115 if oldstderr is not None:
115 if oldstderr is not None:
116 os.dup2(oldstderr, sys.stderr.fileno())
116 os.dup2(oldstderr, sys.stderr.fileno())
117 if devnull is not None:
117 if devnull is not None:
118 devnull.close()
118 devnull.close()
119 shutil.rmtree(tmpdir)
119 shutil.rmtree(tmpdir)
120
120
121 # py2exe needs to be installed to work
121 # py2exe needs to be installed to work
122 try:
122 try:
123 import py2exe
123 import py2exe
124 py2exeloaded = True
124 py2exeloaded = True
125 # import py2exe's patched Distribution class
125 # import py2exe's patched Distribution class
126 from distutils.core import Distribution
126 from distutils.core import Distribution
127 except ImportError:
127 except ImportError:
128 py2exeloaded = False
128 py2exeloaded = False
129
129
130 def runcmd(cmd, env):
130 def runcmd(cmd, env):
131 if sys.platform == 'plan9':
131 if sys.platform == 'plan9':
132 # subprocess kludge to work around issues in half-baked Python
132 # subprocess kludge to work around issues in half-baked Python
133 # ports, notably bichued/python:
133 # ports, notably bichued/python:
134 _, out, err = os.popen3(cmd)
134 _, out, err = os.popen3(cmd)
135 return str(out), str(err)
135 return str(out), str(err)
136 else:
136 else:
137 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
137 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
138 stderr=subprocess.PIPE, env=env)
138 stderr=subprocess.PIPE, env=env)
139 out, err = p.communicate()
139 out, err = p.communicate()
140 return out, err
140 return out, err
141
141
142 def runhg(cmd, env):
142 def runhg(cmd, env):
143 out, err = runcmd(cmd, env)
143 out, err = runcmd(cmd, env)
144 # If root is executing setup.py, but the repository is owned by
144 # If root is executing setup.py, but the repository is owned by
145 # another user (as in "sudo python setup.py install") we will get
145 # another user (as in "sudo python setup.py install") we will get
146 # trust warnings since the .hg/hgrc file is untrusted. That is
146 # trust warnings since the .hg/hgrc file is untrusted. That is
147 # fine, we don't want to load it anyway. Python may warn about
147 # fine, we don't want to load it anyway. Python may warn about
148 # a missing __init__.py in mercurial/locale, we also ignore that.
148 # a missing __init__.py in mercurial/locale, we also ignore that.
149 err = [e for e in err.splitlines()
149 err = [e for e in err.splitlines()
150 if not e.startswith(b('Not trusting file')) \
150 if not e.startswith(b('Not trusting file')) \
151 and not e.startswith(b('warning: Not importing'))]
151 and not e.startswith(b('warning: Not importing'))]
152 if err:
152 if err:
153 return ''
153 return ''
154 return out
154 return out
155
155
156 version = ''
156 version = ''
157
157
158 # Execute hg out of this directory with a custom environment which
158 # Execute hg out of this directory with a custom environment which
159 # includes the pure Python modules in mercurial/pure. We also take
159 # includes the pure Python modules in mercurial/pure. We also take
160 # care to not use any hgrc files and do no localization.
160 # care to not use any hgrc files and do no localization.
161 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
161 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
162 env = {'PYTHONPATH': os.pathsep.join(pypath),
162 env = {'PYTHONPATH': os.pathsep.join(pypath),
163 'HGRCPATH': '',
163 'HGRCPATH': '',
164 'LANGUAGE': 'C'}
164 'LANGUAGE': 'C'}
165 if 'LD_LIBRARY_PATH' in os.environ:
165 if 'LD_LIBRARY_PATH' in os.environ:
166 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
166 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
167 if 'SystemRoot' in os.environ:
167 if 'SystemRoot' in os.environ:
168 # Copy SystemRoot into the custom environment for Python 2.6
168 # Copy SystemRoot into the custom environment for Python 2.6
169 # under Windows. Otherwise, the subprocess will fail with
169 # under Windows. Otherwise, the subprocess will fail with
170 # error 0xc0150004. See: http://bugs.python.org/issue3440
170 # error 0xc0150004. See: http://bugs.python.org/issue3440
171 env['SystemRoot'] = os.environ['SystemRoot']
171 env['SystemRoot'] = os.environ['SystemRoot']
172
172
173 if os.path.isdir('.hg'):
173 if os.path.isdir('.hg'):
174 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
174 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
175 l = runhg(cmd, env).split()
175 l = runhg(cmd, env).split()
176 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
176 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
177 l.pop()
177 l.pop()
178 if len(l) > 1: # tag found
178 if len(l) > 1: # tag found
179 version = l[-1]
179 version = l[-1]
180 if l[0].endswith('+'): # propagate the dirty status to the tag
180 if l[0].endswith('+'): # propagate the dirty status to the tag
181 version += '+'
181 version += '+'
182 elif len(l) == 1: # no tag found
182 elif len(l) == 1: # no tag found
183 cmd = [sys.executable, 'hg', 'parents', '--template',
183 cmd = [sys.executable, 'hg', 'parents', '--template',
184 '{latesttag}+{latesttagdistance}-']
184 '{latesttag}+{latesttagdistance}-']
185 version = runhg(cmd, env) + l[0]
185 version = runhg(cmd, env) + l[0]
186 if version.endswith('+'):
186 if version.endswith('+'):
187 version += time.strftime('%Y%m%d')
187 version += time.strftime('%Y%m%d')
188 elif os.path.exists('.hg_archival.txt'):
188 elif os.path.exists('.hg_archival.txt'):
189 kw = dict([[t.strip() for t in l.split(':', 1)]
189 kw = dict([[t.strip() for t in l.split(':', 1)]
190 for l in open('.hg_archival.txt')])
190 for l in open('.hg_archival.txt')])
191 if 'tag' in kw:
191 if 'tag' in kw:
192 version = kw['tag']
192 version = kw['tag']
193 elif 'latesttag' in kw:
193 elif 'latesttag' in kw:
194 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
194 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
195 else:
195 else:
196 version = kw.get('node', '')[:12]
196 version = kw.get('node', '')[:12]
197
197
198 if version:
198 if version:
199 f = open("mercurial/__version__.py", "w")
199 f = open("mercurial/__version__.py", "w")
200 f.write('# this file is autogenerated by setup.py\n')
200 f.write('# this file is autogenerated by setup.py\n')
201 f.write('version = "%s"\n' % version)
201 f.write('version = "%s"\n' % version)
202 f.close()
202 f.close()
203
203
204
204
205 try:
205 try:
206 from mercurial import __version__
206 from mercurial import __version__
207 version = __version__.version
207 version = __version__.version
208 except ImportError:
208 except ImportError:
209 version = 'unknown'
209 version = 'unknown'
210
210
211 class hgbuild(build):
211 class hgbuild(build):
212 # Insert hgbuildmo first so that files in mercurial/locale/ are found
212 # Insert hgbuildmo first so that files in mercurial/locale/ are found
213 # when build_py is run next.
213 # when build_py is run next.
214 sub_commands = [('build_mo', None),
214 sub_commands = [('build_mo', None),
215
215
216 # We also need build_ext before build_py. Otherwise, when 2to3 is
216 # We also need build_ext before build_py. Otherwise, when 2to3 is
217 # called (in build_py), it will not find osutil & friends,
217 # called (in build_py), it will not find osutil & friends,
218 # thinking that those modules are global and, consequently, making
218 # thinking that those modules are global and, consequently, making
219 # a mess, now that all module imports are global.
219 # a mess, now that all module imports are global.
220
220
221 ('build_ext', build.has_ext_modules),
221 ('build_ext', build.has_ext_modules),
222 ] + build.sub_commands
222 ] + build.sub_commands
223
223
224 class hgbuildmo(build):
224 class hgbuildmo(build):
225
225
226 description = "build translations (.mo files)"
226 description = "build translations (.mo files)"
227
227
228 def run(self):
228 def run(self):
229 if not find_executable('msgfmt'):
229 if not find_executable('msgfmt'):
230 self.warn("could not find msgfmt executable, no translations "
230 self.warn("could not find msgfmt executable, no translations "
231 "will be built")
231 "will be built")
232 return
232 return
233
233
234 podir = 'i18n'
234 podir = 'i18n'
235 if not os.path.isdir(podir):
235 if not os.path.isdir(podir):
236 self.warn("could not find %s/ directory" % podir)
236 self.warn("could not find %s/ directory" % podir)
237 return
237 return
238
238
239 join = os.path.join
239 join = os.path.join
240 for po in os.listdir(podir):
240 for po in os.listdir(podir):
241 if not po.endswith('.po'):
241 if not po.endswith('.po'):
242 continue
242 continue
243 pofile = join(podir, po)
243 pofile = join(podir, po)
244 modir = join('locale', po[:-3], 'LC_MESSAGES')
244 modir = join('locale', po[:-3], 'LC_MESSAGES')
245 mofile = join(modir, 'hg.mo')
245 mofile = join(modir, 'hg.mo')
246 mobuildfile = join('mercurial', mofile)
246 mobuildfile = join('mercurial', mofile)
247 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
247 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
248 if sys.platform != 'sunos5':
248 if sys.platform != 'sunos5':
249 # msgfmt on Solaris does not know about -c
249 # msgfmt on Solaris does not know about -c
250 cmd.append('-c')
250 cmd.append('-c')
251 self.mkpath(join('mercurial', modir))
251 self.mkpath(join('mercurial', modir))
252 self.make_file([pofile], mobuildfile, spawn, (cmd,))
252 self.make_file([pofile], mobuildfile, spawn, (cmd,))
253
253
254
254
255 class hgdist(Distribution):
255 class hgdist(Distribution):
256 pure = 0
256 pure = 0
257
257
258 global_options = Distribution.global_options + \
258 global_options = Distribution.global_options + \
259 [('pure', None, "use pure (slow) Python "
259 [('pure', None, "use pure (slow) Python "
260 "code instead of C extensions"),
260 "code instead of C extensions"),
261 ('c2to3', None, "(experimental!) convert "
261 ('c2to3', None, "(experimental!) convert "
262 "code with 2to3"),
262 "code with 2to3"),
263 ]
263 ]
264
264
265 def has_ext_modules(self):
265 def has_ext_modules(self):
266 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
266 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
267 # too late for some cases
267 # too late for some cases
268 return not self.pure and Distribution.has_ext_modules(self)
268 return not self.pure and Distribution.has_ext_modules(self)
269
269
270 class hgbuildext(build_ext):
270 class hgbuildext(build_ext):
271
271
272 def build_extension(self, ext):
272 def build_extension(self, ext):
273 try:
273 try:
274 build_ext.build_extension(self, ext)
274 build_ext.build_extension(self, ext)
275 except CCompilerError:
275 except CCompilerError:
276 if not getattr(ext, 'optional', False):
276 if not getattr(ext, 'optional', False):
277 raise
277 raise
278 log.warn("Failed to build optional extension '%s' (skipping)",
278 log.warn("Failed to build optional extension '%s' (skipping)",
279 ext.name)
279 ext.name)
280
280
281 class hgbuildpy(build_py):
281 class hgbuildpy(build_py):
282 if convert2to3:
282 if convert2to3:
283 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
283 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
284 getfixers("hgfixes")))
284 getfixers("hgfixes")))
285
285
286 def finalize_options(self):
286 def finalize_options(self):
287 build_py.finalize_options(self)
287 build_py.finalize_options(self)
288
288
289 if self.distribution.pure:
289 if self.distribution.pure:
290 if self.py_modules is None:
290 if self.py_modules is None:
291 self.py_modules = []
291 self.py_modules = []
292 for ext in self.distribution.ext_modules:
292 for ext in self.distribution.ext_modules:
293 if ext.name.startswith("mercurial."):
293 if ext.name.startswith("mercurial."):
294 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
294 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
295 self.distribution.ext_modules = []
295 self.distribution.ext_modules = []
296 else:
296 else:
297 if not os.path.exists(os.path.join(get_python_inc(), 'Python.h')):
297 if not os.path.exists(os.path.join(get_python_inc(), 'Python.h')):
298 raise SystemExit('Python headers are required to build '
298 raise SystemExit('Python headers are required to build '
299 'Mercurial')
299 'Mercurial')
300
300
301 def find_modules(self):
301 def find_modules(self):
302 modules = build_py.find_modules(self)
302 modules = build_py.find_modules(self)
303 for module in modules:
303 for module in modules:
304 if module[0] == "mercurial.pure":
304 if module[0] == "mercurial.pure":
305 if module[1] != "__init__":
305 if module[1] != "__init__":
306 yield ("mercurial", module[1], module[2])
306 yield ("mercurial", module[1], module[2])
307 else:
307 else:
308 yield module
308 yield module
309
309
310 class buildhgextindex(Command):
310 class buildhgextindex(Command):
311 description = 'generate prebuilt index of hgext (for frozen package)'
311 description = 'generate prebuilt index of hgext (for frozen package)'
312 user_options = []
312 user_options = []
313 _indexfilename = 'hgext/__index__.py'
313 _indexfilename = 'hgext/__index__.py'
314
314
315 def initialize_options(self):
315 def initialize_options(self):
316 pass
316 pass
317
317
318 def finalize_options(self):
318 def finalize_options(self):
319 pass
319 pass
320
320
321 def run(self):
321 def run(self):
322 if os.path.exists(self._indexfilename):
322 if os.path.exists(self._indexfilename):
323 os.unlink(self._indexfilename)
323 os.unlink(self._indexfilename)
324
324
325 # here no extension enabled, disabled() lists up everything
325 # here no extension enabled, disabled() lists up everything
326 code = ('import pprint; from mercurial import extensions; '
326 code = ('import pprint; from mercurial import extensions; '
327 'pprint.pprint(extensions.disabled())')
327 'pprint.pprint(extensions.disabled())')
328 out, err = runcmd([sys.executable, '-c', code], env)
328 out, err = runcmd([sys.executable, '-c', code], env)
329 if err:
329 if err:
330 raise DistutilsExecError(err)
330 raise DistutilsExecError(err)
331
331
332 f = open(self._indexfilename, 'w')
332 f = open(self._indexfilename, 'w')
333 f.write('# this file is autogenerated by setup.py\n')
333 f.write('# this file is autogenerated by setup.py\n')
334 f.write('docs = ')
334 f.write('docs = ')
335 f.write(out)
335 f.write(out)
336 f.close()
336 f.close()
337
337
338 class buildhgexe(build_ext):
339 description = 'compile hg.exe from mercurial/exewrapper.c'
340
341 def build_extensions(self):
342 if os.name != 'nt':
343 return
344 objects = self.compiler.compile(['mercurial/exewrapper.c'],
345 output_dir=self.build_temp)
346 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
347 target = os.path.join(dir, 'hg')
348 self.compiler.link_executable(objects, target,
349 output_dir=self.build_temp)
350
338 class hginstallscripts(install_scripts):
351 class hginstallscripts(install_scripts):
339 '''
352 '''
340 This is a specialization of install_scripts that replaces the @LIBDIR@ with
353 This is a specialization of install_scripts that replaces the @LIBDIR@ with
341 the configured directory for modules. If possible, the path is made relative
354 the configured directory for modules. If possible, the path is made relative
342 to the directory for scripts.
355 to the directory for scripts.
343 '''
356 '''
344
357
345 def initialize_options(self):
358 def initialize_options(self):
346 install_scripts.initialize_options(self)
359 install_scripts.initialize_options(self)
347
360
348 self.install_lib = None
361 self.install_lib = None
349
362
350 def finalize_options(self):
363 def finalize_options(self):
351 install_scripts.finalize_options(self)
364 install_scripts.finalize_options(self)
352 self.set_undefined_options('install',
365 self.set_undefined_options('install',
353 ('install_lib', 'install_lib'))
366 ('install_lib', 'install_lib'))
354
367
355 def run(self):
368 def run(self):
356 install_scripts.run(self)
369 install_scripts.run(self)
357
370
358 if (os.path.splitdrive(self.install_dir)[0] !=
371 if (os.path.splitdrive(self.install_dir)[0] !=
359 os.path.splitdrive(self.install_lib)[0]):
372 os.path.splitdrive(self.install_lib)[0]):
360 # can't make relative paths from one drive to another, so use an
373 # can't make relative paths from one drive to another, so use an
361 # absolute path instead
374 # absolute path instead
362 libdir = self.install_lib
375 libdir = self.install_lib
363 else:
376 else:
364 common = os.path.commonprefix((self.install_dir, self.install_lib))
377 common = os.path.commonprefix((self.install_dir, self.install_lib))
365 rest = self.install_dir[len(common):]
378 rest = self.install_dir[len(common):]
366 uplevel = len([n for n in os.path.split(rest) if n])
379 uplevel = len([n for n in os.path.split(rest) if n])
367
380
368 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
381 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
369
382
370 for outfile in self.outfiles:
383 for outfile in self.outfiles:
371 fp = open(outfile, 'rb')
384 fp = open(outfile, 'rb')
372 data = fp.read()
385 data = fp.read()
373 fp.close()
386 fp.close()
374
387
375 # skip binary files
388 # skip binary files
376 if b('\0') in data:
389 if b('\0') in data:
377 continue
390 continue
378
391
379 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
392 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
380 fp = open(outfile, 'wb')
393 fp = open(outfile, 'wb')
381 fp.write(data)
394 fp.write(data)
382 fp.close()
395 fp.close()
383
396
384 cmdclass = {'build': hgbuild,
397 cmdclass = {'build': hgbuild,
385 'build_mo': hgbuildmo,
398 'build_mo': hgbuildmo,
386 'build_ext': hgbuildext,
399 'build_ext': hgbuildext,
387 'build_py': hgbuildpy,
400 'build_py': hgbuildpy,
388 'build_hgextindex': buildhgextindex,
401 'build_hgextindex': buildhgextindex,
389 'install_scripts': hginstallscripts}
402 'install_scripts': hginstallscripts,
403 'build_hgexe': buildhgexe,
404 }
390
405
391 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
406 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
392 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
407 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
393 'hgext.largefiles']
408 'hgext.largefiles']
394
409
395 pymodules = []
410 pymodules = []
396
411
397 extmodules = [
412 extmodules = [
398 Extension('mercurial.base85', ['mercurial/base85.c']),
413 Extension('mercurial.base85', ['mercurial/base85.c']),
399 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
414 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
400 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
415 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
401 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
416 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
402 Extension('mercurial.parsers', ['mercurial/parsers.c']),
417 Extension('mercurial.parsers', ['mercurial/parsers.c']),
403 ]
418 ]
404
419
405 osutil_ldflags = []
420 osutil_ldflags = []
406
421
407 if sys.platform == 'darwin':
422 if sys.platform == 'darwin':
408 osutil_ldflags += ['-framework', 'ApplicationServices']
423 osutil_ldflags += ['-framework', 'ApplicationServices']
409
424
410 # disable osutil.c under windows + python 2.4 (issue1364)
425 # disable osutil.c under windows + python 2.4 (issue1364)
411 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
426 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
412 pymodules.append('mercurial.pure.osutil')
427 pymodules.append('mercurial.pure.osutil')
413 else:
428 else:
414 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
429 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
415 extra_link_args=osutil_ldflags))
430 extra_link_args=osutil_ldflags))
416
431
417 if sys.platform.startswith('linux') and os.uname()[2] > '2.6':
432 if sys.platform.startswith('linux') and os.uname()[2] > '2.6':
418 # The inotify extension is only usable with Linux 2.6 kernels.
433 # The inotify extension is only usable with Linux 2.6 kernels.
419 # You also need a reasonably recent C library.
434 # You also need a reasonably recent C library.
420 # In any case, if it fails to build the error will be skipped ('optional').
435 # In any case, if it fails to build the error will be skipped ('optional').
421 cc = new_compiler()
436 cc = new_compiler()
422 if hasfunction(cc, 'inotify_add_watch'):
437 if hasfunction(cc, 'inotify_add_watch'):
423 inotify = Extension('hgext.inotify.linux._inotify',
438 inotify = Extension('hgext.inotify.linux._inotify',
424 ['hgext/inotify/linux/_inotify.c'],
439 ['hgext/inotify/linux/_inotify.c'],
425 ['mercurial'])
440 ['mercurial'])
426 inotify.optional = True
441 inotify.optional = True
427 extmodules.append(inotify)
442 extmodules.append(inotify)
428 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
443 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
429
444
430 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
445 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
431 'help/*.txt']}
446 'help/*.txt']}
432
447
433 def ordinarypath(p):
448 def ordinarypath(p):
434 return p and p[0] != '.' and p[-1] != '~'
449 return p and p[0] != '.' and p[-1] != '~'
435
450
436 for root in ('templates',):
451 for root in ('templates',):
437 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
452 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
438 curdir = curdir.split(os.sep, 1)[1]
453 curdir = curdir.split(os.sep, 1)[1]
439 dirs[:] = filter(ordinarypath, dirs)
454 dirs[:] = filter(ordinarypath, dirs)
440 for f in filter(ordinarypath, files):
455 for f in filter(ordinarypath, files):
441 f = os.path.join(curdir, f)
456 f = os.path.join(curdir, f)
442 packagedata['mercurial'].append(f)
457 packagedata['mercurial'].append(f)
443
458
444 datafiles = []
459 datafiles = []
445 setupversion = version
460 setupversion = version
446 extra = {}
461 extra = {}
447
462
448 if py2exeloaded:
463 if py2exeloaded:
449 extra['console'] = [
464 extra['console'] = [
450 {'script':'hg',
465 {'script':'hg',
451 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
466 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
452 'product_version':version}]
467 'product_version':version}]
453 # sub command of 'build' because 'py2exe' does not handle sub_commands
468 # sub command of 'build' because 'py2exe' does not handle sub_commands
454 build.sub_commands.insert(0, ('build_hgextindex', None))
469 build.sub_commands.insert(0, ('build_hgextindex', None))
455
470
456 if os.name == 'nt':
471 if os.name == 'nt':
457 # Windows binary file versions for exe/dll files must have the
472 # Windows binary file versions for exe/dll files must have the
458 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
473 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
459 setupversion = version.split('+', 1)[0]
474 setupversion = version.split('+', 1)[0]
460
475
461 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
476 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
462 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
477 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
463 # distutils.sysconfig
478 # distutils.sysconfig
464 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
479 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
465 if version:
480 if version:
466 version = version[0]
481 version = version[0]
467 xcode4 = (version.startswith('Xcode') and
482 xcode4 = (version.startswith('Xcode') and
468 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
483 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
469 else:
484 else:
470 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
485 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
471 # installed, but instead with only command-line tools. Assume
486 # installed, but instead with only command-line tools. Assume
472 # that only happens on >= Lion, thus no PPC support.
487 # that only happens on >= Lion, thus no PPC support.
473 xcode4 = True
488 xcode4 = True
474
489
475 if xcode4:
490 if xcode4:
476 os.environ['ARCHFLAGS'] = ''
491 os.environ['ARCHFLAGS'] = ''
477
492
478 setup(name='mercurial',
493 setup(name='mercurial',
479 version=setupversion,
494 version=setupversion,
480 author='Matt Mackall',
495 author='Matt Mackall',
481 author_email='mpm@selenic.com',
496 author_email='mpm@selenic.com',
482 url='http://mercurial.selenic.com/',
497 url='http://mercurial.selenic.com/',
483 description='Scalable distributed SCM',
498 description='Scalable distributed SCM',
484 license='GNU GPLv2+',
499 license='GNU GPLv2+',
485 scripts=scripts,
500 scripts=scripts,
486 packages=packages,
501 packages=packages,
487 py_modules=pymodules,
502 py_modules=pymodules,
488 ext_modules=extmodules,
503 ext_modules=extmodules,
489 data_files=datafiles,
504 data_files=datafiles,
490 package_data=packagedata,
505 package_data=packagedata,
491 cmdclass=cmdclass,
506 cmdclass=cmdclass,
492 distclass=hgdist,
507 distclass=hgdist,
493 options=dict(py2exe=dict(packages=['hgext', 'email']),
508 options=dict(py2exe=dict(packages=['hgext', 'email']),
494 bdist_mpkg=dict(zipdist=True,
509 bdist_mpkg=dict(zipdist=True,
495 license='COPYING',
510 license='COPYING',
496 readme='contrib/macosx/Readme.html',
511 readme='contrib/macosx/Readme.html',
497 welcome='contrib/macosx/Welcome.html')),
512 welcome='contrib/macosx/Welcome.html')),
498 **extra)
513 **extra)
General Comments 0
You need to be logged in to leave comments. Login now