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