##// END OF EJS Templates
setup: pass LD_LIBRARY_PATH to subprocess when determining version.
Christian Boos -
r9856:ed362d41 default
parent child Browse files
Show More
@@ -1,281 +1,283
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.
107 # fine, we don't want to load it anyway.
108 err = [e for e in err.splitlines()
108 err = [e for e in err.splitlines()
109 if not e.startswith('Not trusting file')]
109 if not e.startswith('Not trusting file')]
110 if err:
110 if err:
111 return ''
111 return ''
112 return out
112 return out
113
113
114 version = ''
114 version = ''
115
115
116 if os.path.isdir('.hg'):
116 if os.path.isdir('.hg'):
117 # Execute hg out of this directory with a custom environment which
117 # Execute hg out of this directory with a custom environment which
118 # includes the pure Python modules in mercurial/pure. We also take
118 # includes the pure Python modules in mercurial/pure. We also take
119 # care to not use any hgrc files and do no localization.
119 # care to not use any hgrc files and do no localization.
120 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
120 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
121 env = {'PYTHONPATH': os.pathsep.join(pypath),
121 env = {'PYTHONPATH': os.pathsep.join(pypath),
122 'HGRCPATH': '',
122 'HGRCPATH': '',
123 'LANGUAGE': 'C'}
123 'LANGUAGE': 'C'}
124 if 'LD_LIBRARY_PATH' in os.environ:
125 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
124 if 'SystemRoot' in os.environ:
126 if 'SystemRoot' in os.environ:
125 # Copy SystemRoot into the custom environment for Python 2.6
127 # Copy SystemRoot into the custom environment for Python 2.6
126 # under Windows. Otherwise, the subprocess will fail with
128 # under Windows. Otherwise, the subprocess will fail with
127 # error 0xc0150004. See: http://bugs.python.org/issue3440
129 # error 0xc0150004. See: http://bugs.python.org/issue3440
128 env['SystemRoot'] = os.environ['SystemRoot']
130 env['SystemRoot'] = os.environ['SystemRoot']
129 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
131 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
130 l = runcmd(cmd, env).split()
132 l = runcmd(cmd, env).split()
131 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
133 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
132 l.pop()
134 l.pop()
133 if len(l) > 1: # tag found
135 if len(l) > 1: # tag found
134 version = l[-1]
136 version = l[-1]
135 if l[0].endswith('+'): # propagate the dirty status to the tag
137 if l[0].endswith('+'): # propagate the dirty status to the tag
136 version += '+'
138 version += '+'
137 elif len(l) == 1: # no tag found
139 elif len(l) == 1: # no tag found
138 cmd = [sys.executable, 'hg', 'parents', '--template',
140 cmd = [sys.executable, 'hg', 'parents', '--template',
139 '{latesttag}+{latesttagdistance}-']
141 '{latesttag}+{latesttagdistance}-']
140 version = runcmd(cmd, env) + l[0]
142 version = runcmd(cmd, env) + l[0]
141 if version.endswith('+'):
143 if version.endswith('+'):
142 version += time.strftime('%Y%m%d')
144 version += time.strftime('%Y%m%d')
143 elif os.path.exists('.hg_archival.txt'):
145 elif os.path.exists('.hg_archival.txt'):
144 kw = dict([t.strip() for t in l.split(':', 1)]
146 kw = dict([t.strip() for t in l.split(':', 1)]
145 for l in open('.hg_archival.txt'))
147 for l in open('.hg_archival.txt'))
146 if 'tag' in kw:
148 if 'tag' in kw:
147 version = kw['tag']
149 version = kw['tag']
148 elif 'latesttag' in kw:
150 elif 'latesttag' in kw:
149 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
151 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
150 else:
152 else:
151 version = kw.get('node', '')[:12]
153 version = kw.get('node', '')[:12]
152
154
153 if version:
155 if version:
154 f = open("mercurial/__version__.py", "w")
156 f = open("mercurial/__version__.py", "w")
155 f.write('# this file is autogenerated by setup.py\n')
157 f.write('# this file is autogenerated by setup.py\n')
156 f.write('version = "%s"\n' % version)
158 f.write('version = "%s"\n' % version)
157 f.close()
159 f.close()
158
160
159
161
160 try:
162 try:
161 from mercurial import __version__
163 from mercurial import __version__
162 version = __version__.version
164 version = __version__.version
163 except ImportError:
165 except ImportError:
164 version = 'unknown'
166 version = 'unknown'
165
167
166 class install_package_data(install_data):
168 class install_package_data(install_data):
167 def finalize_options(self):
169 def finalize_options(self):
168 self.set_undefined_options('install',
170 self.set_undefined_options('install',
169 ('install_lib', 'install_dir'))
171 ('install_lib', 'install_dir'))
170 install_data.finalize_options(self)
172 install_data.finalize_options(self)
171
173
172 class build_mo(build):
174 class build_mo(build):
173
175
174 description = "build translations (.mo files)"
176 description = "build translations (.mo files)"
175
177
176 def run(self):
178 def run(self):
177 if not find_executable('msgfmt'):
179 if not find_executable('msgfmt'):
178 self.warn("could not find msgfmt executable, no translations "
180 self.warn("could not find msgfmt executable, no translations "
179 "will be built")
181 "will be built")
180 return
182 return
181
183
182 podir = 'i18n'
184 podir = 'i18n'
183 if not os.path.isdir(podir):
185 if not os.path.isdir(podir):
184 self.warn("could not find %s/ directory" % podir)
186 self.warn("could not find %s/ directory" % podir)
185 return
187 return
186
188
187 join = os.path.join
189 join = os.path.join
188 for po in os.listdir(podir):
190 for po in os.listdir(podir):
189 if not po.endswith('.po'):
191 if not po.endswith('.po'):
190 continue
192 continue
191 pofile = join(podir, po)
193 pofile = join(podir, po)
192 modir = join('locale', po[:-3], 'LC_MESSAGES')
194 modir = join('locale', po[:-3], 'LC_MESSAGES')
193 mofile = join(modir, 'hg.mo')
195 mofile = join(modir, 'hg.mo')
194 cmd = ['msgfmt', '-v', '-o', mofile, pofile]
196 cmd = ['msgfmt', '-v', '-o', mofile, pofile]
195 if sys.platform != 'sunos5':
197 if sys.platform != 'sunos5':
196 # msgfmt on Solaris does not know about -c
198 # msgfmt on Solaris does not know about -c
197 cmd.append('-c')
199 cmd.append('-c')
198 self.mkpath(modir)
200 self.mkpath(modir)
199 self.make_file([pofile], mofile, spawn, (cmd,))
201 self.make_file([pofile], mofile, spawn, (cmd,))
200 self.distribution.data_files.append((join('mercurial', modir),
202 self.distribution.data_files.append((join('mercurial', modir),
201 [mofile]))
203 [mofile]))
202
204
203 build.sub_commands.append(('build_mo', None))
205 build.sub_commands.append(('build_mo', None))
204
206
205 Distribution.pure = 0
207 Distribution.pure = 0
206 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
208 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
207 "code instead of C extensions"))
209 "code instead of C extensions"))
208
210
209 class hg_build_py(build_py):
211 class hg_build_py(build_py):
210
212
211 def finalize_options(self):
213 def finalize_options(self):
212 build_py.finalize_options(self)
214 build_py.finalize_options(self)
213
215
214 if self.distribution.pure:
216 if self.distribution.pure:
215 if self.py_modules is None:
217 if self.py_modules is None:
216 self.py_modules = []
218 self.py_modules = []
217 for ext in self.distribution.ext_modules:
219 for ext in self.distribution.ext_modules:
218 if ext.name.startswith("mercurial."):
220 if ext.name.startswith("mercurial."):
219 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
221 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
220 self.distribution.ext_modules = []
222 self.distribution.ext_modules = []
221
223
222 def find_modules(self):
224 def find_modules(self):
223 modules = build_py.find_modules(self)
225 modules = build_py.find_modules(self)
224 for module in modules:
226 for module in modules:
225 if module[0] == "mercurial.pure":
227 if module[0] == "mercurial.pure":
226 if module[1] != "__init__":
228 if module[1] != "__init__":
227 yield ("mercurial", module[1], module[2])
229 yield ("mercurial", module[1], module[2])
228 else:
230 else:
229 yield module
231 yield module
230
232
231 cmdclass = {'install_data': install_package_data,
233 cmdclass = {'install_data': install_package_data,
232 'build_mo': build_mo,
234 'build_mo': build_mo,
233 'build_py': hg_build_py}
235 'build_py': hg_build_py}
234
236
235 ext_modules=[
237 ext_modules=[
236 Extension('mercurial.base85', ['mercurial/base85.c']),
238 Extension('mercurial.base85', ['mercurial/base85.c']),
237 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
239 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
238 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
240 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
239 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
241 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
240 Extension('mercurial.parsers', ['mercurial/parsers.c']),
242 Extension('mercurial.parsers', ['mercurial/parsers.c']),
241 Extension('mercurial.osutil', ['mercurial/osutil.c']),
243 Extension('mercurial.osutil', ['mercurial/osutil.c']),
242 ]
244 ]
243
245
244 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
246 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
245 'hgext.highlight', 'hgext.zeroconf', ]
247 'hgext.highlight', 'hgext.zeroconf', ]
246
248
247 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
249 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
248 # The inotify extension is only usable with Linux 2.6 kernels.
250 # The inotify extension is only usable with Linux 2.6 kernels.
249 # You also need a reasonably recent C library.
251 # You also need a reasonably recent C library.
250 cc = new_compiler()
252 cc = new_compiler()
251 if has_function(cc, 'inotify_add_watch'):
253 if has_function(cc, 'inotify_add_watch'):
252 ext_modules.append(Extension('hgext.inotify.linux._inotify',
254 ext_modules.append(Extension('hgext.inotify.linux._inotify',
253 ['hgext/inotify/linux/_inotify.c']))
255 ['hgext/inotify/linux/_inotify.c']))
254 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
256 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
255
257
256 datafiles = []
258 datafiles = []
257 for root in ('templates', 'i18n', 'help'):
259 for root in ('templates', 'i18n', 'help'):
258 for dir, dirs, files in os.walk(root):
260 for dir, dirs, files in os.walk(root):
259 dirs[:] = [x for x in dirs if not x.startswith('.')]
261 dirs[:] = [x for x in dirs if not x.startswith('.')]
260 files = [x for x in files if not x.startswith('.')]
262 files = [x for x in files if not x.startswith('.')]
261 datafiles.append((os.path.join('mercurial', dir),
263 datafiles.append((os.path.join('mercurial', dir),
262 [os.path.join(dir, file_) for file_ in files]))
264 [os.path.join(dir, file_) for file_ in files]))
263
265
264 setup(name='mercurial',
266 setup(name='mercurial',
265 version=version,
267 version=version,
266 author='Matt Mackall',
268 author='Matt Mackall',
267 author_email='mpm@selenic.com',
269 author_email='mpm@selenic.com',
268 url='http://mercurial.selenic.com/',
270 url='http://mercurial.selenic.com/',
269 description='Scalable distributed SCM',
271 description='Scalable distributed SCM',
270 license='GNU GPL',
272 license='GNU GPL',
271 scripts=scripts,
273 scripts=scripts,
272 packages=packages,
274 packages=packages,
273 ext_modules=ext_modules,
275 ext_modules=ext_modules,
274 data_files=datafiles,
276 data_files=datafiles,
275 cmdclass=cmdclass,
277 cmdclass=cmdclass,
276 options=dict(py2exe=dict(packages=['hgext', 'email']),
278 options=dict(py2exe=dict(packages=['hgext', 'email']),
277 bdist_mpkg=dict(zipdist=True,
279 bdist_mpkg=dict(zipdist=True,
278 license='COPYING',
280 license='COPYING',
279 readme='contrib/macosx/Readme.html',
281 readme='contrib/macosx/Readme.html',
280 welcome='contrib/macosx/Welcome.html')),
282 welcome='contrib/macosx/Welcome.html')),
281 **extra)
283 **extra)
General Comments 0
You need to be logged in to leave comments. Login now