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