source: TI12-security/trunk/NDGSecurity/python/buildout/ndgsecurity/eggs/zc.buildout-1.2.1-py2.5.egg/zc/buildout/testing.py @ 7081

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/python/buildout/ndgsecurity/eggs/zc.buildout-1.2.1-py2.5.egg/zc/buildout/testing.py@7081
Revision 7081, 14.6 KB checked in by pjkersha, 10 years ago (diff)
  • Property svn:keywords set to Id
Line 
1#############################################################################
2#
3# Copyright (c) 2004 Zope Corporation and Contributors.
4# All Rights Reserved.
5#
6# This software is subject to the provisions of the Zope Public License,
7# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11# FOR A PARTICULAR PURPOSE.
12#
13##############################################################################
14"""Various test-support utility functions
15
16$Id$
17"""
18
19import BaseHTTPServer
20import errno
21import os
22import pkg_resources
23import random
24import re
25import shutil
26import socket
27import subprocess
28import sys
29import tempfile
30import threading
31import time
32import urllib2
33
34import zc.buildout.buildout
35import zc.buildout.easy_install
36from zc.buildout.rmtree import rmtree
37
38fsync = getattr(os, 'fsync', lambda fileno: None)
39
40setuptools_location = pkg_resources.working_set.find(
41    pkg_resources.Requirement.parse('setuptools')).location
42
43def cat(dir, *names):
44    path = os.path.join(dir, *names)
45    if (not os.path.exists(path)
46        and sys.platform == 'win32'
47        and os.path.exists(path+'-script.py')
48        ):
49        path = path+'-script.py'
50    print open(path).read(),
51
52def ls(dir, *subs):
53    if subs:
54        dir = os.path.join(dir, *subs)
55    names = os.listdir(dir)
56    names.sort()
57    for name in names:
58        if os.path.isdir(os.path.join(dir, name)):
59            print 'd ',
60        elif os.path.islink(os.path.join(dir, name)):
61            print 'l ',
62        else:
63            print '- ',
64        print name
65
66def mkdir(*path):
67    os.mkdir(os.path.join(*path))
68
69def remove(*path):
70    path = os.path.join(*path)
71    if os.path.isdir(path):
72        shutil.rmtree(path)
73    else:
74        os.remove(path)
75
76def rmdir(*path):
77    shutil.rmtree(os.path.join(*path))
78
79def write(dir, *args):
80    path = os.path.join(dir, *(args[:-1]))
81    f = open(path, 'w')
82    f.write(args[-1])
83    f.flush()
84    fsync(f.fileno())
85    f.close()
86
87
88def system(command, input=''):
89    p = subprocess.Popen(command,
90                         shell=True,
91                         stdin=subprocess.PIPE,
92                         stdout=subprocess.PIPE,
93                         stderr=subprocess.PIPE,
94                         close_fds=True)
95    i, o, e = (p.stdin, p.stdout, p.stderr)
96    if input:
97        i.write(input)
98    i.close()
99    result = o.read() + e.read()
100    o.close()
101    e.close()
102    return result
103
104def get(url):
105    return urllib2.urlopen(url).read()
106
107def _runsetup(setup, executable, *args):
108    if os.path.isdir(setup):
109        setup = os.path.join(setup, 'setup.py')
110    d = os.path.dirname(setup)
111
112    args = [zc.buildout.easy_install._safe_arg(arg)
113            for arg in args]
114    args.insert(0, '-q')
115    args.append(dict(os.environ, PYTHONPATH=setuptools_location))
116
117    here = os.getcwd()
118    try:
119        os.chdir(d)
120        os.spawnle(os.P_WAIT, executable, zc.buildout.easy_install._safe_arg (executable), setup, *args)
121        if os.path.exists('build'):
122            rmtree('build')
123    finally:
124        os.chdir(here)
125
126def sdist(setup, dest):
127    _runsetup(setup, sys.executable, 'sdist', '-d', dest, '--formats=zip')
128
129def bdist_egg(setup, executable, dest):
130    _runsetup(setup, executable, 'bdist_egg', '-d', dest)
131
132def find_python(version):
133    e = os.environ.get('PYTHON%s' % version)
134    if e is not None:
135        return e
136    if sys.platform == 'win32':
137        e = '\Python%s%s\python.exe' % tuple(version.split('.'))
138        if os.path.exists(e):
139            return e
140    else:
141        cmd = 'python%s -c "import sys; print sys.executable"' % version
142        p = subprocess.Popen(cmd,
143                             shell=True,
144                             stdin=subprocess.PIPE,
145                             stdout=subprocess.PIPE,
146                             stderr=subprocess.STDOUT,
147                             close_fds=True)
148        i, o = (p.stdin, p.stdout)
149        i.close()
150        e = o.read().strip()
151        o.close()
152        if os.path.exists(e):
153            return e
154        cmd = 'python -c "import sys; print \'%s.%s\' % sys.version_info[:2]"'
155        p = subprocess.Popen(cmd,
156                             shell=True,
157                             stdin=subprocess.PIPE,
158                             stdout=subprocess.PIPE,
159                             stderr=subprocess.STDOUT,
160                             close_fds=True)
161        i, o = (p.stdin, p.stdout)
162        i.close()
163        e = o.read().strip()
164        o.close()
165        if e == version:
166            cmd = 'python -c "import sys; print sys.executable"'
167            p = subprocess.Popen(cmd,
168                                shell=True,
169                                stdin=subprocess.PIPE,
170                                stdout=subprocess.PIPE,
171                                stderr=subprocess.STDOUT,
172                                close_fds=True)
173            i, o = (p.stdin, p.stdout)
174            i.close()
175            e = o.read().strip()
176            o.close()
177            if os.path.exists(e):
178                return e
179
180    raise ValueError(
181        "Couldn't figure out the executable for Python %(version)s.\n"
182        "Set the environment variable PYTHON%(version)s to the location\n"
183        "of the Python %(version)s executable before running the tests."
184        % {'version': version})
185
186def wait_until(label, func, *args, **kw):
187    if 'timeout' in kw:
188        kw = dict(kw)
189        timeout = kw.pop('timeout')
190    else:
191        timeout = 30
192    deadline = time.time()+timeout
193    while time.time() < deadline:
194        if func(*args, **kw):
195            return
196        time.sleep('.01')
197    raise ValueError('Timed out waiting for: '+label)
198
199def buildoutSetUp(test):
200
201    test.globs['__tear_downs'] = __tear_downs = []
202    test.globs['register_teardown'] = register_teardown = __tear_downs.append
203
204    prefer_final = zc.buildout.easy_install.prefer_final()
205    register_teardown(
206        lambda: zc.buildout.easy_install.prefer_final(prefer_final)
207        )
208
209    here = os.getcwd()
210    register_teardown(lambda: os.chdir(here))
211
212
213    base = tempfile.mkdtemp('buildoutSetUp')
214    register_teardown(lambda base=base: rmtree(base))
215
216    old_home = os.environ.get('HOME')
217    os.environ['HOME'] = os.path.join(base, 'bbbBadHome')
218    def restore_home():
219        if old_home is None:
220            del os.environ['HOME']
221        else:
222            os.environ['HOME'] = old_home
223    register_teardown(restore_home)
224
225    base = os.path.join(base, '_TEST_')
226    os.mkdir(base)
227
228    tmp = tempfile.mkdtemp('buildouttests')
229    register_teardown(lambda: rmtree(tmp))
230
231    zc.buildout.easy_install.default_index_url = 'file://'+tmp
232    os.environ['buildout-testing-index-url'] = (
233        zc.buildout.easy_install.default_index_url)
234
235    def tmpdir(name):
236        path = os.path.join(base, name)
237        mkdir(path)
238        return path
239
240    sample = tmpdir('sample-buildout')
241
242    os.chdir(sample)
243
244    # Create a basic buildout.cfg to avoid a warning from buildout:
245    open('buildout.cfg', 'w').write(
246        "[buildout]\nparts =\n"
247        )
248
249    # Use the buildout bootstrap command to create a buildout
250    zc.buildout.buildout.Buildout(
251        'buildout.cfg',
252        [('buildout', 'log-level', 'WARNING'),
253         # trick bootstrap into putting the buildout develop egg
254         # in the eggs dir.
255         ('buildout', 'develop-eggs-directory', 'eggs'),
256         ]
257        ).bootstrap([])
258
259
260
261    # Create the develop-eggs dir, which didn't get created the usual
262    # way due to thr trick above:
263    os.mkdir('develop-eggs')
264
265    def start_server(path):
266        port, thread = _start_server(path, name=path)
267        url = 'http://localhost:%s/' % port
268        register_teardown(lambda: stop_server(url, thread))
269        return url
270
271    test.globs.update(dict(
272        sample_buildout = sample,
273        ls = ls,
274        cat = cat,
275        mkdir = mkdir,
276        rmdir = rmdir,
277        remove = remove,
278        tmpdir = tmpdir,
279        write = write,
280        system = system,
281        get = get,
282        cd = (lambda *path: os.chdir(os.path.join(*path))),
283        join = os.path.join,
284        sdist = sdist,
285        bdist_egg = bdist_egg,
286        start_server = start_server,
287        buildout = os.path.join(sample, 'bin', 'buildout'),
288        wait_until = wait_until,
289        ))
290
291    zc.buildout.easy_install.prefer_final(prefer_final)
292
293def buildoutTearDown(test):
294    for f in test.globs['__tear_downs']:
295        f()
296
297class Server(BaseHTTPServer.HTTPServer):
298
299    def __init__(self, tree, *args):
300        BaseHTTPServer.HTTPServer.__init__(self, *args)
301        self.tree = os.path.abspath(tree)
302
303    __run = True
304    def serve_forever(self):
305        while self.__run:
306            self.handle_request()
307
308    def handle_error(self, *_):
309        self.__run = False
310
311class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
312
313    Server.__log = False
314
315    def __init__(self, request, address, server):
316        self.__server = server
317        self.tree = server.tree
318        BaseHTTPServer.BaseHTTPRequestHandler.__init__(
319            self, request, address, server)
320
321    def do_GET(self):
322        if '__stop__' in self.path:
323            raise SystemExit
324
325        if self.path == '/enable_server_logging':
326            self.__server.__log = True
327            self.send_response(200)
328            return
329
330        if self.path == '/disable_server_logging':
331            self.__server.__log = False
332            self.send_response(200)
333            return
334
335        path = os.path.abspath(os.path.join(self.tree, *self.path.split('/')))
336        if not (
337            ((path == self.tree) or path.startswith(self.tree+os.path.sep))
338            and
339            os.path.exists(path)
340            ):
341            self.send_response(404, 'Not Found')
342            #self.send_response(200)
343            out = '<html><body>Not Found</body></html>'
344            #out = '\n'.join(self.tree, self.path, path)
345            self.send_header('Content-Length', str(len(out)))
346            self.send_header('Content-Type', 'text/html')
347            self.end_headers()
348            self.wfile.write(out)
349            return
350
351        self.send_response(200)
352        if os.path.isdir(path):
353            out = ['<html><body>\n']
354            names = os.listdir(path)
355            names.sort()
356            for name in names:
357                if os.path.isdir(os.path.join(path, name)):
358                    name += '/'
359                out.append('<a href="%s">%s</a><br>\n' % (name, name))
360            out.append('</body></html>\n')
361            out = ''.join(out)
362            self.send_header('Content-Length', str(len(out)))
363            self.send_header('Content-Type', 'text/html')
364        else:
365            out = open(path, 'rb').read()
366            self.send_header('Content-Length', len(out))
367            if path.endswith('.egg'):
368                self.send_header('Content-Type', 'application/zip')
369            elif path.endswith('.gz'):
370                self.send_header('Content-Type', 'application/x-gzip')
371            elif path.endswith('.zip'):
372                self.send_header('Content-Type', 'application/x-gzip')
373            else:
374                self.send_header('Content-Type', 'text/html')
375        self.end_headers()
376
377        self.wfile.write(out)
378
379    def log_request(self, code):
380        if self.__server.__log:
381            print '%s %s %s' % (self.command, code, self.path)
382
383def _run(tree, port):
384    server_address = ('localhost', port)
385    httpd = Server(tree, server_address, Handler)
386    httpd.serve_forever()
387
388def get_port():
389    for i in range(10):
390        port = random.randrange(20000, 30000)
391        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
392        try:
393            try:
394                s.connect(('localhost', port))
395            except socket.error:
396                return port
397        finally:
398            s.close()
399    raise RuntimeError, "Can't find port"
400
401def _start_server(tree, name=''):
402    port = get_port()
403    thread = threading.Thread(target=_run, args=(tree, port), name=name)
404    thread.setDaemon(True)
405    thread.start()
406    wait(port, up=True)
407    return port, thread
408
409def start_server(tree):
410    return _start_server(tree)[0]
411
412def stop_server(url, thread=None):
413    try:
414        urllib2.urlopen(url+'__stop__')
415    except Exception:
416        pass
417    if thread is not None:
418        thread.join() # wait for thread to stop
419
420def wait(port, up):
421    addr = 'localhost', port
422    for i in range(120):
423        time.sleep(0.25)
424        try:
425            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
426            s.connect(addr)
427            s.close()
428            if up:
429                break
430        except socket.error, e:
431            if e[0] not in (errno.ECONNREFUSED, errno.ECONNRESET):
432                raise
433            s.close()
434            if not up:
435                break
436    else:
437        if up:
438            raise
439        else:
440            raise SystemError("Couln't stop server")
441
442def install(project, destination):
443    if not isinstance(destination, basestring):
444        destination = os.path.join(destination.globs['sample_buildout'],
445                                   'eggs')
446
447    dist = pkg_resources.working_set.find(
448        pkg_resources.Requirement.parse(project))
449    if dist.location.endswith('.egg'):
450        destination = os.path.join(destination,
451                                   os.path.basename(dist.location),
452                                   )
453        if os.path.isdir(dist.location):
454            shutil.copytree(dist.location, destination)
455        else:
456            shutil.copyfile(dist.location, destination)
457    else:
458        # copy link
459        open(os.path.join(destination, project+'.egg-link'), 'w'
460             ).write(dist.location)
461
462def install_develop(project, destination):
463    if not isinstance(destination, basestring):
464        destination = os.path.join(destination.globs['sample_buildout'],
465                                   'develop-eggs')
466
467    dist = pkg_resources.working_set.find(
468        pkg_resources.Requirement.parse(project))
469    open(os.path.join(destination, project+'.egg-link'), 'w'
470         ).write(dist.location)
471
472def _normalize_path(match):
473    path = match.group(1)
474    if os.path.sep == '\\':
475        path = path.replace('\\\\', '/')
476        if path.startswith('\\'):
477            path = path[1:]
478    return '/' + path.replace(os.path.sep, '/')
479
480normalize_path = (
481    re.compile(
482        r'''[^'" \t\n\r]+\%(sep)s_[Tt][Ee][Ss][Tt]_\%(sep)s([^"' \t\n\r]+)'''
483        % dict(sep=os.path.sep)),
484    _normalize_path,
485    )
486
487normalize_script = (
488    re.compile('(\n?)-  ([a-zA-Z_.-]+)-script.py\n\\2.exe\n'),
489    '\\1-  \\2\n')
490
491normalize_egg_py = (
492    re.compile('-py\d[.]\d(-\S+)?.egg'),
493    '-pyN.N.egg',
494    )
Note: See TracBrowser for help on using the repository browser.