source: rtems-source-builder/source-builder/sb/bootstrap.py @ 8225925

4.104.114.9
Last change on this file since 8225925 was 8225925, checked in by Chris Johns <chrisj@…>, on Dec 14, 2013 at 1:15:14 AM

Use the --jobs option.

  • Property mode set to 100644
File size: 9.0 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2013 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Permission to use, copy, modify, and/or distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19#
20
21import datetime
22import operator
23import os
24import re
25import sys
26import threading
27import time
28
29import error
30import log
31import options
32import path
33import version
34
35def _collect(path_, file):
36    confs = []
37    for root, dirs, files in os.walk(path.host(path_), topdown = True):
38        for f in files:
39            if f == file:
40                confs += [path.shell(path.join(root, f))]
41    return confs
42
43def _grep(file, pattern):
44    rege = re.compile(pattern)
45    try:
46        f = open(path.host(file), 'r')
47        matches = [rege.match(l) != None for l in f.readlines()]
48        f.close()
49    except IOError, err:
50        raise error.general('error reading: %s' % (file))
51    return True in matches
52
53class command:
54
55    def __init__(self, cmd, cwd):
56        self.exit_code = 0
57        self.thread = None
58        self.output = None
59        self.cmd = cmd
60        self.cwd = cwd
61
62    def runner(self):
63
64        import subprocess
65
66        #
67        # Support Python 2.6
68        #
69        if "check_output" not in dir(subprocess):
70            def f(*popenargs, **kwargs):
71                if 'stdout' in kwargs:
72                    raise ValueError('stdout argument not allowed, it will be overridden.')
73                process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
74                output, unused_err = process.communicate()
75                retcode = process.poll()
76                if retcode:
77                    cmd = kwargs.get("args")
78                    if cmd is None:
79                        cmd = popenargs[0]
80                    raise CalledProcessError(retcode, cmd)
81                return output
82            subprocess.check_output = f
83
84        self.start_time = datetime.datetime.now()
85        self.exit_code = 0
86        try:
87            self.output = subprocess.check_output(self.cmd, cwd = self.cwd)
88        except subprocess.CalledProcessError, cpe:
89            self.exit_code = cpe.returncode
90            self.output = cpe.output
91        except OSError, ose:
92            raise error.general('bootstrap failed: %s in %s: %s' % \
93                                (' '.join(self.cmd), self.cwd, (str(ose))))
94        self.end_time = datetime.datetime.now()
95
96    def run(self):
97        self.thread = threading.Thread(target = self.runner)
98        self.thread.start()
99
100    def is_alive(self):
101        return self.thread and self.thread.is_alive()
102
103class autoreconf:
104
105    def __init__(self, topdir, configure):
106        self.topdir = topdir
107        self.configure = configure
108        self.cwd = path.dirname(self.configure)
109        self.bspopts()
110        self.command = command(['autoreconf', '-i', '--no-recursive'], self.cwd)
111        self.command.run()
112
113    def bspopts(self):
114        if _grep(self.configure, 'RTEMS_CHECK_BSPDIR'):
115            bsp_specs = _collect(self.cwd, 'bsp_specs')
116            try:
117                acinclude = path.join(self.cwd, 'acinclude.m4')
118                b = open(path.host(acinclude), 'w')
119                b.write('# RTEMS_CHECK_BSPDIR(RTEMS_BSP_FAMILY)' + os.linesep)
120                b.write('AC_DEFUN([RTEMS_CHECK_BSPDIR],' + os.linesep)
121                b.write('[' + os.linesep)
122                b.write('  case "$1" in' + os.linesep)
123                for bs in sorted(bsp_specs):
124                    dir = path.dirname(bs)[len(self.cwd) + 1:]
125                    b.write(%s )%s' % (dir, os.linesep))
126                    b.write('    AC_CONFIG_SUBDIRS([%s]);;%s' % (dir, os.linesep))
127                b.write('  *)' + os.linesep)
128                b.write('    AC_MSG_ERROR([Invalid BSP]);;' + os.linesep)
129                b.write('  esac' + os.linesep)
130                b.write('])' + os.linesep)
131                b.close()
132            except IOError, err:
133                raise error.general('error writing: %s' % (acinclude))
134
135    def is_alive(self):
136        return self.command.is_alive()
137
138    def post_process(self):
139        if self.command is not None:
140            if self.command.exit_code != 0:
141                raise error.general('error: autoreconf: %s' % (' '.join(self.command.cmd)))
142            makefile = path.join(self.cwd, 'Makefile.am')
143            if path.exists(makefile):
144                if _grep(makefile, 'stamp-h\.in'):
145                    stamp_h = path.join(self.cwd, 'stamp-h.in')
146                    try:
147                        t = open(path.host(stamp_h), 'w')
148                        t.write('timestamp')
149                        t.close()
150                    except IOError, err:
151                        raise error.general('error writing: %s' % (stamp_h))
152
153def generate(topdir, jobs):
154    if type(jobs) is str:
155        jobs = int(jobs)
156    start_time = datetime.datetime.now()
157    confs = _collect(topdir, 'configure.ac')
158    next = 0
159    autoreconfs = []
160    while next < len(confs) or len(autoreconfs) > 0:
161        if next < len(confs) and len(autoreconfs) < jobs:
162            log.notice('%3d/%3d: autoreconf: %s' % \
163                           (next + 1, len(confs), confs[next][len(topdir) + 1:]))
164            autoreconfs += [autoreconf(topdir, confs[next])]
165            next += 1
166        else:
167            for ac in autoreconfs:
168                if not ac.is_alive():
169                    ac.post_process()
170                    autoreconfs.remove(ac)
171                    del ac
172            if len(autoreconfs) >= jobs:
173                time.sleep(1)
174    end_time = datetime.datetime.now()
175    log.notice('Bootstrap time: %s' % (str(end_time - start_time)))
176
177class ampolish3:
178
179    def __init__(self, topdir, makefile):
180        self.topdir = topdir
181        self.makefile = makefile
182        self.preinstall = path.join(path.dirname(makefile), 'preinstall.am')
183        self.command = command([path.join(topdir, 'ampolish3'), makefile], self.topdir)
184        self.command.run()
185
186    def is_alive(self):
187        return self.command.is_alive()
188
189    def post_process(self):
190        if self.command is not None:
191            if self.command.exit_code != 0:
192                raise error.general('error: ampolish3: %s' % (' '.join(self.command.cmd)))
193            try:
194                p = open(path.host(self.preinstall), 'w')
195                for l in self.command.output:
196                    p.write(l)
197                p.close()
198            except IOError, err:
199                raise error.general('error writing: %s' % (self.preinstall))
200
201def preinstall(topdir, jobs):
202    if type(jobs) is str:
203        jobs = int(jobs)
204    start_time = datetime.datetime.now()
205    makes = []
206    for am in _collect(topdir, 'Makefile.am'):
207        if _grep(am, 'include .*/preinstall\.am'):
208            makes += [am]
209    next = 0
210    ampolish3s = []
211    while next < len(makes) or len(ampolish3s) > 0:
212        if next < len(makes) and len(ampolish3s) < jobs:
213            log.notice('%3d/%3d: ampolish3: %s' % \
214                           (next + 1, len(makes), makes[next][len(topdir) + 1:]))
215            ampolish3s += [ampolish3(topdir, makes[next])]
216            next += 1
217        else:
218            for ap in ampolish3s:
219                if not ap.is_alive():
220                    ap.post_process()
221                    ampolish3s.remove(ap)
222                    del ap
223            if len(ampolish3s) >= jobs:
224                time.sleep(1)
225    end_time = datetime.datetime.now()
226    log.notice('Preinstall time: %s' % (str(end_time - start_time)))
227
228def run(args):
229    try:
230        optargs = { '--rtems':       'The RTEMS source directory',
231                    '--preinstall':  'Preinstall AM generation' }
232        log.notice('RTEMS Source Builder - RTEMS Bootstrap, v%s' % (version.str()))
233        opts = options.load(sys.argv, optargs)
234        if opts.get_arg('--rtems'):
235            topdir = opts.get_arg('--rtems')
236        else:
237            topdir = os.getcwd()
238        if opts.get_arg('--preinstall'):
239            preinstall(topdir, opts.jobs(opts.defaults['_ncpus']))
240        else:
241            generate(topdir, opts.jobs(opts.defaults['_ncpus']))
242    except error.general, gerr:
243        print gerr
244        print >> sys.stderr, 'Bootstrap FAILED'
245        sys.exit(1)
246    except error.internal, ierr:
247        print ierr
248        print >> sys.stderr, 'Bootstrap FAILED'
249        sys.exit(1)
250    except error.exit, eerr:
251        pass
252    except KeyboardInterrupt:
253        log.notice('abort: user terminated')
254        sys.exit(1)
255    sys.exit(0)
256
257if __name__ == "__main__":
258    run(sys.argv)
Note: See TracBrowser for help on using the repository browser.