source: rtems-source-builder/source-builder/sb/defaults.py @ 69e5938

4.104.114.95
Last change on this file since 69e5938 was 0add2ea, checked in by Chris Johns <chrisj@…>, on 04/03/13 at 03:31:41

PR 2108, PR 2109. Add --jobs and --always-clean.

Refactor the options handling in defaults.py to allow the --jobs
option have varing specific parameters. The option supports 'none',
'max' and 'half' or a fraction to divide the number of CPUs or
an integer value which is the number of jobs. The --no-smp has
been removed.

The host specific modules have been changed to set the number of
CPUs in the defaults table.

Fixed the --keep-going to clean up is --always-clean is provided
even if the build has an error.

  • Property mode set to 100644
File size: 28.4 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2012 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#
21# Determine the defaults and load the specific file.
22#
23
24import glob
25import pprint
26import re
27import os
28
29import error
30import execute
31import git
32import path
33import sys
34
35basepath = 'sb'
36
37#
38# All paths in defaults must be Unix format. Do not store any Windows format
39# paths in the defaults.
40#
41# Every entry must describe the type of checking a host must pass.
42#
43
44defaults = {
45# Nothing
46'nil':                 ('none', 'none', ''),
47
48# Set to invalid values.
49'_bset':               ('none',    'none', ''),
50'name':                ('none',    'none', ''),
51'version':             ('none',    'none', ''),
52'release':             ('none',    'none', ''),
53
54# GNU triples needed to build packages
55'_host':               ('triplet', 'required', ''),
56'_build':              ('triplet', 'required', '%{_host}'),
57'_target':             ('none',    'optional', ''),
58
59# Paths
60'_host_platform':      ('none',    'none',     '%{_host_cpu}-%{_host_vendor}-%{_host_os}%{?_gnu}'),
61'_arch':               ('none',    'none',     '%{_host_arch}'),
62'_sbdir':              ('none',    'none',     ''),
63'_topdir':             ('dir',     'required',  path.shell(os.getcwd())),
64'_configdir':          ('dir',     'optional', '%{_topdir}/config:%{_sbdir}/config'),
65'_tardir':             ('dir',     'optional', '%{_topdir}/tar'),
66'_sourcedir':          ('dir',     'optional', '%{_topdir}/sources'),
67'_patchdir':           ('dir',     'optional', '%{_topdir}/patches:%{_sbdir}/patches'),
68'_builddir':           ('dir',     'optional', '%{_topdir}/build/%{name}-%{version}-%{release}'),
69'_buildcxcdir':        ('dir',     'optional', '%{_topdir}/build/%{name}-%{version}-%{release}-cxc'),
70'_docdir':             ('dir',     'none',     '%{_defaultdocdir}'),
71'_tmppath':            ('dir',     'none',     '%{_topdir}/build/tmp'),
72'_tmproot':            ('dir',     'none',     '%{_tmppath}/source-build-%(%{__id_u} -n)/%{_bset}'),
73'_tmpcxcroot':         ('dir',     'none',     '%{_tmppath}/source-build-%(%{__id_u} -n)-cxc/%{_bset}'),
74'buildroot':           ('dir',     'none',     '%{_tmppath}/%{name}-root-%(%{__id_u} -n)'),
75'buildcxcroot':        ('dir',     'none',     '%{_tmppath}/%{name}-root-%(%{__id_u} -n)-cxc'),
76'_datadir':            ('dir',     'none',     '%{_prefix}/share'),
77'_defaultdocdir':      ('dir',     'none',     '%{_prefix}/share/doc'),
78'_exeext':             ('none',    'none',     ''),
79'_exec_prefix':        ('dir',     'none',     '%{_prefix}'),
80'_bindir':             ('dir',     'none',     '%{_exec_prefix}/bin'),
81'_sbindir':            ('dir',     'none',     '%{_exec_prefix}/sbin'),
82'_libexecdir':         ('dir',     'none',     '%{_exec_prefix}/libexec'),
83'_datarootdir':        ('dir',     'none',     '%{_prefix}/share'),
84'_datadir':            ('dir',     'none',     '%{_datarootdir}'),
85'_sysconfdir':         ('dir',     'none',     '%{_prefix}/etc'),
86'_sharedstatedir':     ('dir',     'none',     '%{_prefix}/com'),
87'_localstatedir':      ('dir',     'none',     '%{prefix}/var'),
88'_includedir':         ('dir',     'none',     '%{_prefix}/include'),
89'_lib':                ('dir',     'none',     'lib'),
90'_libdir':             ('dir',     'none',     '%{_exec_prefix}/%{_lib}'),
91'_libexecdir':         ('dir',     'none',     '%{_exec_prefix}/libexec'),
92'_mandir':             ('dir',     'none',     '%{_datarootdir}/man'),
93'_infodir':            ('dir',     'none',     '%{_datarootdir}/info'),
94'_localedir':          ('dir',     'none',     '%{_datarootdir}/locale'),
95'_localedir':          ('dir',     'none',     '%{_datadir}/locale'),
96'_localstatedir':      ('dir',     'none',     '%{_prefix}/var'),
97'_prefix':             ('dir',     'none',     '%{_usr}'),
98'_usr':                ('dir',     'none',     '/usr/local'),
99'_usrsrc':             ('dir',     'none',     '%{_usr}/src'),
100'_var':                ('dir',     'none',     '/usr/local/var'),
101'_varrun':             ('dir',     'none',     '%{_var}/run'),
102
103# Defaults, override in platform specific modules.
104'___setup_shell':      ('exe',     'required', '/bin/sh'),
105'__aclocal':           ('exe',     'optional', 'aclocal'),
106'__ar':                ('exe',     'required', 'ar'),
107'__arch_install_post': ('exe',     'none',     '%{nil}'),
108'__as':                ('exe',     'required', 'as'),
109'__autoconf':          ('exe',     'required', 'autoconf'),
110'__autoheader':        ('exe',     'required', 'autoheader'),
111'__automake':          ('exe',     'required', 'automake'),
112'__awk':               ('exe',     'required', 'awk'),
113'__bash':              ('exe',     'optional', '/bin/bash'),
114'__bison':             ('exe',     'required', '/usr/bin/bison'),
115'__bzip2':             ('exe',     'required', '/usr/bin/bzip2'),
116'__cat':               ('exe',     'required', '/bin/cat'),
117'__cc':                ('exe',     'required', '/usr/bin/gcc'),
118'__chgrp':             ('exe',     'required', '/usr/bin/chgrp'),
119'__chmod':             ('exe',     'required', '/bin/chmod'),
120'__chown':             ('exe',     'required', '/usr/sbin/chown'),
121'__cp':                ('exe',     'required', '/bin/cp'),
122'__cpp':               ('exe',     'none',     '%{__cc} -E'),
123'__cxx':               ('exe',     'required', '/usr/bin/g++'),
124'__flex':              ('exe',     'required', '/usr/bin/flex'),
125'__git':               ('exe',     'required', '/usr/bin/git'),
126'__grep':              ('exe',     'required', '/usr/bin/grep'),
127'__gzip':              ('exe',     'required', '/usr/bin/gzip'),
128'__id':                ('exe',     'required', '/usr/bin/id'),
129'__id_u':              ('exe',     'none',     '%{__id} -u'),
130'__install':           ('exe',     'required', '/usr/bin/install'),
131'__install_info':      ('exe',     'optional', '/usr/bin/install-info'),
132'__ld':                ('exe',     'required', '/usr/bin/ld'),
133'__ldconfig':          ('exe',     'required', '/sbin/ldconfig'),
134'__ln_s':              ('exe',     'none',     'ln -s'),
135'__make':              ('exe',     'required', 'make'),
136'__makeinfo':          ('exe',     'required', '/usr/bin/makeinfo'),
137'__mkdir':             ('exe',     'required', '/bin/mkdir'),
138'__mkdir_p':           ('exe',     'none',     '/bin/mkdir -p'),
139'__mv':                ('exe',     'required', '/bin/mv'),
140'__nm':                ('exe',     'required', '/usr/bin/nm'),
141'__objcopy':           ('exe',     'optional', '/usr/bin/objcopy'),
142'__objdump':           ('exe',     'optional', '/usr/bin/objdump'),
143'__patch_bin':         ('exe',     'required', '/usr/bin/patch'),
144'__patch_opts':        ('none',    'none',     '%{nil}'),
145'__patch':             ('exe',     'none',     '%{__patch_bin} %{__patch_opts}'),
146'__perl':              ('exe',     'optional', 'perl'),
147'__ranlib':            ('exe',     'required', 'ranlib'),
148'__rm':                ('exe',     'required', '/bin/rm'),
149'__rmfile':            ('exe',     'none',     '%{__rm} -f'),
150'__rmdir':             ('exe',     'none',     '%{__rm} -rf'),
151'__sed':               ('exe',     'required', '/usr/bin/sed'),
152'__setup_post':        ('exe',     'none',     '%{__chmod} -R a+rX,g-w,o-w .'),
153'__sh':                ('exe',     'required', '/bin/sh'),
154'__tar':               ('exe',     'required', '/usr/bin/tar'),
155'__tar_extract':       ('exe',     'none',     '%{__tar} -xvvf'),
156'__touch':             ('exe',     'required', '/usr/bin/touch'),
157'__unzip':             ('exe',     'required', '/usr/bin/unzip'),
158'__xz':                ('exe',     'required', '/usr/bin/xz'),
159
160# Shell Build Settings.
161'___build_args': ('none', 'none', '-e'),
162'___build_cmd':  ('none', 'none', '%{?_sudo:%{_sudo} }%{?_remsh:%{_remsh} %{_remhost} }%{?_remsudo:%{_remsudo} }%{?_remchroot:%{_remchroot} %{_remroot} }%{___build_shell} %{___build_args}'),
163'___build_post': ('none', 'none', 'exit 0'),
164
165# Prebuild set up script.
166'___build_pre': ('none', 'none', '''# ___build_pre in as set up in defaults.py
167# Save the original path away.
168export SB_ORIG_PATH=${PATH}
169# Directories
170%{?_prefix:SB_PREFIX="%{_prefix}"}
171%{?_prefix:SB_PREFIX_CLEAN=$(echo "%{_prefix}" | %{__sed} -e \'s/^\///\')}
172SB_SOURCE_DIR="%{_sourcedir}"
173SB_BUILD_DIR="%{_builddir}"
174SB_OPT_FLAGS="%{?_tmproot:-I%{_tmproot}/${SB_PREFIX_CLEAN}/include -L%{_tmproot}/${SB_PREFIX_CLEAN}/lib} %{optflags}"
175SB_ARCH="%{_arch}"
176SB_OS="%{_os}"
177export SB_SOURCE_DIR SB_BUILD_DIR SB_OPT_FLAGS SB_ARCH SB_OS
178# Documentation
179SB_DOC_DIR="%{_docdir}"
180export SB_DOC_DIR
181# Packages
182SB_PACKAGE_NAME="%{name}"
183SB_PACKAGE_VERSION="%{version}"
184SB_PACKAGE_RELEASE="%{release}"
185export SB_PACKAGE_NAME SB_PACKAGE_VERSION SB_PACKAGE_RELEASE
186# Build directories
187export SB_PREFIX
188%{?_builddir:SB_BUILD_DIR="%{_builddir}"}
189%{?buildroot:SB_BUILD_ROOT="%{buildroot}"}
190%{?buildroot:%{?_prefix:SB_BUILD_ROOT_BINDIR="%{buildroot}/${SB_PREFIX_CLEAN}/bin"}}
191export SB_BUILD_ROOT SB_BUILD_DIR SB_BUILD_ROOT_BINDIR
192%{?_buildcxcdir:SB_BUILD_CXC_DIR="%{_buildcxcdir}"}
193%{?buildcxcroot:SB_BUILD_CXC_ROOT="%{buildcxcroot}"}
194%{?buildcxcroot:%{?_prefix:SB_BUILD_CXC_ROOT_BINDIR="%{buildcxcroot}/${SB_PREFIX_CLEAN}/bin"}}
195export SB_BUILD_CXC_ROOT SB_BUILD_CXC_DIR SB_BUILD_CXC_ROOT_BINDIR
196%{?_tmproot:SB_TMPROOT="%{_tmproot}"}
197%{?_tmproot:%{?_prefix:SB_TMPPREFIX="%{_tmproot}/${SB_PREFIX_CLEAN}"}}
198%{?_tmproot:%{?_prefix:SB_TMPBINDIR="%{_tmproot}/${SB_PREFIX_CLEAN}/bin"}}
199export SB_TMPROOT SB_TMPPREFIX SB_TMPBINDIR
200%{?_tmpcxcroot:SB_TMPCXCROOT="%{_tmproot}"}
201%{?_tmpcxcroot:%{?_prefix:SB_TMPCXCPREFIX="%{_tmpcxcroot}/${SB_PREFIX_CLEAN}"}}
202%{?_tmpcxcroot:%{?_prefix:SB_TMPCXCBINDIR="%{_tmpcxcroot}/${SB_PREFIX_CLEAN}/bin"}}
203export SB_TMPCXCROOT SB_TMPCXCPREFIX SB_TMPCXCBINDIR
204# The compiler flags
205%{?_targetcflags:CFLAGS_FOR_TARGET="%{_targetcflags}"}
206%{?_targetcxxflags:CXXFLAGS_FOR_TARGET="%{_targetcxxflags}"}
207export CFLAGS_FOR_TARGET
208export CXXFLAGS_FOR_TARGET
209# Set up the path. Put the CXC path first.
210if test -n "${SB_TMPBINDIR}" ; then
211 PATH="${SB_TMPBINDIR}:$PATH"
212fi
213if test -n "${SB_TMPCXCBINDIR}" ; then
214 PATH="${SB_TMPCXCBINDIR}:$PATH"
215fi
216export PATH
217# Default environment set up.
218LANG=C
219export LANG
220unset DISPLAY || :
221umask 022
222cd "%{_builddir}"'''),
223'___build_shell': ('none', 'none', '%{?_buildshell:%{_buildshell}}%{!?_buildshell:/bin/sh}'),
224'___build_template': ('none', 'none', '''#!%{___build_shell}
225%{___build_pre}
226%{nil}'''),
227
228# Configure command
229'configure': ('none', 'none', '''
230CFLAGS="${CFLAGS:-%optflags}" ; export CFLAGS ;
231CXXFLAGS="${CXXFLAGS:-%optflags}" ; export CXXFLAGS ;
232FFLAGS="${FFLAGS:-%optflags}" ; export FFLAGS ;
233./configure --build=%{_build} --host=%{_host} \
234      --target=%{_target_platform} \
235      --program-prefix=%{?_program_prefix} \
236      --prefix=%{_prefix} \
237      --exec-prefix=%{_exec_prefix} \
238      --bindir=%{_bindir} \
239      --sbindir=%{_sbindir} \
240      --sysconfdir=%{_sysconfdir} \
241      --datadir=%{_datadir} \
242      --includedir=%{_includedir} \
243      --libdir=%{_libdir} \
244      --libexecdir=%{_libexecdir} \
245      --localstatedir=%{_localstatedir} \
246      --sharedstatedir=%{_sharedstatedir} \
247      --mandir=%{_mandir} \
248      --infodir=%{_infodir}''')
249}
250
251class command_line:
252    """Process the command line in a common way for all Tool Builder commands."""
253
254    def __init__(self, argv, optargs):
255        self._long_opts = {
256            # key                 macro              handler            param  defs    init
257            '--prefix'         : ('_prefix',         self._lo_path,     True,  None,  False),
258            '--topdir'         : ('_topdir',         self._lo_path,     True,  None,  False),
259            '--configdir'      : ('_configdir',      self._lo_path,     True,  None,  False),
260            '--builddir'       : ('_builddir',       self._lo_path,     True,  None,  False),
261            '--sourcedir'      : ('_sourcedir',      self._lo_path,     True,  None,  False),
262            '--tmppath'        : ('_tmppath',        self._lo_path,     True,  None,  False),
263            '--jobs'           : ('_jobs',           self._lo_jobs,     True,  'max', True),
264            '--log'            : ('_logfile',        self._lo_string,   True,  None,  False),
265            '--url'            : ('_url_base',       self._lo_string,   True,  None,  False),
266            '--targetcflags'   : ('_targetcflags',   self._lo_string,   True,  None,  False),
267            '--targetcxxflags' : ('_targetcxxflags', self._lo_string,   True,  None,  False),
268            '--libstdcxxflags' : ('_libstdcxxflags', self._lo_string,   True,  None,  False),
269            '--force'          : ('_force',          self._lo_bool,     False, '0',   True),
270            '--quiet'          : ('_quiet',          self._lo_bool,     False, '0',   True),
271            '--trace'          : ('_trace',          self._lo_bool,     False, '0',   True),
272            '--dry-run'        : ('_dry_run',        self._lo_bool,     False, '0',   True),
273            '--warn-all'       : ('_warn_all',       self._lo_bool,     False, '0',   True),
274            '--no-clean'       : ('_no_clean',       self._lo_bool,     False, '0',   True),
275            '--keep-going'     : ('_keep_going',     self._lo_bool,     False, '0',   True),
276            '--always-clean'   : ('_always_clean',   self._lo_bool,     False, '0',   True),
277            '--host'           : ('_host',           self._lo_triplets, True,  None,  False),
278            '--build'          : ('_build',          self._lo_triplets, True,  None,  False),
279            '--target'         : ('_target',         self._lo_triplets, True,  None,  False),
280            '--help'           : (None,              self._lo_help,     False, None,  False)
281            }
282
283        self.command_path = path.dirname(argv[0])
284        if len(self.command_path) == 0:
285            self.command_path = '.'
286        self.command_name = path.basename(argv[0])
287        self.argv = argv
288        self.args = argv[1:]
289        self.optargs = optargs
290        self.defaults = {}
291        self.defaults['_sbdir'] = ('dir', 'required', path.shell(self.command_path))
292        self.opts = { 'params' : [] }
293        for lo in self._long_opts:
294            self.opts[lo[2:]] = self._long_opts[lo][3]
295            if self._long_opts[lo][4]:
296                self.defaults[self._long_opts[lo][0]] = ('none', 'none', self._long_opts[lo][3])
297        self._process()
298
299    def __str__(self):
300        def _dict(dd):
301            s = ''
302            ddl = dd.keys()
303            ddl.sort()
304            for d in ddl:
305                s += '  ' + d + ': ' + str(dd[d]) + '\n'
306            return s
307
308        s = 'command: ' + self.command() + \
309            '\nargs: ' + str(self.args) + \
310            '\nopts:\n' + _dict(self.opts)
311
312        return s
313
314    def _lo_string(self, opt, macro, value):
315        if value is None:
316            raise error.general('option requires a value: %s' % (opt))
317        self.opts[opt[2:]] = value
318        self.defaults[macro] = ('none', 'none', value)
319
320    def _lo_path(self, opt, macro, value):
321        if value is None:
322            raise error.general('option requires a path: %s' % (opt))
323        value = path.shell(value)
324        self.opts[opt[2:]] = value
325        self.defaults[macro] = ('none', 'none', value)
326
327    def _lo_jobs(self, opt, macro, value):
328        if value is None:
329            raise error.general('option requires a value: %s' % (opt))
330        ok = False
331        if value in ['max', 'none', 'half']:
332            ok = True
333        else:
334            try:
335                i = int(value)
336                ok = True
337            except:
338                pass
339            if not ok:
340                try:
341                    f = float(value)
342                    ok = True
343                except:
344                    pass
345        if not ok:
346            raise error.general('invalid jobs option: %s' % (value))
347        self.defaults[macro] = ('none', 'none', value)
348        self.opts[opt[2:]] = value
349
350    def _lo_bool(self, opt, macro, value):
351        if value is not None:
352            raise error.general('option does not take a value: %s' % (opt))
353        self.opts[opt[2:]] = '1'
354        self.defaults[macro] = ('none', 'none', '1')
355
356    def _lo_triplets(self, opt, macro, value):
357        #
358        # This is a target triplet. Run it past config.sub to make make sure it
359        # is ok.  The target triplet is 'cpu-vendor-os'.
360        #
361        e = execute.capture_execution()
362        config_sub = path.join(self.command_path,
363                               basepath, 'config.sub')
364        exit_code, proc, output = e.shell(config_sub + ' ' + value)
365        if exit_code == 0:
366            value = output
367        self.defaults[macro] = ('triplet', 'none', value)
368        self.opts[opt[2:]] = value
369        _cpu = macro + '_cpu'
370        _arch = macro + '_arch'
371        _vendor = macro + '_vendor'
372        _os = macro + '_os'
373        _arch_value = ''
374        _vendor_value = ''
375        _os_value = ''
376        dash = value.find('-')
377        if dash >= 0:
378            _arch_value = value[:dash]
379            value = value[dash + 1:]
380        dash = value.find('-')
381        if dash >= 0:
382            _vendor_value = value[:dash]
383            value = value[dash + 1:]
384        if len(value):
385            _os_value = value
386        self.defaults[_cpu] = ('none', 'none', _arch_value)
387        self.defaults[_arch] = ('none', 'none', _arch_value)
388        self.defaults[_vendor] = ('none', 'none', _vendor_value)
389        self.defaults[_os] = ('none', 'none', _os_value)
390
391    def _lo_help(self, opt, macro, value):
392        self.help()
393
394    def _help(self):
395        print '%s: [options] [args]' % (self.command_name)
396        print 'RTEMS Source Builder, an RTEMS Tools Project (c) 2012-2013 Chris Johns'
397        print 'Options and arguments:'
398        print '--force                : Force the build to proceed'
399        print '--quiet                : Quiet output (not used)'
400        print '--trace                : Trace the execution'
401        print '--dry-run              : Do everything but actually run the build'
402        print '--warn-all             : Generate warnings'
403        print '--no-clean             : Do not clean up the build tree'
404        print '--always-clean         : Always clean the build tree, even with an error'
405        print '--jobs                 : Run with specified number of jobs, default: num CPUs.'
406        print '--host                 : Set the host triplet'
407        print '--build                : Set the build triplet'
408        print '--target               : Set the target triplet'
409        print '--prefix path          : Tools build prefix, ie where they are installed'
410        print '--topdir path          : Top of the build tree, default is $PWD'
411        print '--configdir path       : Path to the configuration directory, default: ./config'
412        print '--builddir path        : Path to the build directory, default: ./build'
413        print '--sourcedir path       : Path to the source directory, default: ./source'
414        print '--tmppath path         : Path to the temp directory, default: ./tmp'
415        print '--log file             : Log file where all build out is written too'
416        print '--url url              : URL to look for source'
417        print '--targetcflags flags   : List of C flags for the target code'
418        print '--targetcxxflags flags : List of C++ flags for the target code'
419        print '--libstdcxxflags flags : List of C++ flags to build the target libstdc++ code'
420        print '--with-<label>         : Add the --with-<label> to the build'
421        print '--without-<label>      : Add the --without-<label> to the build'
422        if self.optargs:
423            for a in self.optargs:
424                print '%-22s : %s' % (a, self.optargs[a])
425        raise error.exit()
426
427    def _process(self):
428        arg = 0
429        while arg < len(self.args):
430            a = self.args[arg]
431            if a == '-?':
432                self._help()
433            elif a.startswith('--'):
434                los = a.split('=')
435                lo = los[0]
436                if lo in self._long_opts:
437                    long_opt = self._long_opts[lo]
438                    if len(los) == 1:
439                        if long_opt[2]:
440                            if arg == len(args) - 1:
441                                raise error.general('option requires a parameter: %s' % (lo))
442                            arg += 1
443                            value = args[arg]
444                        else:
445                            value = None
446                    else:
447                        value = '='.join(los[1:])
448                    long_opt[1](lo, long_opt[0], value)
449            else:
450                self.opts['params'].append(a)
451            arg += 1
452
453    def _post_process(self, _defaults):
454        if _defaults['_host'][2] == _defaults['nil'][2]:
455            raise error.general('host not set')
456        if '_ncpus' not in _defaults:
457            raise error.general('host number of CPUs not set')
458        ncpus = self.jobs(_defaults['_ncpus'][2])
459        if ncpus > 1:
460            _defaults['_smp_mflags'] = ('none', 'none', '-j %d' % (ncpus))
461        else:
462            _defaults['_smp_mflags'] = ('none', 'none', _defaults['nil'][2])
463        return _defaults
464
465    def define(self, _defaults, key, value = '1'):
466        _defaults[key] = ('none', 'none', value)
467
468    def undefine(self, _defaults, key):
469        if key in _defaults:
470            del _defaults[key]
471
472    def expand(self, s, _defaults):
473        """Simple basic expander of config file macros."""
474        mf = re.compile(r'%{[^}]+}')
475        expanded = True
476        while expanded:
477            expanded = False
478            for m in mf.findall(s):
479                name = m[2:-1]
480                if name in _defaults:
481                    s = s.replace(m, _defaults[name][2])
482                    expanded = True
483                else:
484                    raise error.general('cannot expand default macro: %s in "%s"' %
485                                        (m, s))
486        return s
487
488    def command(self):
489        return path.join(self.command_path, self.command_name)
490
491    def force(self):
492        return self.opts['force'] != '0'
493
494    def dry_run(self):
495        return self.opts['dry-run'] != '0'
496
497    def set_dry_run(self):
498        self.opts['dry-run'] = '1'
499
500    def quiet(self):
501        return self.opts['quiet'] != '0'
502
503    def trace(self):
504        return self.opts['trace'] != '0'
505
506    def warn_all(self):
507        return self.opts['warn-all'] != '0'
508
509    def keep_going(self):
510        return self.opts['keep-going'] != '0'
511
512    def no_clean(self):
513        return self.opts['no-clean'] != '0'
514
515    def always_clean(self):
516        return self.opts['always-clean'] != '0'
517
518    def jobs(self, cpus):
519        cpus = int(cpus)
520        if self.opts['jobs'] == 'none':
521            cpus = 0
522        elif self.opts['jobs'] == 'max':
523            pass
524        elif self.opts['jobs'] == 'half':
525            cpus = cpus / 2
526        else:
527            ok = False
528            try:
529                i = int(self.opts['jobs'])
530                cpus = i
531                ok = True
532            except:
533                pass
534            if not ok:
535                try:
536                    f = float(self.opts['jobs'])
537                    cpus = f * cpus
538                    ok = True
539                except:
540                    pass
541                if not ok:
542                    raise error.internal('bad jobs option: %s' % (self.opts['jobs']))
543        if cpus <= 0:
544            cpu = 1
545        return cpus
546
547    def params(self):
548        return self.opts['params']
549
550    def get_arg(self, arg):
551        if not arg in self.optargs:
552            raise error.internal('bad arg: %s' % (arg))
553        for a in self.args:
554            sa = a.split('=')
555            if sa[0].startswith(arg):
556                return sa
557        return None
558
559    def get_config_files(self, config):
560        #
561        # Convert to shell paths and return shell paths.
562        #
563        # @fixme should this use a passed in set of defaults and not
564        #        not the initial set of values ?
565        #
566        config = path.shell(config)
567        if '*' in config or '?' in config:
568            print config
569            configdir = path.dirname(config)
570            configbase = path.basename(config)
571            if len(configbase) == 0:
572                configbase = '*'
573            if not configbase.endswith('.cfg'):
574                configbase = configbase + '.cfg'
575            if len(configdir) == 0:
576                configdir = self.expand(self.defaults['_configdir'][2], self.defaults)
577            configs = []
578            for cp in configdir.split(':'):
579                hostconfigdir = path.host(cp)
580                for f in glob.glob(os.path.join(hostconfigdir, configbase)):
581                    configs += path.shell(f)
582        else:
583            configs = [config]
584        return configs
585
586    def config_files(self):
587        configs = []
588        for config in self.opts['params']:
589            configs.extend(self.get_config_files(config))
590        return configs
591
592    def logfiles(self):
593        if 'log' in self.opts:
594            return self.opts['log'].split(',')
595        return ['stdout']
596
597    def urls(self):
598        if self.opts['url'] is not None:
599            return self.opts['url'].split(',')
600        return None
601
602def load(args, optargs = None):
603    """
604    Copy the defaults, get the host specific values and merge them overriding
605    any matching defaults, then create an options object to handle the command
606    line merging in any command line overrides. Finally post process the
607    command line.
608    """
609    import copy
610    d = copy.deepcopy(defaults)
611    overrides = None
612    if os.name == 'nt':
613        import windows
614        overrides = windows.load()
615    elif os.name == 'posix':
616        uname = os.uname()
617        try:
618            if uname[0].startswith('CYGWIN_NT'):
619                import windows
620                overrides = windows.load()
621            elif uname[0] == 'Darwin':
622                import darwin
623                overrides = darwin.load()
624            elif uname[0] == 'FreeBSD':
625                import freebsd
626                overrides = freebsd.load()
627            elif uname[0] == 'Linux':
628                import linux
629                overrides = linux.load()
630        except:
631            pass
632    else:
633        raise error.general('unsupported host type; please add')
634    if overrides is None:
635        raise error.general('no hosts defaults found; please add')
636    for k in overrides:
637        d[k] = overrides[k]
638    o = command_line(args, optargs)
639    for k in o.defaults:
640        d[k] = o.defaults[k]
641    d = o._post_process(d)
642    repo = git.repo(o.expand('%{_sbdir}', d), o, d)
643    if repo.valid():
644        repo_valid = '1'
645        repo_head = repo.head()
646        repo_clean = repo.clean()
647        repo_id = repo_head
648        if not repo_clean:
649            repo_id += '-modified'
650    else:
651        repo_valid = '0'
652        repo_head = '%{nil}'
653        repo_clean = '%{nil}'
654        repo_id = 'no-repo'
655    o.define(d, '_sbgit_valid', repo_valid)
656    o.define(d, '_sbgit_head', repo_head)
657    o.define(d, '_sbgit_clean', str(repo_clean))
658    o.define(d, '_sbgit_id', repo_id)
659    return o, d
660
661def run(args):
662    try:
663        _opts, _defaults = load(args = args)
664        print 'Options:'
665        print _opts
666        print 'Defaults:'
667        for k in sorted(_defaults.keys()):
668            d = _defaults[k]
669            print '%-20s: %-8s %-10s' % (k, d[0], d[1]),
670            indent = False
671            if len(d[2]) == 0:
672                print
673            text_len = 80
674            for l in d[2].split('\n'):
675                while len(l):
676                    if indent:
677                        print '%20s  %8s %10s' % (' ', ' ', ' '),
678                    print l[0:text_len],
679                    l = l[text_len:]
680                    if len(l):
681                        print ' \\',
682                    print
683                    indent = True
684    except error.general, gerr:
685        print gerr
686        sys.exit(1)
687    except error.internal, ierr:
688        print ierr
689        sys.exit(1)
690    except error.exit, eerr:
691        pass
692    except KeyboardInterrupt:
693        _notice(opts, 'abort: user terminated')
694        sys.exit(1)
695    sys.exit(0)
696
697if __name__ == '__main__':
698    run(sys.argv)
Note: See TracBrowser for help on using the repository browser.