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