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