##// END OF EJS Templates
merge with stable
Benoit Boissinot -
r10769:d70ada7e merge default
parent child Browse files
Show More
@@ -1,314 +1,314 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # This is the mercurial setup script.
3 # This is the mercurial setup script.
4 #
4 #
5 # 'python setup.py install', or
5 # 'python setup.py install', or
6 # 'python setup.py --help' for more options
6 # 'python setup.py --help' for more options
7
7
8 import sys
8 import sys
9 if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
9 if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
10 raise SystemExit("Mercurial requires Python 2.4 or later.")
10 raise SystemExit("Mercurial requires Python 2.4 or later.")
11
11
12 # Solaris Python packaging brain damage
12 # Solaris Python packaging brain damage
13 try:
13 try:
14 import hashlib
14 import hashlib
15 sha = hashlib.sha1()
15 sha = hashlib.sha1()
16 except:
16 except:
17 try:
17 try:
18 import sha
18 import sha
19 except:
19 except:
20 raise SystemExit(
20 raise SystemExit(
21 "Couldn't import standard hashlib (incomplete Python install).")
21 "Couldn't import standard hashlib (incomplete Python install).")
22
22
23 try:
23 try:
24 import zlib
24 import zlib
25 except:
25 except:
26 raise SystemExit(
26 raise SystemExit(
27 "Couldn't import standard zlib (incomplete Python install).")
27 "Couldn't import standard zlib (incomplete Python install).")
28
28
29 try:
29 try:
30 import bz2
30 import bz2
31 except:
31 except:
32 raise SystemExit(
32 raise SystemExit(
33 "Couldn't import standard bz2 (incomplete Python install).")
33 "Couldn't import standard bz2 (incomplete Python install).")
34
34
35 import os, subprocess, time
35 import os, subprocess, time
36 import shutil
36 import shutil
37 import tempfile
37 import tempfile
38 from distutils.core import setup, Extension
38 from distutils.core import setup, Extension
39 from distutils.dist import Distribution
39 from distutils.dist import Distribution
40 from distutils.command.install_data import install_data
40 from distutils.command.install_data import install_data
41 from distutils.command.build import build
41 from distutils.command.build import build
42 from distutils.command.build_py import build_py
42 from distutils.command.build_py import build_py
43 from distutils.spawn import spawn, find_executable
43 from distutils.spawn import spawn, find_executable
44 from distutils.ccompiler import new_compiler
44 from distutils.ccompiler import new_compiler
45
45
46 scripts = ['hg']
46 scripts = ['hg']
47 if os.name == 'nt':
47 if os.name == 'nt':
48 scripts.append('contrib/win32/hg.bat')
48 scripts.append('contrib/win32/hg.bat')
49
49
50 # simplified version of distutils.ccompiler.CCompiler.has_function
50 # simplified version of distutils.ccompiler.CCompiler.has_function
51 # that actually removes its temporary files.
51 # that actually removes its temporary files.
52 def hasfunction(cc, funcname):
52 def hasfunction(cc, funcname):
53 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
53 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
54 devnull = oldstderr = None
54 devnull = oldstderr = None
55 try:
55 try:
56 try:
56 try:
57 fname = os.path.join(tmpdir, 'funcname.c')
57 fname = os.path.join(tmpdir, 'funcname.c')
58 f = open(fname, 'w')
58 f = open(fname, 'w')
59 f.write('int main(void) {\n')
59 f.write('int main(void) {\n')
60 f.write(' %s();\n' % funcname)
60 f.write(' %s();\n' % funcname)
61 f.write('}\n')
61 f.write('}\n')
62 f.close()
62 f.close()
63 # Redirect stderr to /dev/null to hide any error messages
63 # Redirect stderr to /dev/null to hide any error messages
64 # from the compiler.
64 # from the compiler.
65 # This will have to be changed if we ever have to check
65 # This will have to be changed if we ever have to check
66 # for a function on Windows.
66 # for a function on Windows.
67 devnull = open('/dev/null', 'w')
67 devnull = open('/dev/null', 'w')
68 oldstderr = os.dup(sys.stderr.fileno())
68 oldstderr = os.dup(sys.stderr.fileno())
69 os.dup2(devnull.fileno(), sys.stderr.fileno())
69 os.dup2(devnull.fileno(), sys.stderr.fileno())
70 objects = cc.compile([fname], output_dir=tmpdir)
70 objects = cc.compile([fname], output_dir=tmpdir)
71 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
71 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
72 except:
72 except:
73 return False
73 return False
74 return True
74 return True
75 finally:
75 finally:
76 if oldstderr is not None:
76 if oldstderr is not None:
77 os.dup2(oldstderr, sys.stderr.fileno())
77 os.dup2(oldstderr, sys.stderr.fileno())
78 if devnull is not None:
78 if devnull is not None:
79 devnull.close()
79 devnull.close()
80 shutil.rmtree(tmpdir)
80 shutil.rmtree(tmpdir)
81
81
82 # py2exe needs to be installed to work
82 # py2exe needs to be installed to work
83 try:
83 try:
84 import py2exe
84 import py2exe
85 py2exeloaded = True
85 py2exeloaded = True
86
86
87 # Help py2exe to find win32com.shell
87 # Help py2exe to find win32com.shell
88 try:
88 try:
89 import modulefinder
89 import modulefinder
90 import win32com
90 import win32com
91 for p in win32com.__path__[1:]: # Take the path to win32comext
91 for p in win32com.__path__[1:]: # Take the path to win32comext
92 modulefinder.AddPackagePath("win32com", p)
92 modulefinder.AddPackagePath("win32com", p)
93 pn = "win32com.shell"
93 pn = "win32com.shell"
94 __import__(pn)
94 __import__(pn)
95 m = sys.modules[pn]
95 m = sys.modules[pn]
96 for p in m.__path__[1:]:
96 for p in m.__path__[1:]:
97 modulefinder.AddPackagePath(pn, p)
97 modulefinder.AddPackagePath(pn, p)
98 except ImportError:
98 except ImportError:
99 pass
99 pass
100
100
101 except ImportError:
101 except ImportError:
102 py2exeloaded = False
102 py2exeloaded = False
103 pass
103 pass
104
104
105 def runcmd(cmd, env):
105 def runcmd(cmd, env):
106 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
106 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
107 stderr=subprocess.PIPE, env=env)
107 stderr=subprocess.PIPE, env=env)
108 out, err = p.communicate()
108 out, err = p.communicate()
109 # If root is executing setup.py, but the repository is owned by
109 # If root is executing setup.py, but the repository is owned by
110 # another user (as in "sudo python setup.py install") we will get
110 # another user (as in "sudo python setup.py install") we will get
111 # trust warnings since the .hg/hgrc file is untrusted. That is
111 # trust warnings since the .hg/hgrc file is untrusted. That is
112 # fine, we don't want to load it anyway. Python may warn about
112 # fine, we don't want to load it anyway. Python may warn about
113 # a missing __init__.py in mercurial/locale, we also ignore that.
113 # a missing __init__.py in mercurial/locale, we also ignore that.
114 err = [e for e in err.splitlines()
114 err = [e for e in err.splitlines()
115 if not e.startswith('Not trusting file') \
115 if not e.startswith('Not trusting file') \
116 and not e.startswith('warning: Not importing')]
116 and not e.startswith('warning: Not importing')]
117 if err:
117 if err:
118 return ''
118 return ''
119 return out
119 return out
120
120
121 version = ''
121 version = ''
122
122
123 if os.path.isdir('.hg'):
123 if os.path.isdir('.hg'):
124 # Execute hg out of this directory with a custom environment which
124 # Execute hg out of this directory with a custom environment which
125 # includes the pure Python modules in mercurial/pure. We also take
125 # includes the pure Python modules in mercurial/pure. We also take
126 # care to not use any hgrc files and do no localization.
126 # care to not use any hgrc files and do no localization.
127 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
127 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
128 env = {'PYTHONPATH': os.pathsep.join(pypath),
128 env = {'PYTHONPATH': os.pathsep.join(pypath),
129 'HGRCPATH': '',
129 'HGRCPATH': '',
130 'LANGUAGE': 'C'}
130 'LANGUAGE': 'C'}
131 if 'LD_LIBRARY_PATH' in os.environ:
131 if 'LD_LIBRARY_PATH' in os.environ:
132 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
132 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
133 if 'SystemRoot' in os.environ:
133 if 'SystemRoot' in os.environ:
134 # Copy SystemRoot into the custom environment for Python 2.6
134 # Copy SystemRoot into the custom environment for Python 2.6
135 # under Windows. Otherwise, the subprocess will fail with
135 # under Windows. Otherwise, the subprocess will fail with
136 # error 0xc0150004. See: http://bugs.python.org/issue3440
136 # error 0xc0150004. See: http://bugs.python.org/issue3440
137 env['SystemRoot'] = os.environ['SystemRoot']
137 env['SystemRoot'] = os.environ['SystemRoot']
138 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
138 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
139 l = runcmd(cmd, env).split()
139 l = runcmd(cmd, env).split()
140 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
140 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
141 l.pop()
141 l.pop()
142 if len(l) > 1: # tag found
142 if len(l) > 1: # tag found
143 version = l[-1]
143 version = l[-1]
144 if l[0].endswith('+'): # propagate the dirty status to the tag
144 if l[0].endswith('+'): # propagate the dirty status to the tag
145 version += '+'
145 version += '+'
146 elif len(l) == 1: # no tag found
146 elif len(l) == 1: # no tag found
147 cmd = [sys.executable, 'hg', 'parents', '--template',
147 cmd = [sys.executable, 'hg', 'parents', '--template',
148 '{latesttag}+{latesttagdistance}-']
148 '{latesttag}+{latesttagdistance}-']
149 version = runcmd(cmd, env) + l[0]
149 version = runcmd(cmd, env) + l[0]
150 if version.endswith('+'):
150 if version.endswith('+'):
151 version += time.strftime('%Y%m%d')
151 version += time.strftime('%Y%m%d')
152 elif os.path.exists('.hg_archival.txt'):
152 elif os.path.exists('.hg_archival.txt'):
153 kw = dict([[t.strip() for t in l.split(':', 1)]
153 kw = dict([[t.strip() for t in l.split(':', 1)]
154 for l in open('.hg_archival.txt')])
154 for l in open('.hg_archival.txt')])
155 if 'tag' in kw:
155 if 'tag' in kw:
156 version = kw['tag']
156 version = kw['tag']
157 elif 'latesttag' in kw:
157 elif 'latesttag' in kw:
158 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
158 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
159 else:
159 else:
160 version = kw.get('node', '')[:12]
160 version = kw.get('node', '')[:12]
161
161
162 if version:
162 if version:
163 f = open("mercurial/__version__.py", "w")
163 f = open("mercurial/__version__.py", "w")
164 f.write('# this file is autogenerated by setup.py\n')
164 f.write('# this file is autogenerated by setup.py\n')
165 f.write('version = "%s"\n' % version)
165 f.write('version = "%s"\n' % version)
166 f.close()
166 f.close()
167
167
168
168
169 try:
169 try:
170 from mercurial import __version__
170 from mercurial import __version__
171 version = __version__.version
171 version = __version__.version
172 except ImportError:
172 except ImportError:
173 version = 'unknown'
173 version = 'unknown'
174
174
175 class hgbuildmo(build):
175 class hgbuildmo(build):
176
176
177 description = "build translations (.mo files)"
177 description = "build translations (.mo files)"
178
178
179 def run(self):
179 def run(self):
180 if not find_executable('msgfmt'):
180 if not find_executable('msgfmt'):
181 self.warn("could not find msgfmt executable, no translations "
181 self.warn("could not find msgfmt executable, no translations "
182 "will be built")
182 "will be built")
183 return
183 return
184
184
185 podir = 'i18n'
185 podir = 'i18n'
186 if not os.path.isdir(podir):
186 if not os.path.isdir(podir):
187 self.warn("could not find %s/ directory" % podir)
187 self.warn("could not find %s/ directory" % podir)
188 return
188 return
189
189
190 join = os.path.join
190 join = os.path.join
191 for po in os.listdir(podir):
191 for po in os.listdir(podir):
192 if not po.endswith('.po'):
192 if not po.endswith('.po'):
193 continue
193 continue
194 pofile = join(podir, po)
194 pofile = join(podir, po)
195 modir = join('locale', po[:-3], 'LC_MESSAGES')
195 modir = join('locale', po[:-3], 'LC_MESSAGES')
196 mofile = join(modir, 'hg.mo')
196 mofile = join(modir, 'hg.mo')
197 mobuildfile = join('mercurial', mofile)
197 mobuildfile = join('mercurial', mofile)
198 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
198 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
199 if sys.platform != 'sunos5':
199 if sys.platform != 'sunos5':
200 # msgfmt on Solaris does not know about -c
200 # msgfmt on Solaris does not know about -c
201 cmd.append('-c')
201 cmd.append('-c')
202 self.mkpath(join('mercurial', modir))
202 self.mkpath(join('mercurial', modir))
203 self.make_file([pofile], mobuildfile, spawn, (cmd,))
203 self.make_file([pofile], mobuildfile, spawn, (cmd,))
204
204
205 # Insert hgbuildmo first so that files in mercurial/locale/ are found
205 # Insert hgbuildmo first so that files in mercurial/locale/ are found
206 # when build_py is run next.
206 # when build_py is run next.
207 build.sub_commands.insert(0, ('build_mo', None))
207 build.sub_commands.insert(0, ('build_mo', None))
208
208
209 Distribution.pure = 0
209 Distribution.pure = 0
210 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
210 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
211 "code instead of C extensions"))
211 "code instead of C extensions"))
212
212
213 class hgbuildpy(build_py):
213 class hgbuildpy(build_py):
214
214
215 def finalize_options(self):
215 def finalize_options(self):
216 build_py.finalize_options(self)
216 build_py.finalize_options(self)
217
217
218 if self.distribution.pure:
218 if self.distribution.pure:
219 if self.py_modules is None:
219 if self.py_modules is None:
220 self.py_modules = []
220 self.py_modules = []
221 for ext in self.distribution.ext_modules:
221 for ext in self.distribution.ext_modules:
222 if ext.name.startswith("mercurial."):
222 if ext.name.startswith("mercurial."):
223 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
223 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
224 self.distribution.ext_modules = []
224 self.distribution.ext_modules = []
225
225
226 def find_modules(self):
226 def find_modules(self):
227 modules = build_py.find_modules(self)
227 modules = build_py.find_modules(self)
228 for module in modules:
228 for module in modules:
229 if module[0] == "mercurial.pure":
229 if module[0] == "mercurial.pure":
230 if module[1] != "__init__":
230 if module[1] != "__init__":
231 yield ("mercurial", module[1], module[2])
231 yield ("mercurial", module[1], module[2])
232 else:
232 else:
233 yield module
233 yield module
234
234
235 cmdclass = {'build_mo': hgbuildmo,
235 cmdclass = {'build_mo': hgbuildmo,
236 'build_py': hgbuildpy}
236 'build_py': hgbuildpy}
237
237
238 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
238 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
239 'hgext.highlight', 'hgext.zeroconf']
239 'hgext.highlight', 'hgext.zeroconf']
240
240
241 pymodules = []
241 pymodules = []
242
242
243 extmodules = [
243 extmodules = [
244 Extension('mercurial.base85', ['mercurial/base85.c']),
244 Extension('mercurial.base85', ['mercurial/base85.c']),
245 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
245 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
246 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
246 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
247 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
247 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
248 Extension('mercurial.parsers', ['mercurial/parsers.c']),
248 Extension('mercurial.parsers', ['mercurial/parsers.c']),
249 ]
249 ]
250
250
251 # disable osutil.c under windows + python 2.4 (issue1364)
251 # disable osutil.c under windows + python 2.4 (issue1364)
252 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
252 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
253 pymodules.append('mercurial.pure.osutil')
253 pymodules.append('mercurial.pure.osutil')
254 else:
254 else:
255 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c']))
255 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c']))
256
256
257 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
257 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
258 # The inotify extension is only usable with Linux 2.6 kernels.
258 # The inotify extension is only usable with Linux 2.6 kernels.
259 # You also need a reasonably recent C library.
259 # You also need a reasonably recent C library.
260 cc = new_compiler()
260 cc = new_compiler()
261 if hasfunction(cc, 'inotify_add_watch'):
261 if hasfunction(cc, 'inotify_add_watch'):
262 extmodules.append(Extension('hgext.inotify.linux._inotify',
262 extmodules.append(Extension('hgext.inotify.linux._inotify',
263 ['hgext/inotify/linux/_inotify.c']))
263 ['hgext/inotify/linux/_inotify.c']))
264 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
264 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
265
265
266 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
266 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
267 'help/*.txt']}
267 'help/*.txt']}
268
268
269 def ordinarypath(p):
269 def ordinarypath(p):
270 return p and p[0] != '.' and p[-1] != '~'
270 return p and p[0] != '.' and p[-1] != '~'
271
271
272 for root in ('templates',):
272 for root in ('templates',):
273 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
273 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
274 curdir = curdir.split(os.sep, 1)[1]
274 curdir = curdir.split(os.sep, 1)[1]
275 dirs[:] = filter(ordinarypath, dirs)
275 dirs[:] = filter(ordinarypath, dirs)
276 for f in filter(ordinarypath, files):
276 for f in filter(ordinarypath, files):
277 f = os.path.join(curdir, f)
277 f = os.path.join(curdir, f)
278 packagedata['mercurial'].append(f)
278 packagedata['mercurial'].append(f)
279
279
280 datafiles = []
280 datafiles = []
281 setupversion = version
281 setupversion = version
282 extra = {}
282 extra = {}
283
283
284 if py2exeloaded:
284 if py2exeloaded:
285 extra['console'] = [
285 extra['console'] = [
286 {'script':'hg',
286 {'script':'hg',
287 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
287 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
288 'product_version':version}]
288 'product_version':version}]
289
289
290 if os.name == 'nt':
290 if os.name == 'nt':
291 # Windows binary file versions for exe/dll files must have the
291 # Windows binary file versions for exe/dll files must have the
292 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
292 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
293 setupversion = version.split('+', 1)[0]
293 setupversion = version.split('+', 1)[0]
294
294
295 setup(name='mercurial',
295 setup(name='mercurial',
296 version=setupversion,
296 version=setupversion,
297 author='Matt Mackall',
297 author='Matt Mackall',
298 author_email='mpm@selenic.com',
298 author_email='mpm@selenic.com',
299 url='http://mercurial.selenic.com/',
299 url='http://mercurial.selenic.com/',
300 description='Scalable distributed SCM',
300 description='Scalable distributed SCM',
301 license='GNU GPLv2+',
301 license='GNU GPLv2+',
302 scripts=scripts,
302 scripts=scripts,
303 packages=packages,
303 packages=packages,
304 py_modules=pymodules,
304 py_modules=pymodules,
305 ext_modules=extmodules,
305 ext_modules=extmodules,
306 data_files=datafiles,
306 data_files=datafiles,
307 package_data=packagedata,
307 package_data=packagedata,
308 cmdclass=cmdclass,
308 cmdclass=cmdclass,
309 options=dict(py2exe=dict(packages=['hgext', 'email']),
309 options=dict(py2exe=dict(packages=['hgext', 'email']),
310 bdist_mpkg=dict(zipdist=True,
310 bdist_mpkg=dict(zipdist=True,
311 license='COPYING',
311 license='COPYING',
312 readme='contrib/macosx/Readme.html',
312 readme='contrib/macosx/Readme.html',
313 welcome='contrib/macosx/Welcome.html')),
313 welcome='contrib/macosx/Welcome.html')),
314 **extra)
314 **extra)
General Comments 0
You need to be logged in to leave comments. Login now