source: rtems-source-builder/source-builder/sb/defaults.py @ 972ad8c

4.104.114.95
Last change on this file since 972ad8c was 972ad8c, checked in by Chris Johns <chrisj@…>, on 02/19/13 at 08:02:51

Make force on the default. Option is now --no-force.

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