##// END OF EJS Templates
setup.py: keep Python 2.3 compatibility...
Martin Geisler -
r10124:08384d87 stable
parent child Browse files
Show More
@@ -1,285 +1,285 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 import os, subprocess, time
29 import os, subprocess, time
30 import shutil
30 import shutil
31 import tempfile
31 import tempfile
32 from distutils.core import setup, Extension
32 from distutils.core import setup, Extension
33 from distutils.dist import Distribution
33 from distutils.dist import Distribution
34 from distutils.command.install_data import install_data
34 from distutils.command.install_data import install_data
35 from distutils.command.build import build
35 from distutils.command.build import build
36 from distutils.command.build_py import build_py
36 from distutils.command.build_py import build_py
37 from distutils.spawn import spawn, find_executable
37 from distutils.spawn import spawn, find_executable
38 from distutils.ccompiler import new_compiler
38 from distutils.ccompiler import new_compiler
39
39
40 extra = {}
40 extra = {}
41 scripts = ['hg']
41 scripts = ['hg']
42 if os.name == 'nt':
42 if os.name == 'nt':
43 scripts.append('contrib/win32/hg.bat')
43 scripts.append('contrib/win32/hg.bat')
44
44
45 # simplified version of distutils.ccompiler.CCompiler.has_function
45 # simplified version of distutils.ccompiler.CCompiler.has_function
46 # that actually removes its temporary files.
46 # that actually removes its temporary files.
47 def has_function(cc, funcname):
47 def has_function(cc, funcname):
48 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
48 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
49 devnull = oldstderr = None
49 devnull = oldstderr = None
50 try:
50 try:
51 try:
51 try:
52 fname = os.path.join(tmpdir, 'funcname.c')
52 fname = os.path.join(tmpdir, 'funcname.c')
53 f = open(fname, 'w')
53 f = open(fname, 'w')
54 f.write('int main(void) {\n')
54 f.write('int main(void) {\n')
55 f.write(' %s();\n' % funcname)
55 f.write(' %s();\n' % funcname)
56 f.write('}\n')
56 f.write('}\n')
57 f.close()
57 f.close()
58 # Redirect stderr to /dev/null to hide any error messages
58 # Redirect stderr to /dev/null to hide any error messages
59 # from the compiler.
59 # from the compiler.
60 # This will have to be changed if we ever have to check
60 # This will have to be changed if we ever have to check
61 # for a function on Windows.
61 # for a function on Windows.
62 devnull = open('/dev/null', 'w')
62 devnull = open('/dev/null', 'w')
63 oldstderr = os.dup(sys.stderr.fileno())
63 oldstderr = os.dup(sys.stderr.fileno())
64 os.dup2(devnull.fileno(), sys.stderr.fileno())
64 os.dup2(devnull.fileno(), sys.stderr.fileno())
65 objects = cc.compile([fname], output_dir=tmpdir)
65 objects = cc.compile([fname], output_dir=tmpdir)
66 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
66 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
67 except:
67 except:
68 return False
68 return False
69 return True
69 return True
70 finally:
70 finally:
71 if oldstderr is not None:
71 if oldstderr is not None:
72 os.dup2(oldstderr, sys.stderr.fileno())
72 os.dup2(oldstderr, sys.stderr.fileno())
73 if devnull is not None:
73 if devnull is not None:
74 devnull.close()
74 devnull.close()
75 shutil.rmtree(tmpdir)
75 shutil.rmtree(tmpdir)
76
76
77 # py2exe needs to be installed to work
77 # py2exe needs to be installed to work
78 try:
78 try:
79 import py2exe
79 import py2exe
80
80
81 # Help py2exe to find win32com.shell
81 # Help py2exe to find win32com.shell
82 try:
82 try:
83 import modulefinder
83 import modulefinder
84 import win32com
84 import win32com
85 for p in win32com.__path__[1:]: # Take the path to win32comext
85 for p in win32com.__path__[1:]: # Take the path to win32comext
86 modulefinder.AddPackagePath("win32com", p)
86 modulefinder.AddPackagePath("win32com", p)
87 pn = "win32com.shell"
87 pn = "win32com.shell"
88 __import__(pn)
88 __import__(pn)
89 m = sys.modules[pn]
89 m = sys.modules[pn]
90 for p in m.__path__[1:]:
90 for p in m.__path__[1:]:
91 modulefinder.AddPackagePath(pn, p)
91 modulefinder.AddPackagePath(pn, p)
92 except ImportError:
92 except ImportError:
93 pass
93 pass
94
94
95 extra['console'] = ['hg']
95 extra['console'] = ['hg']
96
96
97 except ImportError:
97 except ImportError:
98 pass
98 pass
99
99
100 def runcmd(cmd, env):
100 def runcmd(cmd, env):
101 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
101 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
102 stderr=subprocess.PIPE, env=env)
102 stderr=subprocess.PIPE, env=env)
103 out, err = p.communicate()
103 out, err = p.communicate()
104 # If root is executing setup.py, but the repository is owned by
104 # If root is executing setup.py, but the repository is owned by
105 # another user (as in "sudo python setup.py install") we will get
105 # another user (as in "sudo python setup.py install") we will get
106 # trust warnings since the .hg/hgrc file is untrusted. That is
106 # trust warnings since the .hg/hgrc file is untrusted. That is
107 # fine, we don't want to load it anyway. Python may warn about
107 # fine, we don't want to load it anyway. Python may warn about
108 # a missing __init__.py in mercurial/locale, we also ignore that.
108 # a missing __init__.py in mercurial/locale, we also ignore that.
109 err = [e for e in err.splitlines()
109 err = [e for e in err.splitlines()
110 if not e.startswith('Not trusting file') \
110 if not e.startswith('Not trusting file') \
111 and not e.startswith('warning: Not importing')]
111 and not e.startswith('warning: Not importing')]
112 if err:
112 if err:
113 return ''
113 return ''
114 return out
114 return out
115
115
116 version = ''
116 version = ''
117
117
118 if os.path.isdir('.hg'):
118 if os.path.isdir('.hg'):
119 # Execute hg out of this directory with a custom environment which
119 # Execute hg out of this directory with a custom environment which
120 # includes the pure Python modules in mercurial/pure. We also take
120 # includes the pure Python modules in mercurial/pure. We also take
121 # care to not use any hgrc files and do no localization.
121 # care to not use any hgrc files and do no localization.
122 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
122 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
123 env = {'PYTHONPATH': os.pathsep.join(pypath),
123 env = {'PYTHONPATH': os.pathsep.join(pypath),
124 'HGRCPATH': '',
124 'HGRCPATH': '',
125 'LANGUAGE': 'C'}
125 'LANGUAGE': 'C'}
126 if 'LD_LIBRARY_PATH' in os.environ:
126 if 'LD_LIBRARY_PATH' in os.environ:
127 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
127 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
128 if 'SystemRoot' in os.environ:
128 if 'SystemRoot' in os.environ:
129 # Copy SystemRoot into the custom environment for Python 2.6
129 # Copy SystemRoot into the custom environment for Python 2.6
130 # under Windows. Otherwise, the subprocess will fail with
130 # under Windows. Otherwise, the subprocess will fail with
131 # error 0xc0150004. See: http://bugs.python.org/issue3440
131 # error 0xc0150004. See: http://bugs.python.org/issue3440
132 env['SystemRoot'] = os.environ['SystemRoot']
132 env['SystemRoot'] = os.environ['SystemRoot']
133 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
133 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
134 l = runcmd(cmd, env).split()
134 l = runcmd(cmd, env).split()
135 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
135 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
136 l.pop()
136 l.pop()
137 if len(l) > 1: # tag found
137 if len(l) > 1: # tag found
138 version = l[-1]
138 version = l[-1]
139 if l[0].endswith('+'): # propagate the dirty status to the tag
139 if l[0].endswith('+'): # propagate the dirty status to the tag
140 version += '+'
140 version += '+'
141 elif len(l) == 1: # no tag found
141 elif len(l) == 1: # no tag found
142 cmd = [sys.executable, 'hg', 'parents', '--template',
142 cmd = [sys.executable, 'hg', 'parents', '--template',
143 '{latesttag}+{latesttagdistance}-']
143 '{latesttag}+{latesttagdistance}-']
144 version = runcmd(cmd, env) + l[0]
144 version = runcmd(cmd, env) + l[0]
145 if version.endswith('+'):
145 if version.endswith('+'):
146 version += time.strftime('%Y%m%d')
146 version += time.strftime('%Y%m%d')
147 elif os.path.exists('.hg_archival.txt'):
147 elif os.path.exists('.hg_archival.txt'):
148 kw = dict([t.strip() for t in l.split(':', 1)]
148 kw = dict([[t.strip() for t in l.split(':', 1)]
149 for l in open('.hg_archival.txt'))
149 for l in open('.hg_archival.txt')])
150 if 'tag' in kw:
150 if 'tag' in kw:
151 version = kw['tag']
151 version = kw['tag']
152 elif 'latesttag' in kw:
152 elif 'latesttag' in kw:
153 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
153 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
154 else:
154 else:
155 version = kw.get('node', '')[:12]
155 version = kw.get('node', '')[:12]
156
156
157 if version:
157 if version:
158 f = open("mercurial/__version__.py", "w")
158 f = open("mercurial/__version__.py", "w")
159 f.write('# this file is autogenerated by setup.py\n')
159 f.write('# this file is autogenerated by setup.py\n')
160 f.write('version = "%s"\n' % version)
160 f.write('version = "%s"\n' % version)
161 f.close()
161 f.close()
162
162
163
163
164 try:
164 try:
165 from mercurial import __version__
165 from mercurial import __version__
166 version = __version__.version
166 version = __version__.version
167 except ImportError:
167 except ImportError:
168 version = 'unknown'
168 version = 'unknown'
169
169
170 class install_package_data(install_data):
170 class install_package_data(install_data):
171 def finalize_options(self):
171 def finalize_options(self):
172 self.set_undefined_options('install',
172 self.set_undefined_options('install',
173 ('install_lib', 'install_dir'))
173 ('install_lib', 'install_dir'))
174 install_data.finalize_options(self)
174 install_data.finalize_options(self)
175
175
176 class build_mo(build):
176 class build_mo(build):
177
177
178 description = "build translations (.mo files)"
178 description = "build translations (.mo files)"
179
179
180 def run(self):
180 def run(self):
181 if not find_executable('msgfmt'):
181 if not find_executable('msgfmt'):
182 self.warn("could not find msgfmt executable, no translations "
182 self.warn("could not find msgfmt executable, no translations "
183 "will be built")
183 "will be built")
184 return
184 return
185
185
186 podir = 'i18n'
186 podir = 'i18n'
187 if not os.path.isdir(podir):
187 if not os.path.isdir(podir):
188 self.warn("could not find %s/ directory" % podir)
188 self.warn("could not find %s/ directory" % podir)
189 return
189 return
190
190
191 join = os.path.join
191 join = os.path.join
192 for po in os.listdir(podir):
192 for po in os.listdir(podir):
193 if not po.endswith('.po'):
193 if not po.endswith('.po'):
194 continue
194 continue
195 pofile = join(podir, po)
195 pofile = join(podir, po)
196 modir = join('locale', po[:-3], 'LC_MESSAGES')
196 modir = join('locale', po[:-3], 'LC_MESSAGES')
197 mofile = join(modir, 'hg.mo')
197 mofile = join(modir, 'hg.mo')
198 cmd = ['msgfmt', '-v', '-o', mofile, pofile]
198 cmd = ['msgfmt', '-v', '-o', mofile, 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(modir)
202 self.mkpath(modir)
203 self.make_file([pofile], mofile, spawn, (cmd,))
203 self.make_file([pofile], mofile, spawn, (cmd,))
204 self.distribution.data_files.append((join('mercurial', modir),
204 self.distribution.data_files.append((join('mercurial', modir),
205 [mofile]))
205 [mofile]))
206
206
207 build.sub_commands.append(('build_mo', None))
207 build.sub_commands.append(('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 hg_build_py(build_py):
213 class hg_build_py(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 = {'install_data': install_package_data,
235 cmdclass = {'install_data': install_package_data,
236 'build_mo': build_mo,
236 'build_mo': build_mo,
237 'build_py': hg_build_py}
237 'build_py': hg_build_py}
238
238
239 ext_modules=[
239 ext_modules=[
240 Extension('mercurial.base85', ['mercurial/base85.c']),
240 Extension('mercurial.base85', ['mercurial/base85.c']),
241 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
241 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
242 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
242 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
243 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
243 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
244 Extension('mercurial.parsers', ['mercurial/parsers.c']),
244 Extension('mercurial.parsers', ['mercurial/parsers.c']),
245 Extension('mercurial.osutil', ['mercurial/osutil.c']),
245 Extension('mercurial.osutil', ['mercurial/osutil.c']),
246 ]
246 ]
247
247
248 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
248 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
249 'hgext.highlight', 'hgext.zeroconf', ]
249 'hgext.highlight', 'hgext.zeroconf', ]
250
250
251 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
251 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
252 # The inotify extension is only usable with Linux 2.6 kernels.
252 # The inotify extension is only usable with Linux 2.6 kernels.
253 # You also need a reasonably recent C library.
253 # You also need a reasonably recent C library.
254 cc = new_compiler()
254 cc = new_compiler()
255 if has_function(cc, 'inotify_add_watch'):
255 if has_function(cc, 'inotify_add_watch'):
256 ext_modules.append(Extension('hgext.inotify.linux._inotify',
256 ext_modules.append(Extension('hgext.inotify.linux._inotify',
257 ['hgext/inotify/linux/_inotify.c']))
257 ['hgext/inotify/linux/_inotify.c']))
258 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
258 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
259
259
260 datafiles = []
260 datafiles = []
261 for root in ('templates', 'i18n', 'help'):
261 for root in ('templates', 'i18n', 'help'):
262 for dir, dirs, files in os.walk(root):
262 for dir, dirs, files in os.walk(root):
263 dirs[:] = [x for x in dirs if not x.startswith('.')]
263 dirs[:] = [x for x in dirs if not x.startswith('.')]
264 files = [x for x in files if not x.startswith('.')]
264 files = [x for x in files if not x.startswith('.')]
265 datafiles.append((os.path.join('mercurial', dir),
265 datafiles.append((os.path.join('mercurial', dir),
266 [os.path.join(dir, file_) for file_ in files]))
266 [os.path.join(dir, file_) for file_ in files]))
267
267
268 setup(name='mercurial',
268 setup(name='mercurial',
269 version=version,
269 version=version,
270 author='Matt Mackall',
270 author='Matt Mackall',
271 author_email='mpm@selenic.com',
271 author_email='mpm@selenic.com',
272 url='http://mercurial.selenic.com/',
272 url='http://mercurial.selenic.com/',
273 description='Scalable distributed SCM',
273 description='Scalable distributed SCM',
274 license='GNU GPL',
274 license='GNU GPL',
275 scripts=scripts,
275 scripts=scripts,
276 packages=packages,
276 packages=packages,
277 ext_modules=ext_modules,
277 ext_modules=ext_modules,
278 data_files=datafiles,
278 data_files=datafiles,
279 cmdclass=cmdclass,
279 cmdclass=cmdclass,
280 options=dict(py2exe=dict(packages=['hgext', 'email']),
280 options=dict(py2exe=dict(packages=['hgext', 'email']),
281 bdist_mpkg=dict(zipdist=True,
281 bdist_mpkg=dict(zipdist=True,
282 license='COPYING',
282 license='COPYING',
283 readme='contrib/macosx/Readme.html',
283 readme='contrib/macosx/Readme.html',
284 welcome='contrib/macosx/Welcome.html')),
284 welcome='contrib/macosx/Welcome.html')),
285 **extra)
285 **extra)
General Comments 0
You need to be logged in to leave comments. Login now