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