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