##// END OF EJS Templates
setup.py: subprocess instead of os.popen, sys.stderr.write instead of print...
Christian Ebert -
r8547:548fd7a0 default
parent child Browse files
Show More
@@ -1,249 +1,251
1 1 #!/usr/bin/env python
2 2 #
3 3 # This is the mercurial setup script.
4 4 #
5 5 # 'python setup.py install', or
6 6 # 'python setup.py --help' for more options
7 7
8 8 import sys
9 9 if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
10 10 raise SystemExit("Mercurial requires Python 2.4 or later.")
11 11
12 12 # Solaris Python packaging brain damage
13 13 try:
14 14 import hashlib
15 15 sha = hashlib.sha1()
16 16 except:
17 17 try:
18 18 import sha
19 19 except:
20 20 raise SystemExit(
21 21 "Couldn't import standard hashlib (incomplete Python install).")
22 22
23 23 try:
24 24 import zlib
25 25 except:
26 26 raise SystemExit(
27 27 "Couldn't import standard zlib (incomplete Python install).")
28 28
29 import os, time
29 import os, subprocess, time
30 30 import shutil
31 31 import tempfile
32 32 from distutils.core import setup, Extension
33 33 from distutils.dist import Distribution
34 34 from distutils.command.install_data import install_data
35 35 from distutils.command.build import build
36 36 from distutils.command.build_py import build_py
37 37 from distutils.spawn import spawn, find_executable
38 38 from distutils.ccompiler import new_compiler
39 39
40 40 extra = {}
41 41 scripts = ['hg']
42 42 if os.name == 'nt':
43 43 scripts.append('contrib/win32/hg.bat')
44 44
45 45 # simplified version of distutils.ccompiler.CCompiler.has_function
46 46 # that actually removes its temporary files.
47 47 def has_function(cc, funcname):
48 48 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
49 49 devnull = oldstderr = None
50 50 try:
51 51 try:
52 52 fname = os.path.join(tmpdir, 'funcname.c')
53 53 f = open(fname, 'w')
54 54 f.write('int main(void) {\n')
55 55 f.write(' %s();\n' % funcname)
56 56 f.write('}\n')
57 57 f.close()
58 58 # Redirect stderr to /dev/null to hide any error messages
59 59 # from the compiler.
60 60 # This will have to be changed if we ever have to check
61 61 # for a function on Windows.
62 62 devnull = open('/dev/null', 'w')
63 63 oldstderr = os.dup(sys.stderr.fileno())
64 64 os.dup2(devnull.fileno(), sys.stderr.fileno())
65 65 objects = cc.compile([fname])
66 66 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
67 67 except:
68 68 return False
69 69 return True
70 70 finally:
71 71 if oldstderr is not None:
72 72 os.dup2(oldstderr, sys.stderr.fileno())
73 73 if devnull is not None:
74 74 devnull.close()
75 75 shutil.rmtree(tmpdir)
76 76
77 77 # py2exe needs to be installed to work
78 78 try:
79 79 import py2exe
80 80
81 81 # Help py2exe to find win32com.shell
82 82 try:
83 83 import modulefinder
84 84 import win32com
85 85 for p in win32com.__path__[1:]: # Take the path to win32comext
86 86 modulefinder.AddPackagePath("win32com", p)
87 87 pn = "win32com.shell"
88 88 __import__(pn)
89 89 m = sys.modules[pn]
90 90 for p in m.__path__[1:]:
91 91 modulefinder.AddPackagePath(pn, p)
92 92 except ImportError:
93 93 pass
94 94
95 95 extra['console'] = ['hg']
96 96
97 97 except ImportError:
98 98 pass
99 99
100 if os.path.exists('.hg'):
100 if os.path.isdir('.hg'):
101 101 # execute hg out of this directory with a custom environment which
102 102 # includes the pure Python modules in mercurial/pure
103 103 pypath = os.environ.get('PYTHONPATH', '')
104 104 purepath = os.path.join('mercurial', 'pure')
105 105 os.environ['PYTHONPATH'] = os.pathsep.join(['mercurial', purepath, pypath])
106 106 os.environ['HGRCPATH'] = '' # do not read any config file
107 cmd = '%s hg id -it' % sys.executable
107 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
108 108 version = None
109 109
110 try:
111 l = os.popen(cmd).read().split()
112 except OSError, e:
113 print "warning: could not establish Mercurial version: %s" % e
114
110 l, e = subprocess.Popen(cmd, stdout=subprocess.PIPE,
111 stderr=subprocess.PIPE).communicate()
115 112 os.environ['PYTHONPATH'] = pypath
116 113
114 if e:
115 sys.stderr.write('warning: could not establish Mercurial version: %s'
116 % e)
117 else:
118 l = l.split()
117 119 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
118 120 l.pop()
119 121 if l:
120 122 version = l[-1] # latest tag or revision number
121 123 if version.endswith('+'):
122 124 version += time.strftime('%Y%m%d')
123 125
124 126 if version:
125 127 f = file("mercurial/__version__.py", "w")
126 128 f.write('# this file is autogenerated by setup.py\n')
127 129 f.write('version = "%s"\n' % version)
128 130 f.close()
129 131
130 132 try:
131 133 from mercurial import __version__
132 134 version = __version__.version
133 135 except ImportError:
134 136 version = 'unknown'
135 137
136 138 class install_package_data(install_data):
137 139 def finalize_options(self):
138 140 self.set_undefined_options('install',
139 141 ('install_lib', 'install_dir'))
140 142 install_data.finalize_options(self)
141 143
142 144 class build_mo(build):
143 145
144 146 description = "build translations (.mo files)"
145 147
146 148 def run(self):
147 149 if not find_executable('msgfmt'):
148 150 self.warn("could not find msgfmt executable, no translations "
149 151 "will be built")
150 152 return
151 153
152 154 podir = 'i18n'
153 155 if not os.path.isdir(podir):
154 156 self.warn("could not find %s/ directory" % podir)
155 157 return
156 158
157 159 join = os.path.join
158 160 for po in os.listdir(podir):
159 161 if not po.endswith('.po'):
160 162 continue
161 163 pofile = join(podir, po)
162 164 modir = join('locale', po[:-3], 'LC_MESSAGES')
163 165 mofile = join(modir, 'hg.mo')
164 166 cmd = ['msgfmt', '-v', '-o', mofile, pofile]
165 167 if sys.platform != 'sunos5':
166 168 # msgfmt on Solaris does not know about -c
167 169 cmd.append('-c')
168 170 self.mkpath(modir)
169 171 self.make_file([pofile], mofile, spawn, (cmd,))
170 172 self.distribution.data_files.append((join('mercurial', modir),
171 173 [mofile]))
172 174
173 175 build.sub_commands.append(('build_mo', None))
174 176
175 177 Distribution.pure = 0
176 178 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
177 179 "code instead of C extensions"))
178 180
179 181 class hg_build_py(build_py):
180 182
181 183 def finalize_options(self):
182 184 build_py.finalize_options(self)
183 185
184 186 if self.distribution.pure:
185 187 if self.py_modules is None:
186 188 self.py_modules = []
187 189 for ext in self.distribution.ext_modules:
188 190 if ext.name.startswith("mercurial."):
189 191 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
190 192 self.distribution.ext_modules = []
191 193
192 194 def find_modules(self):
193 195 modules = build_py.find_modules(self)
194 196 for module in modules:
195 197 if module[0] == "mercurial.pure":
196 198 if module[1] != "__init__":
197 199 yield ("mercurial", module[1], module[2])
198 200 else:
199 201 yield module
200 202
201 203 cmdclass = {'install_data': install_package_data,
202 204 'build_mo': build_mo,
203 205 'build_py': hg_build_py}
204 206
205 207 ext_modules=[
206 208 Extension('mercurial.base85', ['mercurial/base85.c']),
207 209 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
208 210 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
209 211 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
210 212 Extension('mercurial.parsers', ['mercurial/parsers.c']),
211 213 Extension('mercurial.osutil', ['mercurial/osutil.c']),
212 214 ]
213 215
214 216 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
215 217 'hgext.highlight', 'hgext.zeroconf', ]
216 218
217 219 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
218 220 # The inotify extension is only usable with Linux 2.6 kernels.
219 221 # You also need a reasonably recent C library.
220 222 cc = new_compiler()
221 223 if has_function(cc, 'inotify_add_watch'):
222 224 ext_modules.append(Extension('hgext.inotify.linux._inotify',
223 225 ['hgext/inotify/linux/_inotify.c']))
224 226 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
225 227
226 228 datafiles = []
227 229 for root in ('templates', 'i18n'):
228 230 for dir, dirs, files in os.walk(root):
229 231 datafiles.append((os.path.join('mercurial', dir),
230 232 [os.path.join(dir, file_) for file_ in files]))
231 233
232 234 setup(name='mercurial',
233 235 version=version,
234 236 author='Matt Mackall',
235 237 author_email='mpm@selenic.com',
236 238 url='http://selenic.com/mercurial',
237 239 description='Scalable distributed SCM',
238 240 license='GNU GPL',
239 241 scripts=scripts,
240 242 packages=packages,
241 243 ext_modules=ext_modules,
242 244 data_files=datafiles,
243 245 cmdclass=cmdclass,
244 246 options=dict(py2exe=dict(packages=['hgext', 'email']),
245 247 bdist_mpkg=dict(zipdist=True,
246 248 license='COPYING',
247 249 readme='contrib/macosx/Readme.html',
248 250 welcome='contrib/macosx/Welcome.html')),
249 251 **extra)
General Comments 0
You need to be logged in to leave comments. Login now