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

4.11
Last change on this file since e8f5111 was e8f5111, checked in by Chris Johns <chrisj@…>, on Dec 3, 2015 at 11:22:17 AM

sb. Add VERSION support for releasing the RSB.

Add support to release the RSB by adding the VERSION file. The file
is a single line with the version.

Fix the reports to include the version. Update the INI file
support to include the details of the build.

Show the GIT or released version when the command starts.

Closes #2480.

  • Property mode set to 100644
File size: 9.4 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('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        self.result = None
62
63    def runner(self):
64
65        import subprocess
66
67        #
68        # Support Python 2.6
69        #
70        if "check_output" not in dir(subprocess):
71            def f(*popenargs, **kwargs):
72                if 'stdout' in kwargs:
73                    raise ValueError('stdout argument not allowed, it will be overridden.')
74                process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
75                output, unused_err = process.communicate()
76                retcode = process.poll()
77                if retcode:
78                    cmd = kwargs.get("args")
79                    if cmd is None:
80                        cmd = popenargs[0]
81                    raise subprocess.CalledProcessError(retcode, cmd)
82                return output
83            subprocess.check_output = f
84
85        self.start_time = datetime.datetime.now()
86        self.exit_code = 0
87        try:
88            try:
89                self.output = subprocess.check_output(self.cmd, cwd = self.cwd)
90            except subprocess.CalledProcessError, cpe:
91                self.exit_code = cpe.returncode
92                self.output = cpe.output
93            except OSError, ose:
94                raise error.general('bootstrap failed: %s in %s: %s' % \
95                                        (' '.join(self.cmd), self.cwd, (str(ose))))
96            except KeyboardInterrupt:
97                pass
98            except:
99                raise
100        except:
101            self.result = sys.exc_info()
102        self.end_time = datetime.datetime.now()
103
104    def run(self):
105        self.thread = threading.Thread(target = self.runner)
106        self.thread.start()
107
108    def is_alive(self):
109        return self.thread and self.thread.is_alive()
110
111    def reraise(self):
112        if self.result is not None:
113            raise self.result[0], self.result[1], self.result[2]
114
115class autoreconf:
116
117    def __init__(self, topdir, configure):
118        self.topdir = topdir
119        self.configure = configure
120        self.cwd = path.dirname(self.configure)
121        self.bspopts()
122        self.command = command(['autoreconf', '-i', '--no-recursive'], self.cwd)
123        self.command.run()
124
125    def bspopts(self):
126        if _grep(self.configure, 'RTEMS_CHECK_BSPDIR'):
127            bsp_specs = _collect(self.cwd, 'bsp_specs')
128            try:
129                acinclude = path.join(self.cwd, 'acinclude.m4')
130                b = open(path.host(acinclude), 'w')
131                b.write('# RTEMS_CHECK_BSPDIR(RTEMS_BSP_FAMILY)' + os.linesep)
132                b.write('AC_DEFUN([RTEMS_CHECK_BSPDIR],' + os.linesep)
133                b.write('[' + os.linesep)
134                b.write('  case "$1" in' + os.linesep)
135                for bs in sorted(bsp_specs):
136                    dir = path.dirname(bs)[len(self.cwd) + 1:]
137                    b.write(%s )%s' % (dir, os.linesep))
138                    b.write('    AC_CONFIG_SUBDIRS([%s]);;%s' % (dir, os.linesep))
139                b.write('  *)' + os.linesep)
140                b.write('    AC_MSG_ERROR([Invalid BSP]);;' + os.linesep)
141                b.write('  esac' + os.linesep)
142                b.write('])' + os.linesep)
143                b.close()
144            except IOError, err:
145                raise error.general('writing: %s' % (acinclude))
146
147    def is_alive(self):
148        return self.command.is_alive()
149
150    def post_process(self):
151        if self.command is not None:
152            self.command.reraise()
153            if self.command.exit_code != 0:
154                raise error.general('error: autoreconf: %s' % (' '.join(self.command.cmd)))
155            makefile = path.join(self.cwd, 'Makefile.am')
156            if path.exists(makefile):
157                if _grep(makefile, 'stamp-h\.in'):
158                    stamp_h = path.join(self.cwd, 'stamp-h.in')
159                    try:
160                        t = open(path.host(stamp_h), 'w')
161                        t.write('timestamp')
162                        t.close()
163                    except IOError, err:
164                        raise error.general('writing: %s' % (stamp_h))
165
166def generate(topdir, jobs):
167    if type(jobs) is str:
168        jobs = int(jobs)
169    start_time = datetime.datetime.now()
170    confs = _collect(topdir, 'configure.ac')
171    next = 0
172    autoreconfs = []
173    while next < len(confs) or len(autoreconfs) > 0:
174        if next < len(confs) and len(autoreconfs) < jobs:
175            log.notice('%3d/%3d: autoreconf: %s' % \
176                           (next + 1, len(confs), confs[next][len(topdir) + 1:]))
177            autoreconfs += [autoreconf(topdir, confs[next])]
178            next += 1
179        else:
180            for ac in autoreconfs:
181                if not ac.is_alive():
182                    ac.post_process()
183                    autoreconfs.remove(ac)
184                    del ac
185            if len(autoreconfs) >= jobs:
186                time.sleep(1)
187    end_time = datetime.datetime.now()
188    log.notice('Bootstrap time: %s' % (str(end_time - start_time)))
189
190class ampolish3:
191
192    def __init__(self, topdir, makefile):
193        self.topdir = topdir
194        self.makefile = makefile
195        self.preinstall = path.join(path.dirname(makefile), 'preinstall.am')
196        self.command = command([path.join(topdir, 'ampolish3'), makefile], self.topdir)
197        self.command.run()
198
199    def is_alive(self):
200        return self.command.is_alive()
201
202    def post_process(self):
203        if self.command is not None:
204            if self.command.exit_code != 0:
205                raise error.general('error: ampolish3: %s' % (' '.join(self.command.cmd)))
206            try:
207                p = open(path.host(self.preinstall), 'w')
208                for l in self.command.output:
209                    p.write(l)
210                p.close()
211            except IOError, err:
212                raise error.general('writing: %s' % (self.preinstall))
213
214def preinstall(topdir, jobs):
215    if type(jobs) is str:
216        jobs = int(jobs)
217    start_time = datetime.datetime.now()
218    makes = []
219    for am in _collect(topdir, 'Makefile.am'):
220        if _grep(am, 'include .*/preinstall\.am'):
221            makes += [am]
222    next = 0
223    ampolish3s = []
224    while next < len(makes) or len(ampolish3s) > 0:
225        if next < len(makes) and len(ampolish3s) < jobs:
226            log.notice('%3d/%3d: ampolish3: %s' % \
227                           (next + 1, len(makes), makes[next][len(topdir) + 1:]))
228            ampolish3s += [ampolish3(topdir, makes[next])]
229            next += 1
230        else:
231            for ap in ampolish3s:
232                if not ap.is_alive():
233                    ap.post_process()
234                    ampolish3s.remove(ap)
235                    del ap
236            if len(ampolish3s) >= jobs:
237                time.sleep(1)
238    end_time = datetime.datetime.now()
239    log.notice('Preinstall time: %s' % (str(end_time - start_time)))
240
241def run(args):
242    try:
243        optargs = { '--rtems':       'The RTEMS source directory',
244                    '--preinstall':  'Preinstall AM generation' }
245        log.notice('RTEMS Source Builder - RTEMS Bootstrap, %s' % (version.str()))
246        opts = options.load(sys.argv, optargs)
247        if opts.get_arg('--rtems'):
248            topdir = opts.get_arg('--rtems')
249        else:
250            topdir = os.getcwd()
251        if opts.get_arg('--preinstall'):
252            preinstall(topdir, opts.jobs(opts.defaults['_ncpus']))
253        else:
254            generate(topdir, opts.jobs(opts.defaults['_ncpus']))
255    except error.general, gerr:
256        print gerr
257        print >> sys.stderr, 'Bootstrap FAILED'
258        sys.exit(1)
259    except error.internal, ierr:
260        print ierr
261        print >> sys.stderr, 'Bootstrap FAILED'
262        sys.exit(1)
263    except error.exit, eerr:
264        pass
265    except KeyboardInterrupt:
266        log.notice('abort: user terminated')
267        sys.exit(1)
268    sys.exit(0)
269
270if __name__ == "__main__":
271    run(sys.argv)
Note: See TracBrowser for help on using the repository browser.