##// END OF EJS Templates
setup: add command to generate index of extensions...
Yuya Nishihara -
r14538:3818c67a default
parent child Browse files
Show More
@@ -1,49 +1,50 b''
1 1 syntax: glob
2 2
3 3 *.elc
4 4 *.orig
5 5 *.rej
6 6 *~
7 7 *.mergebackup
8 8 *.o
9 9 *.so
10 10 *.dll
11 11 *.pyd
12 12 *.pyc
13 13 *.pyo
14 14 *$py.class
15 15 *.swp
16 16 *.prof
17 17 \#*\#
18 18 .\#*
19 19 tests/.coverage*
20 20 tests/annotated
21 21 tests/*.err
22 22 build
23 23 contrib/hgsh/hgsh
24 24 dist
25 25 doc/*.[0-9]
26 26 doc/*.[0-9].gendoc.txt
27 27 doc/*.[0-9].{x,ht}ml
28 28 MANIFEST
29 29 patches
30 30 mercurial/__version__.py
31 31 mercurial.egg-info
32 32 Output/Mercurial-*.exe
33 33 .DS_Store
34 34 tags
35 35 cscope.*
36 36 i18n/hg.pot
37 37 locale/*/LC_MESSAGES/hg.mo
38 hgext/__index__.py
38 39
39 40 # files installed with a local --pure build
40 41 mercurial/base85.py
41 42 mercurial/bdiff.py
42 43 mercurial/diffhelpers.py
43 44 mercurial/mpatch.py
44 45 mercurial/osutil.py
45 46 mercurial/parsers.py
46 47
47 48 syntax: regexp
48 49 ^\.pc/
49 50 ^\.(pydev)?project
@@ -1,410 +1,441 b''
1 1 #
2 2 # This is the mercurial setup script.
3 3 #
4 4 # 'python setup.py install', or
5 5 # 'python setup.py --help' for more options
6 6
7 7 import sys, platform
8 8 if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
9 9 raise SystemExit("Mercurial requires Python 2.4 or later.")
10 10
11 11 if sys.version_info[0] >= 3:
12 12 def b(s):
13 13 '''A helper function to emulate 2.6+ bytes literals using string
14 14 literals.'''
15 15 return s.encode('latin1')
16 16 else:
17 17 def b(s):
18 18 '''A helper function to emulate 2.6+ bytes literals using string
19 19 literals.'''
20 20 return s
21 21
22 22 # Solaris Python packaging brain damage
23 23 try:
24 24 import hashlib
25 25 sha = hashlib.sha1()
26 26 except:
27 27 try:
28 28 import sha
29 29 except:
30 30 raise SystemExit(
31 31 "Couldn't import standard hashlib (incomplete Python install).")
32 32
33 33 try:
34 34 import zlib
35 35 except:
36 36 raise SystemExit(
37 37 "Couldn't import standard zlib (incomplete Python install).")
38 38
39 39 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 40 isironpython = False
41 41 try:
42 42 isironpython = platform.python_implementation().lower().find("ironpython") != -1
43 43 except:
44 44 pass
45 45
46 46 if isironpython:
47 47 print "warning: IronPython detected (no bz2 support)"
48 48 else:
49 49 try:
50 50 import bz2
51 51 except:
52 52 raise SystemExit(
53 53 "Couldn't import standard bz2 (incomplete Python install).")
54 54
55 55 import os, subprocess, time
56 56 import shutil
57 57 import tempfile
58 58 from distutils import log
59 from distutils.core import setup, Extension
59 from distutils.core import setup, Command, Extension
60 60 from distutils.dist import Distribution
61 61 from distutils.command.build import build
62 62 from distutils.command.build_ext import build_ext
63 63 from distutils.command.build_py import build_py
64 64 from distutils.command.install_scripts import install_scripts
65 65 from distutils.spawn import spawn, find_executable
66 66 from distutils.ccompiler import new_compiler
67 from distutils.errors import CCompilerError
67 from distutils.errors import CCompilerError, DistutilsExecError
68 68 from distutils.sysconfig import get_python_inc
69 69 from distutils.version import StrictVersion
70 70
71 71 scripts = ['hg']
72 72 if os.name == 'nt':
73 73 scripts.append('contrib/win32/hg.bat')
74 74
75 75 # simplified version of distutils.ccompiler.CCompiler.has_function
76 76 # that actually removes its temporary files.
77 77 def hasfunction(cc, funcname):
78 78 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
79 79 devnull = oldstderr = None
80 80 try:
81 81 try:
82 82 fname = os.path.join(tmpdir, 'funcname.c')
83 83 f = open(fname, 'w')
84 84 f.write('int main(void) {\n')
85 85 f.write(' %s();\n' % funcname)
86 86 f.write('}\n')
87 87 f.close()
88 88 # Redirect stderr to /dev/null to hide any error messages
89 89 # from the compiler.
90 90 # This will have to be changed if we ever have to check
91 91 # for a function on Windows.
92 92 devnull = open('/dev/null', 'w')
93 93 oldstderr = os.dup(sys.stderr.fileno())
94 94 os.dup2(devnull.fileno(), sys.stderr.fileno())
95 95 objects = cc.compile([fname], output_dir=tmpdir)
96 96 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
97 97 except:
98 98 return False
99 99 return True
100 100 finally:
101 101 if oldstderr is not None:
102 102 os.dup2(oldstderr, sys.stderr.fileno())
103 103 if devnull is not None:
104 104 devnull.close()
105 105 shutil.rmtree(tmpdir)
106 106
107 107 # py2exe needs to be installed to work
108 108 try:
109 109 import py2exe
110 110 py2exeloaded = True
111 111 except ImportError:
112 112 py2exeloaded = False
113 113
114 114 def runcmd(cmd, env):
115 115 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
116 116 stderr=subprocess.PIPE, env=env)
117 117 out, err = p.communicate()
118 118 return out, err
119 119
120 120 def runhg(cmd, env):
121 121 out, err = runcmd(cmd, env)
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 = runhg(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 = runhg(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
219 219 # Insert hgbuildmo first so that files in mercurial/locale/ are found
220 220 # when build_py is run next.
221 221 build.sub_commands.insert(0, ('build_mo', None))
222 222
223 223 Distribution.pure = 0
224 224 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
225 225 "code instead of C extensions"))
226 226
227 227 class hgbuildext(build_ext):
228 228
229 229 def build_extension(self, ext):
230 230 try:
231 231 build_ext.build_extension(self, ext)
232 232 except CCompilerError:
233 233 if not getattr(ext, 'optional', False):
234 234 raise
235 235 log.warn("Failed to build optional extension '%s' (skipping)",
236 236 ext.name)
237 237
238 238 class hgbuildpy(build_py):
239 239
240 240 def finalize_options(self):
241 241 build_py.finalize_options(self)
242 242
243 243 if self.distribution.pure:
244 244 if self.py_modules is None:
245 245 self.py_modules = []
246 246 for ext in self.distribution.ext_modules:
247 247 if ext.name.startswith("mercurial."):
248 248 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
249 249 self.distribution.ext_modules = []
250 250 else:
251 251 if not os.path.exists(os.path.join(get_python_inc(), 'Python.h')):
252 252 raise SystemExit("Python headers are required to build Mercurial")
253 253
254 254 def find_modules(self):
255 255 modules = build_py.find_modules(self)
256 256 for module in modules:
257 257 if module[0] == "mercurial.pure":
258 258 if module[1] != "__init__":
259 259 yield ("mercurial", module[1], module[2])
260 260 else:
261 261 yield module
262 262
263 class buildhgextindex(Command):
264 description = 'generate prebuilt index of hgext (for frozen package)'
265 user_options = []
266 _indexfilename = 'hgext/__index__.py'
267
268 def initialize_options(self):
269 pass
270
271 def finalize_options(self):
272 pass
273
274 def run(self):
275 if os.path.exists(self._indexfilename):
276 os.unlink(self._indexfilename)
277
278 # here no extension enabled, disabled() lists up everything
279 code = ('import pprint; from mercurial import extensions; '
280 'pprint.pprint(extensions.disabled())')
281 out, err = runcmd([sys.executable, '-c', code], env)
282 if err:
283 raise DistutilsExecError(err)
284
285 f = open(self._indexfilename, 'w')
286 f.write('# this file is autogenerated by setup.py\n')
287 f.write('docs = ')
288 f.write(out)
289 f.close()
290
263 291 class hginstallscripts(install_scripts):
264 292 '''
265 293 This is a specialization of install_scripts that replaces the @LIBDIR@ with
266 294 the configured directory for modules. If possible, the path is made relative
267 295 to the directory for scripts.
268 296 '''
269 297
270 298 def initialize_options(self):
271 299 install_scripts.initialize_options(self)
272 300
273 301 self.install_lib = None
274 302
275 303 def finalize_options(self):
276 304 install_scripts.finalize_options(self)
277 305 self.set_undefined_options('install',
278 306 ('install_lib', 'install_lib'))
279 307
280 308 def run(self):
281 309 install_scripts.run(self)
282 310
283 311 if (os.path.splitdrive(self.install_dir)[0] !=
284 312 os.path.splitdrive(self.install_lib)[0]):
285 313 # can't make relative paths from one drive to another, so use an
286 314 # absolute path instead
287 315 libdir = self.install_lib
288 316 else:
289 317 common = os.path.commonprefix((self.install_dir, self.install_lib))
290 318 rest = self.install_dir[len(common):]
291 319 uplevel = len([n for n in os.path.split(rest) if n])
292 320
293 321 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
294 322
295 323 for outfile in self.outfiles:
296 324 fp = open(outfile, 'rb')
297 325 data = fp.read()
298 326 fp.close()
299 327
300 328 # skip binary files
301 329 if '\0' in data:
302 330 continue
303 331
304 332 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
305 333 fp = open(outfile, 'wb')
306 334 fp.write(data)
307 335 fp.close()
308 336
309 337 cmdclass = {'build_mo': hgbuildmo,
310 338 'build_ext': hgbuildext,
311 339 'build_py': hgbuildpy,
340 'build_hgextindex': buildhgextindex,
312 341 'install_scripts': hginstallscripts}
313 342
314 343 packages = ['mercurial', 'mercurial.hgweb',
315 344 'mercurial.httpclient', 'mercurial.httpclient.tests',
316 345 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf']
317 346
318 347 pymodules = []
319 348
320 349 extmodules = [
321 350 Extension('mercurial.base85', ['mercurial/base85.c']),
322 351 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
323 352 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
324 353 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
325 354 Extension('mercurial.parsers', ['mercurial/parsers.c']),
326 355 ]
327 356
328 357 osutil_ldflags = []
329 358
330 359 if sys.platform == 'darwin':
331 360 osutil_ldflags += ['-framework', 'ApplicationServices']
332 361
333 362 # disable osutil.c under windows + python 2.4 (issue1364)
334 363 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
335 364 pymodules.append('mercurial.pure.osutil')
336 365 else:
337 366 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
338 367 extra_link_args=osutil_ldflags))
339 368
340 369 if sys.platform == 'linux2' and os.uname()[2] > '2.6':
341 370 # The inotify extension is only usable with Linux 2.6 kernels.
342 371 # You also need a reasonably recent C library.
343 372 # In any case, if it fails to build the error will be skipped ('optional').
344 373 cc = new_compiler()
345 374 if hasfunction(cc, 'inotify_add_watch'):
346 375 inotify = Extension('hgext.inotify.linux._inotify',
347 376 ['hgext/inotify/linux/_inotify.c'],
348 377 ['mercurial'])
349 378 inotify.optional = True
350 379 extmodules.append(inotify)
351 380 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
352 381
353 382 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
354 383 'help/*.txt']}
355 384
356 385 def ordinarypath(p):
357 386 return p and p[0] != '.' and p[-1] != '~'
358 387
359 388 for root in ('templates',):
360 389 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
361 390 curdir = curdir.split(os.sep, 1)[1]
362 391 dirs[:] = filter(ordinarypath, dirs)
363 392 for f in filter(ordinarypath, files):
364 393 f = os.path.join(curdir, f)
365 394 packagedata['mercurial'].append(f)
366 395
367 396 datafiles = []
368 397 setupversion = version
369 398 extra = {}
370 399
371 400 if py2exeloaded:
372 401 extra['console'] = [
373 402 {'script':'hg',
374 403 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
375 404 'product_version':version}]
405 # sub command of 'build' because 'py2exe' does not handle sub_commands
406 build.sub_commands.insert(0, ('build_hgextindex', None))
376 407
377 408 if os.name == 'nt':
378 409 # Windows binary file versions for exe/dll files must have the
379 410 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
380 411 setupversion = version.split('+', 1)[0]
381 412
382 413 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
383 414 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
384 415 # distutils.sysconfig
385 416 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()[0]
386 417 # Also parse only first digit, because 3.2.1 can't be parsed nicely
387 418 if (version.startswith('Xcode') and
388 419 StrictVersion(version.split()[1]) >= StrictVersion('4.0')):
389 420 os.environ['ARCHFLAGS'] = ''
390 421
391 422 setup(name='mercurial',
392 423 version=setupversion,
393 424 author='Matt Mackall',
394 425 author_email='mpm@selenic.com',
395 426 url='http://mercurial.selenic.com/',
396 427 description='Scalable distributed SCM',
397 428 license='GNU GPLv2+',
398 429 scripts=scripts,
399 430 packages=packages,
400 431 py_modules=pymodules,
401 432 ext_modules=extmodules,
402 433 data_files=datafiles,
403 434 package_data=packagedata,
404 435 cmdclass=cmdclass,
405 436 options=dict(py2exe=dict(packages=['hgext', 'email']),
406 437 bdist_mpkg=dict(zipdist=True,
407 438 license='COPYING',
408 439 readme='contrib/macosx/Readme.html',
409 440 welcome='contrib/macosx/Welcome.html')),
410 441 **extra)
General Comments 0
You need to be logged in to leave comments. Login now