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