##// END OF EJS Templates
cleanup: make sure we always access members of imported modules...
Mads Kiilerich -
r22198:77142de4 default
parent child Browse files
Show More
@@ -1,95 +1,96 b''
1 1 # An example WSGI script for IIS/isapi-wsgi to export multiple hgweb repos
2 2 # Copyright 2010 Sune Foldager <cryo@cyanite.org>
3 3 #
4 4 # This software may be used and distributed according to the terms of the
5 5 # GNU General Public License version 2 or any later version.
6 6 #
7 7 # Requirements:
8 8 # - Python 2.6
9 9 # - PyWin32 build 214 or newer
10 10 # - Mercurial installed from source (python setup.py install)
11 11 # - IIS 7
12 12 #
13 13 # Earlier versions will in general work as well, but the PyWin32 version is
14 14 # necessary for win32traceutil to work correctly.
15 15 #
16 16 #
17 17 # Installation and use:
18 18 #
19 19 # - Download the isapi-wsgi source and run python setup.py install:
20 20 # http://code.google.com/p/isapi-wsgi/
21 21 #
22 22 # - Run this script (i.e. python hgwebdir_wsgi.py) to get a shim dll. The
23 23 # shim is identical for all scripts, so you can just copy and rename one
24 24 # from an earlier run, if you wish.
25 25 #
26 26 # - Setup an IIS application where your hgwebdir is to be served from.
27 27 # On 64-bit systems, make sure it's assigned a 32-bit app pool.
28 28 #
29 29 # - In the application, setup a wildcard script handler mapping of type
30 30 # IsapiModule with the shim dll as its executable. This file MUST reside
31 31 # in the same directory as the shim. Remove all other handlers, if you wish.
32 32 #
33 33 # - Make sure the ISAPI and CGI restrictions (configured globally on the
34 34 # web server) includes the shim dll, to allow it to run.
35 35 #
36 36 # - Adjust the configuration variables below to match your needs.
37 37 #
38 38
39 39 # Configuration file location
40 40 hgweb_config = r'c:\src\iis\hg\hgweb.config'
41 41
42 42 # Global settings for IIS path translation
43 43 path_strip = 0 # Strip this many path elements off (when using url rewrite)
44 44 path_prefix = 1 # This many path elements are prefixes (depends on the
45 45 # virtual path of the IIS application).
46 46
47 47 import sys
48 48
49 49 # Adjust python path if this is not a system-wide install
50 50 #sys.path.insert(0, r'c:\path\to\python\lib')
51 51
52 52 # Enable tracing. Run 'python -m win32traceutil' to debug
53 53 if getattr(sys, 'isapidllhandle', None) is not None:
54 54 import win32traceutil
55 win32traceutil.SetupForPrint # silence unused import warning
55 56
56 57 # To serve pages in local charset instead of UTF-8, remove the two lines below
57 58 import os
58 59 os.environ['HGENCODING'] = 'UTF-8'
59 60
60 61
61 62 import isapi_wsgi
62 63 from mercurial import demandimport; demandimport.enable()
63 64 from mercurial.hgweb.hgwebdir_mod import hgwebdir
64 65
65 66 # Example tweak: Replace isapi_wsgi's handler to provide better error message
66 67 # Other stuff could also be done here, like logging errors etc.
67 68 class WsgiHandler(isapi_wsgi.IsapiWsgiHandler):
68 69 error_status = '500 Internal Server Error' # less silly error message
69 70
70 71 isapi_wsgi.IsapiWsgiHandler = WsgiHandler
71 72
72 73 # Only create the hgwebdir instance once
73 74 application = hgwebdir(hgweb_config)
74 75
75 76 def handler(environ, start_response):
76 77
77 78 # Translate IIS's weird URLs
78 79 url = environ['SCRIPT_NAME'] + environ['PATH_INFO']
79 80 paths = url[1:].split('/')[path_strip:]
80 81 script_name = '/' + '/'.join(paths[:path_prefix])
81 82 path_info = '/'.join(paths[path_prefix:])
82 83 if path_info:
83 84 path_info = '/' + path_info
84 85 environ['SCRIPT_NAME'] = script_name
85 86 environ['PATH_INFO'] = path_info
86 87
87 88 return application(environ, start_response)
88 89
89 90 def __ExtensionFactory__():
90 91 return isapi_wsgi.ISAPISimpleHandler(handler)
91 92
92 93 if __name__=='__main__':
93 from isapi.install import *
94 from isapi.install import ISAPIParameters, HandleCommandLine
94 95 params = ISAPIParameters()
95 96 HandleCommandLine(params)
@@ -1,588 +1,592 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 getattr(sys, 'version_info', (0, 0, 0)) < (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 printf = eval('print')
17 17 libdir_escape = 'unicode_escape'
18 18 else:
19 19 libdir_escape = 'string_escape'
20 20 def b(s):
21 21 '''A helper function to emulate 2.6+ bytes literals using string
22 22 literals.'''
23 23 return s
24 24 def printf(*args, **kwargs):
25 25 f = kwargs.get('file', sys.stdout)
26 26 end = kwargs.get('end', '\n')
27 27 f.write(b(' ').join(args) + end)
28 28
29 29 # Solaris Python packaging brain damage
30 30 try:
31 31 import hashlib
32 32 sha = hashlib.sha1()
33 33 except ImportError:
34 34 try:
35 35 import sha
36 sha.sha # silence unused import warning
36 37 except ImportError:
37 38 raise SystemExit(
38 39 "Couldn't import standard hashlib (incomplete Python install).")
39 40
40 41 try:
41 42 import zlib
43 zlib.compressobj # silence unused import warning
42 44 except ImportError:
43 45 raise SystemExit(
44 46 "Couldn't import standard zlib (incomplete Python install).")
45 47
46 48 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
47 49 isironpython = False
48 50 try:
49 51 isironpython = (platform.python_implementation()
50 52 .lower().find("ironpython") != -1)
51 53 except AttributeError:
52 54 pass
53 55
54 56 if isironpython:
55 57 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
56 58 else:
57 59 try:
58 60 import bz2
61 bz2.BZ2Compressor # silence unused import warning
59 62 except ImportError:
60 63 raise SystemExit(
61 64 "Couldn't import standard bz2 (incomplete Python install).")
62 65
63 66 import os, subprocess, time
64 67 import re
65 68 import shutil
66 69 import tempfile
67 70 from distutils import log
68 71 from distutils.core import setup, Command, Extension
69 72 from distutils.dist import Distribution
70 73 from distutils.command.build import build
71 74 from distutils.command.build_ext import build_ext
72 75 from distutils.command.build_py import build_py
73 76 from distutils.command.install_scripts import install_scripts
74 77 from distutils.spawn import spawn, find_executable
75 78 from distutils import cygwinccompiler
76 79 from distutils.errors import CCompilerError, DistutilsExecError
77 80 from distutils.sysconfig import get_python_inc, get_config_var
78 81 from distutils.version import StrictVersion
79 82
80 83 convert2to3 = '--c2to3' in sys.argv
81 84 if convert2to3:
82 85 try:
83 86 from distutils.command.build_py import build_py_2to3 as build_py
84 87 from lib2to3.refactor import get_fixers_from_package as getfixers
85 88 except ImportError:
86 89 if sys.version_info[0] < 3:
87 90 raise SystemExit("--c2to3 is only compatible with python3.")
88 91 raise
89 92 sys.path.append('contrib')
90 93 elif sys.version_info[0] >= 3:
91 94 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
92 95
93 96 scripts = ['hg']
94 97 if os.name == 'nt':
95 98 scripts.append('contrib/win32/hg.bat')
96 99
97 100 # simplified version of distutils.ccompiler.CCompiler.has_function
98 101 # that actually removes its temporary files.
99 102 def hasfunction(cc, funcname):
100 103 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
101 104 devnull = oldstderr = None
102 105 try:
103 106 try:
104 107 fname = os.path.join(tmpdir, 'funcname.c')
105 108 f = open(fname, 'w')
106 109 f.write('int main(void) {\n')
107 110 f.write(' %s();\n' % funcname)
108 111 f.write('}\n')
109 112 f.close()
110 113 # Redirect stderr to /dev/null to hide any error messages
111 114 # from the compiler.
112 115 # This will have to be changed if we ever have to check
113 116 # for a function on Windows.
114 117 devnull = open('/dev/null', 'w')
115 118 oldstderr = os.dup(sys.stderr.fileno())
116 119 os.dup2(devnull.fileno(), sys.stderr.fileno())
117 120 objects = cc.compile([fname], output_dir=tmpdir)
118 121 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
119 122 except Exception:
120 123 return False
121 124 return True
122 125 finally:
123 126 if oldstderr is not None:
124 127 os.dup2(oldstderr, sys.stderr.fileno())
125 128 if devnull is not None:
126 129 devnull.close()
127 130 shutil.rmtree(tmpdir)
128 131
129 132 # py2exe needs to be installed to work
130 133 try:
131 134 import py2exe
135 py2exe.Distribution # silence unused import warning
132 136 py2exeloaded = True
133 137 # import py2exe's patched Distribution class
134 138 from distutils.core import Distribution
135 139 except ImportError:
136 140 py2exeloaded = False
137 141
138 142 def runcmd(cmd, env):
139 143 if sys.platform == 'plan9':
140 144 # subprocess kludge to work around issues in half-baked Python
141 145 # ports, notably bichued/python:
142 146 _, out, err = os.popen3(cmd)
143 147 return str(out), str(err)
144 148 else:
145 149 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
146 150 stderr=subprocess.PIPE, env=env)
147 151 out, err = p.communicate()
148 152 return out, err
149 153
150 154 def runhg(cmd, env):
151 155 out, err = runcmd(cmd, env)
152 156 # If root is executing setup.py, but the repository is owned by
153 157 # another user (as in "sudo python setup.py install") we will get
154 158 # trust warnings since the .hg/hgrc file is untrusted. That is
155 159 # fine, we don't want to load it anyway. Python may warn about
156 160 # a missing __init__.py in mercurial/locale, we also ignore that.
157 161 err = [e for e in err.splitlines()
158 162 if not e.startswith(b('not trusting file')) \
159 163 and not e.startswith(b('warning: Not importing')) \
160 164 and not e.startswith(b('obsolete feature not enabled'))]
161 165 if err:
162 166 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
163 167 printf(b('\n').join([b(' ') + e for e in err]), file=sys.stderr)
164 168 return ''
165 169 return out
166 170
167 171 version = ''
168 172
169 173 # Execute hg out of this directory with a custom environment which
170 174 # includes the pure Python modules in mercurial/pure. We also take
171 175 # care to not use any hgrc files and do no localization.
172 176 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
173 177 env = {'PYTHONPATH': os.pathsep.join(pypath),
174 178 'HGRCPATH': '',
175 179 'LANGUAGE': 'C'}
176 180 if 'LD_LIBRARY_PATH' in os.environ:
177 181 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
178 182 if 'SystemRoot' in os.environ:
179 183 # Copy SystemRoot into the custom environment for Python 2.6
180 184 # under Windows. Otherwise, the subprocess will fail with
181 185 # error 0xc0150004. See: http://bugs.python.org/issue3440
182 186 env['SystemRoot'] = os.environ['SystemRoot']
183 187
184 188 if os.path.isdir('.hg'):
185 189 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
186 190 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
187 191 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
188 192 if numerictags: # tag(s) found
189 193 version = numerictags[-1]
190 194 if hgid.endswith('+'): # propagate the dirty status to the tag
191 195 version += '+'
192 196 else: # no tag found
193 197 cmd = [sys.executable, 'hg', 'parents', '--template',
194 198 '{latesttag}+{latesttagdistance}-']
195 199 version = runhg(cmd, env) + hgid
196 200 if version.endswith('+'):
197 201 version += time.strftime('%Y%m%d')
198 202 elif os.path.exists('.hg_archival.txt'):
199 203 kw = dict([[t.strip() for t in l.split(':', 1)]
200 204 for l in open('.hg_archival.txt')])
201 205 if 'tag' in kw:
202 206 version = kw['tag']
203 207 elif 'latesttag' in kw:
204 208 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
205 209 else:
206 210 version = kw.get('node', '')[:12]
207 211
208 212 if version:
209 213 f = open("mercurial/__version__.py", "w")
210 214 f.write('# this file is autogenerated by setup.py\n')
211 215 f.write('version = "%s"\n' % version)
212 216 f.close()
213 217
214 218
215 219 try:
216 220 from mercurial import __version__
217 221 version = __version__.version
218 222 except ImportError:
219 223 version = 'unknown'
220 224
221 225 class hgbuild(build):
222 226 # Insert hgbuildmo first so that files in mercurial/locale/ are found
223 227 # when build_py is run next.
224 228 sub_commands = [('build_mo', None),
225 229
226 230 # We also need build_ext before build_py. Otherwise, when 2to3 is
227 231 # called (in build_py), it will not find osutil & friends,
228 232 # thinking that those modules are global and, consequently, making
229 233 # a mess, now that all module imports are global.
230 234
231 235 ('build_ext', build.has_ext_modules),
232 236 ] + build.sub_commands
233 237
234 238 class hgbuildmo(build):
235 239
236 240 description = "build translations (.mo files)"
237 241
238 242 def run(self):
239 243 if not find_executable('msgfmt'):
240 244 self.warn("could not find msgfmt executable, no translations "
241 245 "will be built")
242 246 return
243 247
244 248 podir = 'i18n'
245 249 if not os.path.isdir(podir):
246 250 self.warn("could not find %s/ directory" % podir)
247 251 return
248 252
249 253 join = os.path.join
250 254 for po in os.listdir(podir):
251 255 if not po.endswith('.po'):
252 256 continue
253 257 pofile = join(podir, po)
254 258 modir = join('locale', po[:-3], 'LC_MESSAGES')
255 259 mofile = join(modir, 'hg.mo')
256 260 mobuildfile = join('mercurial', mofile)
257 261 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
258 262 if sys.platform != 'sunos5':
259 263 # msgfmt on Solaris does not know about -c
260 264 cmd.append('-c')
261 265 self.mkpath(join('mercurial', modir))
262 266 self.make_file([pofile], mobuildfile, spawn, (cmd,))
263 267
264 268
265 269 class hgdist(Distribution):
266 270 pure = 0
267 271
268 272 global_options = Distribution.global_options + \
269 273 [('pure', None, "use pure (slow) Python "
270 274 "code instead of C extensions"),
271 275 ('c2to3', None, "(experimental!) convert "
272 276 "code with 2to3"),
273 277 ]
274 278
275 279 def has_ext_modules(self):
276 280 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
277 281 # too late for some cases
278 282 return not self.pure and Distribution.has_ext_modules(self)
279 283
280 284 class hgbuildext(build_ext):
281 285
282 286 def build_extension(self, ext):
283 287 try:
284 288 build_ext.build_extension(self, ext)
285 289 except CCompilerError:
286 290 if not getattr(ext, 'optional', False):
287 291 raise
288 292 log.warn("Failed to build optional extension '%s' (skipping)",
289 293 ext.name)
290 294
291 295 class hgbuildpy(build_py):
292 296 if convert2to3:
293 297 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
294 298 getfixers("hgfixes")))
295 299
296 300 def finalize_options(self):
297 301 build_py.finalize_options(self)
298 302
299 303 if self.distribution.pure:
300 304 if self.py_modules is None:
301 305 self.py_modules = []
302 306 for ext in self.distribution.ext_modules:
303 307 if ext.name.startswith("mercurial."):
304 308 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
305 309 self.distribution.ext_modules = []
306 310 else:
307 311 h = os.path.join(get_python_inc(), 'Python.h')
308 312 if not os.path.exists(h):
309 313 raise SystemExit('Python headers are required to build '
310 314 'Mercurial but weren\'t found in %s' % h)
311 315
312 316 def find_modules(self):
313 317 modules = build_py.find_modules(self)
314 318 for module in modules:
315 319 if module[0] == "mercurial.pure":
316 320 if module[1] != "__init__":
317 321 yield ("mercurial", module[1], module[2])
318 322 else:
319 323 yield module
320 324
321 325 class buildhgextindex(Command):
322 326 description = 'generate prebuilt index of hgext (for frozen package)'
323 327 user_options = []
324 328 _indexfilename = 'hgext/__index__.py'
325 329
326 330 def initialize_options(self):
327 331 pass
328 332
329 333 def finalize_options(self):
330 334 pass
331 335
332 336 def run(self):
333 337 if os.path.exists(self._indexfilename):
334 338 f = open(self._indexfilename, 'w')
335 339 f.write('# empty\n')
336 340 f.close()
337 341
338 342 # here no extension enabled, disabled() lists up everything
339 343 code = ('import pprint; from mercurial import extensions; '
340 344 'pprint.pprint(extensions.disabled())')
341 345 out, err = runcmd([sys.executable, '-c', code], env)
342 346 if err:
343 347 raise DistutilsExecError(err)
344 348
345 349 f = open(self._indexfilename, 'w')
346 350 f.write('# this file is autogenerated by setup.py\n')
347 351 f.write('docs = ')
348 352 f.write(out)
349 353 f.close()
350 354
351 355 class buildhgexe(build_ext):
352 356 description = 'compile hg.exe from mercurial/exewrapper.c'
353 357
354 358 def build_extensions(self):
355 359 if os.name != 'nt':
356 360 return
357 361 if isinstance(self.compiler, HackedMingw32CCompiler):
358 362 self.compiler.compiler_so = self.compiler.compiler # no -mdll
359 363 self.compiler.dll_libraries = [] # no -lmsrvc90
360 364 hv = sys.hexversion
361 365 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
362 366 f = open('mercurial/hgpythonlib.h', 'wb')
363 367 f.write('/* this file is autogenerated by setup.py */\n')
364 368 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
365 369 f.close()
366 370 objects = self.compiler.compile(['mercurial/exewrapper.c'],
367 371 output_dir=self.build_temp)
368 372 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
369 373 target = os.path.join(dir, 'hg')
370 374 self.compiler.link_executable(objects, target,
371 375 libraries=[],
372 376 output_dir=self.build_temp)
373 377
374 378 class hginstallscripts(install_scripts):
375 379 '''
376 380 This is a specialization of install_scripts that replaces the @LIBDIR@ with
377 381 the configured directory for modules. If possible, the path is made relative
378 382 to the directory for scripts.
379 383 '''
380 384
381 385 def initialize_options(self):
382 386 install_scripts.initialize_options(self)
383 387
384 388 self.install_lib = None
385 389
386 390 def finalize_options(self):
387 391 install_scripts.finalize_options(self)
388 392 self.set_undefined_options('install',
389 393 ('install_lib', 'install_lib'))
390 394
391 395 def run(self):
392 396 install_scripts.run(self)
393 397
394 398 if (os.path.splitdrive(self.install_dir)[0] !=
395 399 os.path.splitdrive(self.install_lib)[0]):
396 400 # can't make relative paths from one drive to another, so use an
397 401 # absolute path instead
398 402 libdir = self.install_lib
399 403 else:
400 404 common = os.path.commonprefix((self.install_dir, self.install_lib))
401 405 rest = self.install_dir[len(common):]
402 406 uplevel = len([n for n in os.path.split(rest) if n])
403 407
404 408 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
405 409
406 410 for outfile in self.outfiles:
407 411 fp = open(outfile, 'rb')
408 412 data = fp.read()
409 413 fp.close()
410 414
411 415 # skip binary files
412 416 if b('\0') in data:
413 417 continue
414 418
415 419 data = data.replace(b('@LIBDIR@'), libdir.encode(libdir_escape))
416 420 fp = open(outfile, 'wb')
417 421 fp.write(data)
418 422 fp.close()
419 423
420 424 cmdclass = {'build': hgbuild,
421 425 'build_mo': hgbuildmo,
422 426 'build_ext': hgbuildext,
423 427 'build_py': hgbuildpy,
424 428 'build_hgextindex': buildhgextindex,
425 429 'install_scripts': hginstallscripts,
426 430 'build_hgexe': buildhgexe,
427 431 }
428 432
429 433 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
430 434 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
431 435 'hgext.largefiles']
432 436
433 437 pymodules = []
434 438
435 439 common_depends = ['mercurial/util.h']
436 440
437 441 extmodules = [
438 442 Extension('mercurial.base85', ['mercurial/base85.c'],
439 443 depends=common_depends),
440 444 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
441 445 depends=common_depends),
442 446 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
443 447 depends=common_depends),
444 448 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
445 449 depends=common_depends),
446 450 Extension('mercurial.parsers', ['mercurial/dirs.c',
447 451 'mercurial/parsers.c',
448 452 'mercurial/pathencode.c'],
449 453 depends=common_depends),
450 454 ]
451 455
452 456 osutil_ldflags = []
453 457
454 458 if sys.platform == 'darwin':
455 459 osutil_ldflags += ['-framework', 'ApplicationServices']
456 460
457 461 # disable osutil.c under windows + python 2.4 (issue1364)
458 462 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
459 463 pymodules.append('mercurial.pure.osutil')
460 464 else:
461 465 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
462 466 extra_link_args=osutil_ldflags,
463 467 depends=common_depends))
464 468
465 469 # the -mno-cygwin option has been deprecated for years
466 470 Mingw32CCompiler = cygwinccompiler.Mingw32CCompiler
467 471
468 472 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
469 473 def __init__(self, *args, **kwargs):
470 474 Mingw32CCompiler.__init__(self, *args, **kwargs)
471 475 for i in 'compiler compiler_so linker_exe linker_so'.split():
472 476 try:
473 477 getattr(self, i).remove('-mno-cygwin')
474 478 except ValueError:
475 479 pass
476 480
477 481 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
478 482
479 483 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
480 484 'help/*.txt']}
481 485
482 486 def ordinarypath(p):
483 487 return p and p[0] != '.' and p[-1] != '~'
484 488
485 489 for root in ('templates',):
486 490 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
487 491 curdir = curdir.split(os.sep, 1)[1]
488 492 dirs[:] = filter(ordinarypath, dirs)
489 493 for f in filter(ordinarypath, files):
490 494 f = os.path.join(curdir, f)
491 495 packagedata['mercurial'].append(f)
492 496
493 497 datafiles = []
494 498 setupversion = version
495 499 extra = {}
496 500
497 501 if py2exeloaded:
498 502 extra['console'] = [
499 503 {'script':'hg',
500 504 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
501 505 'product_version':version}]
502 506 # sub command of 'build' because 'py2exe' does not handle sub_commands
503 507 build.sub_commands.insert(0, ('build_hgextindex', None))
504 508
505 509 if os.name == 'nt':
506 510 # Windows binary file versions for exe/dll files must have the
507 511 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
508 512 setupversion = version.split('+', 1)[0]
509 513
510 514 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
511 515 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
512 516 if version:
513 517 version = version[0]
514 518 xcode4 = (version.startswith('Xcode') and
515 519 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
516 520 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
517 521 else:
518 522 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
519 523 # installed, but instead with only command-line tools. Assume
520 524 # that only happens on >= Lion, thus no PPC support.
521 525 xcode4 = True
522 526 xcode51 = False
523 527
524 528 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
525 529 # distutils.sysconfig
526 530 if xcode4:
527 531 os.environ['ARCHFLAGS'] = ''
528 532
529 533 # XCode 5.1 changes clang such that it now fails to compile if the
530 534 # -mno-fused-madd flag is passed, but the version of Python shipped with
531 535 # OS X 10.9 Mavericks includes this flag. This causes problems in all
532 536 # C extension modules, and a bug has been filed upstream at
533 537 # http://bugs.python.org/issue21244. We also need to patch this here
534 538 # so Mercurial can continue to compile in the meantime.
535 539 if xcode51:
536 540 cflags = get_config_var('CFLAGS')
537 541 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
538 542 os.environ['CFLAGS'] = (
539 543 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
540 544
541 545 setup(name='mercurial',
542 546 version=setupversion,
543 547 author='Matt Mackall and many others',
544 548 author_email='mercurial@selenic.com',
545 549 url='http://mercurial.selenic.com/',
546 550 download_url='http://mercurial.selenic.com/release/',
547 551 description=('Fast scalable distributed SCM (revision control, version '
548 552 'control) system'),
549 553 long_description=('Mercurial is a distributed SCM tool written in Python.'
550 554 ' It is used by a number of large projects that require'
551 555 ' fast, reliable distributed revision control, such as '
552 556 'Mozilla.'),
553 557 license='GNU GPLv2 or any later version',
554 558 classifiers=[
555 559 'Development Status :: 6 - Mature',
556 560 'Environment :: Console',
557 561 'Intended Audience :: Developers',
558 562 'Intended Audience :: System Administrators',
559 563 'License :: OSI Approved :: GNU General Public License (GPL)',
560 564 'Natural Language :: Danish',
561 565 'Natural Language :: English',
562 566 'Natural Language :: German',
563 567 'Natural Language :: Italian',
564 568 'Natural Language :: Japanese',
565 569 'Natural Language :: Portuguese (Brazilian)',
566 570 'Operating System :: Microsoft :: Windows',
567 571 'Operating System :: OS Independent',
568 572 'Operating System :: POSIX',
569 573 'Programming Language :: C',
570 574 'Programming Language :: Python',
571 575 'Topic :: Software Development :: Version Control',
572 576 ],
573 577 scripts=scripts,
574 578 packages=packages,
575 579 py_modules=pymodules,
576 580 ext_modules=extmodules,
577 581 data_files=datafiles,
578 582 package_data=packagedata,
579 583 cmdclass=cmdclass,
580 584 distclass=hgdist,
581 585 options={'py2exe': {'packages': ['hgext', 'email']},
582 586 'bdist_mpkg': {'zipdist': True,
583 587 'license': 'COPYING',
584 588 'readme': 'contrib/macosx/Readme.html',
585 589 'welcome': 'contrib/macosx/Welcome.html',
586 590 },
587 591 },
588 592 **extra)
@@ -1,339 +1,343 b''
1 1 import os, stat
2 2 import re
3 3 import sys
4 4 import tempfile
5 5
6 6 tempprefix = 'hg-hghave-'
7 7
8 8 checks = {
9 9 "true": (lambda: True, "yak shaving"),
10 10 "false": (lambda: False, "nail clipper"),
11 11 }
12 12
13 13 def check(name, desc):
14 14 def decorator(func):
15 15 checks[name] = (func, desc)
16 16 return func
17 17 return decorator
18 18
19 19 def matchoutput(cmd, regexp, ignorestatus=False):
20 20 """Return True if cmd executes successfully and its output
21 21 is matched by the supplied regular expression.
22 22 """
23 23 r = re.compile(regexp)
24 24 fh = os.popen(cmd)
25 25 s = fh.read()
26 26 try:
27 27 ret = fh.close()
28 28 except IOError:
29 29 # Happen in Windows test environment
30 30 ret = 1
31 31 return (ignorestatus or ret is None) and r.search(s)
32 32
33 33 @check("baz", "GNU Arch baz client")
34 34 def has_baz():
35 35 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
36 36
37 37 @check("bzr", "Canonical's Bazaar client")
38 38 def has_bzr():
39 39 try:
40 40 import bzrlib
41 41 return bzrlib.__doc__ is not None
42 42 except ImportError:
43 43 return False
44 44
45 45 @check("bzr114", "Canonical's Bazaar client >= 1.14")
46 46 def has_bzr114():
47 47 try:
48 48 import bzrlib
49 49 return (bzrlib.__doc__ is not None
50 50 and bzrlib.version_info[:2] >= (1, 14))
51 51 except ImportError:
52 52 return False
53 53
54 54 @check("cvs", "cvs client/server")
55 55 def has_cvs():
56 56 re = r'Concurrent Versions System.*?server'
57 57 return matchoutput('cvs --version 2>&1', re) and not has_msys()
58 58
59 59 @check("cvs112", "cvs client/server >= 1.12")
60 60 def has_cvs112():
61 61 re = r'Concurrent Versions System \(CVS\) 1.12.*?server'
62 62 return matchoutput('cvs --version 2>&1', re) and not has_msys()
63 63
64 64 @check("darcs", "darcs client")
65 65 def has_darcs():
66 66 return matchoutput('darcs --version', r'2\.[2-9]', True)
67 67
68 68 @check("mtn", "monotone client (>= 1.0)")
69 69 def has_mtn():
70 70 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
71 71 'mtn --version', r'monotone 0\.', True)
72 72
73 73 @check("eol-in-paths", "end-of-lines in paths")
74 74 def has_eol_in_paths():
75 75 try:
76 76 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
77 77 os.close(fd)
78 78 os.remove(path)
79 79 return True
80 80 except (IOError, OSError):
81 81 return False
82 82
83 83 @check("execbit", "executable bit")
84 84 def has_executablebit():
85 85 try:
86 86 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
87 87 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
88 88 try:
89 89 os.close(fh)
90 90 m = os.stat(fn).st_mode & 0777
91 91 new_file_has_exec = m & EXECFLAGS
92 92 os.chmod(fn, m ^ EXECFLAGS)
93 93 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
94 94 finally:
95 95 os.unlink(fn)
96 96 except (IOError, OSError):
97 97 # we don't care, the user probably won't be able to commit anyway
98 98 return False
99 99 return not (new_file_has_exec or exec_flags_cannot_flip)
100 100
101 101 @check("icasefs", "case insensitive file system")
102 102 def has_icasefs():
103 103 # Stolen from mercurial.util
104 104 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
105 105 os.close(fd)
106 106 try:
107 107 s1 = os.stat(path)
108 108 d, b = os.path.split(path)
109 109 p2 = os.path.join(d, b.upper())
110 110 if path == p2:
111 111 p2 = os.path.join(d, b.lower())
112 112 try:
113 113 s2 = os.stat(p2)
114 114 return s2 == s1
115 115 except OSError:
116 116 return False
117 117 finally:
118 118 os.remove(path)
119 119
120 120 @check("fifo", "named pipes")
121 121 def has_fifo():
122 122 if getattr(os, "mkfifo", None) is None:
123 123 return False
124 124 name = tempfile.mktemp(dir='.', prefix=tempprefix)
125 125 try:
126 126 os.mkfifo(name)
127 127 os.unlink(name)
128 128 return True
129 129 except OSError:
130 130 return False
131 131
132 132 @check("killdaemons", 'killdaemons.py support')
133 133 def has_killdaemons():
134 134 return True
135 135
136 136 @check("cacheable", "cacheable filesystem")
137 137 def has_cacheable_fs():
138 138 from mercurial import util
139 139
140 140 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
141 141 os.close(fd)
142 142 try:
143 143 return util.cachestat(path).cacheable()
144 144 finally:
145 145 os.remove(path)
146 146
147 147 @check("lsprof", "python lsprof module")
148 148 def has_lsprof():
149 149 try:
150 150 import _lsprof
151 _lsprof.Profiler # silence unused import warning
151 152 return True
152 153 except ImportError:
153 154 return False
154 155
155 156 @check("gettext", "GNU Gettext (msgfmt)")
156 157 def has_gettext():
157 158 return matchoutput('msgfmt --version', 'GNU gettext-tools')
158 159
159 160 @check("git", "git command line client")
160 161 def has_git():
161 162 return matchoutput('git --version 2>&1', r'^git version')
162 163
163 164 @check("docutils", "Docutils text processing library")
164 165 def has_docutils():
165 166 try:
166 167 from docutils.core import publish_cmdline
168 publish_cmdline # silence unused import
167 169 return True
168 170 except ImportError:
169 171 return False
170 172
171 173 def getsvnversion():
172 174 m = matchoutput('svn --version --quiet 2>&1', r'^(\d+)\.(\d+)')
173 175 if not m:
174 176 return (0, 0)
175 177 return (int(m.group(1)), int(m.group(2)))
176 178
177 179 @check("svn15", "subversion client and admin tools >= 1.5")
178 180 def has_svn15():
179 181 return getsvnversion() >= (1, 5)
180 182
181 183 @check("svn13", "subversion client and admin tools >= 1.3")
182 184 def has_svn13():
183 185 return getsvnversion() >= (1, 3)
184 186
185 187 @check("svn", "subversion client and admin tools")
186 188 def has_svn():
187 189 return matchoutput('svn --version 2>&1', r'^svn, version') and \
188 190 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
189 191
190 192 @check("svn-bindings", "subversion python bindings")
191 193 def has_svn_bindings():
192 194 try:
193 195 import svn.core
194 196 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
195 197 if version < (1, 4):
196 198 return False
197 199 return True
198 200 except ImportError:
199 201 return False
200 202
201 203 @check("p4", "Perforce server and client")
202 204 def has_p4():
203 205 return (matchoutput('p4 -V', r'Rev\. P4/') and
204 206 matchoutput('p4d -V', r'Rev\. P4D/'))
205 207
206 208 @check("symlink", "symbolic links")
207 209 def has_symlink():
208 210 if getattr(os, "symlink", None) is None:
209 211 return False
210 212 name = tempfile.mktemp(dir='.', prefix=tempprefix)
211 213 try:
212 214 os.symlink(".", name)
213 215 os.unlink(name)
214 216 return True
215 217 except (OSError, AttributeError):
216 218 return False
217 219
218 220 @check("hardlink", "hardlinks")
219 221 def has_hardlink():
220 222 from mercurial import util
221 223 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
222 224 os.close(fh)
223 225 name = tempfile.mktemp(dir='.', prefix=tempprefix)
224 226 try:
225 227 try:
226 228 util.oslink(fn, name)
227 229 os.unlink(name)
228 230 return True
229 231 except OSError:
230 232 return False
231 233 finally:
232 234 os.unlink(fn)
233 235
234 236 @check("tla", "GNU Arch tla client")
235 237 def has_tla():
236 238 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
237 239
238 240 @check("gpg", "gpg client")
239 241 def has_gpg():
240 242 return matchoutput('gpg --version 2>&1', r'GnuPG')
241 243
242 244 @check("unix-permissions", "unix-style permissions")
243 245 def has_unix_permissions():
244 246 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
245 247 try:
246 248 fname = os.path.join(d, 'foo')
247 249 for umask in (077, 007, 022):
248 250 os.umask(umask)
249 251 f = open(fname, 'w')
250 252 f.close()
251 253 mode = os.stat(fname).st_mode
252 254 os.unlink(fname)
253 255 if mode & 0777 != ~umask & 0666:
254 256 return False
255 257 return True
256 258 finally:
257 259 os.rmdir(d)
258 260
259 261 @check("root", "root permissions")
260 262 def has_root():
261 263 return getattr(os, 'geteuid', None) and os.geteuid() == 0
262 264
263 265 @check("pyflakes", "Pyflakes python linter")
264 266 def has_pyflakes():
265 267 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
266 268 r"<stdin>:1: 're' imported but unused",
267 269 True)
268 270
269 271 @check("pygments", "Pygments source highlighting library")
270 272 def has_pygments():
271 273 try:
272 274 import pygments
275 pygments.highlight # silence unused import warning
273 276 return True
274 277 except ImportError:
275 278 return False
276 279
277 280 @check("python243", "python >= 2.4.3")
278 281 def has_python243():
279 282 return sys.version_info >= (2, 4, 3)
280 283
281 284 @check("outer-repo", "outer repo")
282 285 def has_outer_repo():
283 286 # failing for other reasons than 'no repo' imply that there is a repo
284 287 return not matchoutput('hg root 2>&1',
285 288 r'abort: no repository found', True)
286 289
287 290 @check("ssl", "python >= 2.6 ssl module and python OpenSSL")
288 291 def has_ssl():
289 292 try:
290 293 import ssl
294 ssl.wrap_socket # silence unused import warning
291 295 import OpenSSL
292 296 OpenSSL.SSL.Context
293 297 return True
294 298 except ImportError:
295 299 return False
296 300
297 301 @check("windows", "Windows")
298 302 def has_windows():
299 303 return os.name == 'nt'
300 304
301 305 @check("system-sh", "system() uses sh")
302 306 def has_system_sh():
303 307 return os.name != 'nt'
304 308
305 309 @check("serve", "platform and python can manage 'hg serve -d'")
306 310 def has_serve():
307 311 return os.name != 'nt' # gross approximation
308 312
309 313 @check("test-repo", "running tests from repository")
310 314 def has_test_repo():
311 315 t = os.environ["TESTDIR"]
312 316 return os.path.isdir(os.path.join(t, "..", ".hg"))
313 317
314 318 @check("tic", "terminfo compiler and curses module")
315 319 def has_tic():
316 320 try:
317 321 import curses
318 322 curses.COLOR_BLUE
319 323 return matchoutput('test -x "`which tic`"', '')
320 324 except ImportError:
321 325 return False
322 326
323 327 @check("msys", "Windows with MSYS")
324 328 def has_msys():
325 329 return os.getenv('MSYSTEM')
326 330
327 331 @check("aix", "AIX")
328 332 def has_aix():
329 333 return sys.platform.startswith("aix")
330 334
331 335 @check("absimport", "absolute_import in __future__")
332 336 def has_absimport():
333 337 import __future__
334 338 from mercurial import util
335 339 return util.safehasattr(__future__, "absolute_import")
336 340
337 341 @check("py3k", "running with Python 3.x")
338 342 def has_py3k():
339 343 return 3 == sys.version_info[0]
@@ -1,22 +1,12 b''
1 1 #require test-repo pyflakes
2 2
3 3 $ cd "`dirname "$TESTDIR"`"
4 4
5 5 run pyflakes on all tracked files ending in .py or without a file ending
6 6 (skipping binary file random-seed)
7 7
8 8 $ hg locate 'set:**.py or grep("^!#.*python")' 2>/dev/null \
9 9 > | xargs pyflakes 2>/dev/null | "$TESTDIR/filterpyflakes.py"
10 contrib/win32/hgwebdir_wsgi.py:*: 'win32traceutil' imported but unused (glob)
11 setup.py:*: 'sha' imported but unused (glob)
12 setup.py:*: 'zlib' imported but unused (glob)
13 setup.py:*: 'bz2' imported but unused (glob)
14 setup.py:*: 'py2exe' imported but unused (glob)
15 tests/hghave.py:*: '_lsprof' imported but unused (glob)
16 tests/hghave.py:*: 'publish_cmdline' imported but unused (glob)
17 tests/hghave.py:*: 'pygments' imported but unused (glob)
18 tests/hghave.py:*: 'ssl' imported but unused (glob)
19 contrib/win32/hgwebdir_wsgi.py:93: 'from isapi.install import *' used; unable to detect undefined names (glob)
20 10 tests/filterpyflakes.py:58: undefined name 'undefinedname'
21 11
22 12
General Comments 0
You need to be logged in to leave comments. Login now