diff options
-rw-r--r-- | attoconf/_version.py | 4 | ||||
-rw-r--r-- | attoconf/classy.py | 4 | ||||
-rw-r--r-- | attoconf/core.py | 14 | ||||
-rw-r--r-- | attoconf/lib/arches.py | 23 | ||||
-rw-r--r-- | attoconf/lib/c.py | 26 | ||||
-rw-r--r-- | attoconf/lib/install.py | 124 | ||||
-rw-r--r-- | attoconf/tests/test_core.py | 25 | ||||
-rw-r--r-- | attoconf/types.py | 23 |
8 files changed, 136 insertions, 107 deletions
diff --git a/attoconf/_version.py b/attoconf/_version.py index 28024a6..18e1fb6 100644 --- a/attoconf/_version.py +++ b/attoconf/_version.py @@ -7,11 +7,11 @@ major = 0 # Incremented for releases with compatible API additions. # This is the number that is usually incremented. -minor = 8 +minor = 9 # Incremented if there is a bugfix release. # Might not be contiguous. -patch = 6 +patch = 0 # Reserved for distributors and forks. # Contains arbitrary text, but no parentheses or newlines. diff --git a/attoconf/classy.py b/attoconf/classy.py index a2891dc..a27230d 100644 --- a/attoconf/classy.py +++ b/attoconf/classy.py @@ -68,9 +68,9 @@ class ClassyProject(Project): self.add_help('General:', hidden=False) self.add_alias('--help', ['--help=default'], help='display standard help, then exit', hidden=False) - self.add_option('--help', init=None, + self.add_option('--help', init='none', type=self.do_help, check=None, - help='display some kind of help', hidden=False, + help='just display some kind of help instead of configuring', hidden=False, help_var='KIND') self.help.add_option('--help=hidden', help='display help you should never ever ever care about', diff --git a/attoconf/core.py b/attoconf/core.py index bb9d2ba..0d196e9 100644 --- a/attoconf/core.py +++ b/attoconf/core.py @@ -103,8 +103,9 @@ class Project(object): # used by some tests ... should this be fixed there instead? if help_var is None: help_var = var - if init is not None: - init = type(init) + assert init is not None + init = type(init) + assert init is not None self.options[name] = Option(init=init, type=type) if check is not None: self.order.append(var) @@ -113,10 +114,11 @@ class Project(object): if help_var is None: help_var = var + if help_def is None: help_def = init - if help_def is not None: - help = '%s [%s]' % (help, help_def) + assert help_def is not None + help = '%s [%s]' % (help, help_def) if help_var != name: help_opt = '%s=%s' % (name, help_var) @@ -127,12 +129,14 @@ class Project(object): def do_help(self, opt): ''' Pseudo type-hook to be registered for --help (calls sys.exit). ''' + if opt == 'none': + return opt if opt == 'default': hidden = False elif opt == 'hidden': hidden = True else: - raise ValueError + raise ValueError('Unknown value for opt: %r' % opt) self.help.print(sys.stdout, hidden) sys.exit() # sneaky diff --git a/attoconf/lib/arches.py b/attoconf/lib/arches.py index cffd8ca..8c70f0b 100644 --- a/attoconf/lib/arches.py +++ b/attoconf/lib/arches.py @@ -18,21 +18,19 @@ from __future__ import print_function, division, absolute_import from ..classy import ClassyProject -from ..types import triple +from ..types import triple, maybe -# TODO: see if there's a way to expose them sanely, without using Nones -# (currently I never emit them: instead I pop the order) def build(build, BUILD): pass def host(build, HOST): - if HOST is None: + if not HOST: BUILD = build.vars['BUILD'] build.vars['HOST'] = BUILD def target(build, TARGET): - if TARGET is None: + if not TARGET: HOST = build.vars['HOST'] build.vars['TARGET'] = HOST @@ -42,24 +40,21 @@ class Arches2(ClassyProject): def arches(self): super(Arches2, self).arches() self.add_help('System types:', hidden=False) - self.add_option('--build', init=None, - type=triple, check=build, + self.add_option('--build', init='', + type=maybe(triple), check=build, help='configure for building on BUILD', hidden=False, help_def='native') - self.order.pop() - self.add_option('--host', init=None, - type=triple, check=host, + self.add_option('--host', init='', + type=maybe(triple), check=host, help='cross-compile to build programs to run on HOST', hidden=False, help_def='BUILD') - self.order.pop() # TODO figure out the mro implications when I use this class Arches3(Arches2): __slots__ = () def arches(self): super(Arches3, self).arches() - self.add_option('--target', init=None, - type=triple, check=target, + self.add_option('--target', init='', + type=maybe(triple), check=target, help='configure for building compilers for TARGET', hidden=False, help_def='HOST') - self.order.pop() diff --git a/attoconf/lib/c.py b/attoconf/lib/c.py index 3b6f05f..bc32c49 100644 --- a/attoconf/lib/c.py +++ b/attoconf/lib/c.py @@ -208,7 +208,12 @@ def cppflags(build, CPPFLAGS): pass def cc(build, CC): - pass + if CC.list == []: + HOST = build.vars['HOST'] + if HOST: + build.vars['CC'].list = [HOST + '-gcc'] + else: + build.vars['CC'].list = ['gcc'] def cflags(build, CFLAGS): try_compile_c(build, 'int main() {}\n') @@ -216,7 +221,12 @@ def cflags(build, CFLAGS): try_compile_link2_c(build, 'int main() {}\n') def cxx(build, CXX): - pass + if CXX.list == []: + HOST = build.vars['HOST'] + if HOST: + build.vars['CXX'].list = [HOST + '-g++'] + else: + build.vars['CXX'].list = ['g++'] def cxxflags(build, CXXFLAGS): try_compile_cxx(build, 'int main() {}\n') @@ -235,7 +245,7 @@ class Link(Arches2): type=ShellList, check=libs, help='libraries to pass to the linker, e.g. -l<library>', hidden=False) - self.order.append('LDLIBS') + self.order.append('LDLIBS') #TODO remove for 1.0 class Preprocess(Arches2): __slots__ = () @@ -250,9 +260,10 @@ class C(Link, Preprocess): __slots__ = () def vars(self): super(C, self).vars() - self.add_option('CC', init=['gcc'], + self.add_option('CC', init=[], type=ShellList, check=cc, - help='C compiler command', hidden=False) + help='C compiler command', hidden=False, + help_def='HOST-gcc') self.add_option('CFLAGS', init=['-O2', '-g'], type=ShellList, check=cflags, help='C compiler flags', hidden=False) @@ -261,9 +272,10 @@ class Cxx(Link, Preprocess): __slots__ = () def vars(self): super(Cxx, self).vars() - self.add_option('CXX', init=['g++'], + self.add_option('CXX', init=[], type=ShellList, check=cxx, - help='C++ compiler command', hidden=False) + help='C++ compiler command', hidden=False, + help_def='HOST-g++') self.add_option('CXXFLAGS', init=['-O2', '-g'], type=ShellList, check=cxxflags, help='C++ compiler flags', hidden=False) diff --git a/attoconf/lib/install.py b/attoconf/lib/install.py index 1a55c29..f43b2a1 100644 --- a/attoconf/lib/install.py +++ b/attoconf/lib/install.py @@ -20,7 +20,7 @@ from __future__ import print_function, division, absolute_import import os from ..classy import ClassyProject -from ..types import shell_word, filepath, quoted_string +from ..types import shell_word, filepath, quoted_string, maybe def package(build, PACKAGE): @@ -33,48 +33,48 @@ def prefix(build, PREFIX): pass def exec_prefix(build, EPREFIX): - if EPREFIX is None: + if not EPREFIX: PREFIX = build.vars['PREFIX'] build.vars['EXEC_PREFIX'] = PREFIX build.vars['EPREFIX'] = build.vars['EXEC_PREFIX'] def bindir(build, DIR): - if DIR is None: + if not DIR: EPREFIX = build.vars['EPREFIX'] build.vars['BINDIR'] = os.path.join(EPREFIX, 'bin') def sbindir(build, DIR): - if DIR is None: + if not DIR: EPREFIX = build.vars['EPREFIX'] build.vars['SBINDIR'] = os.path.join(EPREFIX, 'sbin') def libexecdir(build, DIR): - if DIR is None: + if not DIR: EPREFIX = build.vars['EPREFIX'] build.vars['LIBEXECDIR'] = os.path.join(EPREFIX, 'libexec') def sysconfdir(build, DIR): - if DIR is None: + if not DIR: PREFIX = build.vars['PREFIX'] build.vars['SYSCONFDIR'] = os.path.join(PREFIX, 'etc') def sharedstatedir(build, DIR): - if DIR is None: + if not DIR: PREFIX = build.vars['PREFIX'] build.vars['SHAREDSTATEDIR'] = os.path.join(PREFIX, 'com') def localstatedir(build, DIR): - if DIR is None: + if not DIR: PREFIX = build.vars['PREFIX'] build.vars['LOCALSTATEDIR'] = os.path.join(PREFIX, 'var') def libdir(build, DIR): - if DIR is None: + if not DIR: EPREFIX = build.vars['EPREFIX'] build.vars['LIBDIR'] = os.path.join(EPREFIX, 'lib') def includedir(build, DIR): - if DIR is None: + if not DIR: PREFIX = build.vars['PREFIX'] build.vars['INCLUDEDIR'] = os.path.join(PREFIX, 'include') @@ -82,59 +82,59 @@ def oldincludedir(build, DIR): pass def datarootdir(build, DIR): - if DIR is None: + if not DIR: PREFIX = build.vars['PREFIX'] build.vars['DATAROOTDIR'] = os.path.join(PREFIX, 'share') def datadir(build, DIR): - if DIR is None: + if not DIR: DATAROOTDIR = build.vars['DATAROOTDIR'] build.vars['DATADIR'] = DATAROOTDIR def packagedatadir(build, DIR): - if DIR is None: + if not DIR: DATADIR = build.vars['DATADIR'] PACKAGE = build.vars['PACKAGE'] build.vars['PACKAGEDATADIR'] = os.path.join(DATADIR, PACKAGE) def infodir(build, DIR): - if DIR is None: + if not DIR: DATAROOTDIR = build.vars['DATAROOTDIR'] build.vars['INFODIR'] = os.path.join(DATAROOTDIR, 'info') def localedir(build, DIR): - if DIR is None: + if not DIR: DATAROOTDIR = build.vars['DATAROOTDIR'] build.vars['LOCALEDIR'] = os.path.join(DATAROOTDIR, 'locale') def mandir(build, DIR): - if DIR is None: + if not DIR: DATAROOTDIR = build.vars['DATAROOTDIR'] build.vars['MANDIR'] = os.path.join(DATAROOTDIR, 'man') def docdir(build, DIR): - if DIR is None: + if not DIR: DATAROOTDIR = build.vars['DATAROOTDIR'] PACKAGE = build.vars['PACKAGE'] build.vars['DOCDIR'] = os.path.join(DATAROOTDIR, 'doc', PACKAGE) def htmldir(build, DIR): - if DIR is None: + if not DIR: DOCDIR = build.vars['DOCDIR'] build.vars['HTMLDIR'] = DOCDIR def dvidir(build, DIR): - if DIR is None: + if not DIR: DOCDIR = build.vars['DOCDIR'] build.vars['DVIDIR'] = DOCDIR def pdfdir(build, DIR): - if DIR is None: + if not DIR: DOCDIR = build.vars['DOCDIR'] build.vars['PDFDIR'] = DOCDIR def psdir(build, DIR): - if DIR is None: + if not DIR: DOCDIR = build.vars['DOCDIR'] build.vars['PSDIR'] = DOCDIR @@ -179,93 +179,93 @@ class Install(ClassyProject): type=filepath, check=prefix, help='install architecture-independent files in PREFIX', hidden=False) - self.add_option('--exec-prefix', init=None, - type=filepath, check=exec_prefix, + self.add_option('--exec-prefix', init='', + type=maybe(filepath), check=exec_prefix, help='install architecture-dependent files in EPREFIX', hidden=False, help_var='EPREFIX', help_def='PREFIX') - self.order.append('EPREFIX') + self.order.append('EPREFIX') # TODO remove for 1.0 self.order.append(None) self.add_help('Fine tuning of the installation directories:', hidden=False) - self.add_option('--bindir', init=None, - type=filepath, check=bindir, + self.add_option('--bindir', init='', + type=maybe(filepath), check=bindir, help='user executables', hidden=False, help_var='DIR', help_def='EPREFIX/bin') - self.add_option('--sbindir', init=None, - type=filepath, check=sbindir, + self.add_option('--sbindir', init='', + type=maybe(filepath), check=sbindir, help='system admin executables', hidden=False, help_var='DIR', help_def='EPREFIX/sbin') - self.add_option('--libexecdir', init=None, - type=filepath, check=libexecdir, + self.add_option('--libexecdir', init='', + type=maybe(filepath), check=libexecdir, help='program executables', hidden=False, help_var='DIR', help_def='EPREFIX/libexec') - self.add_option('--sysconfdir', init=None, - type=filepath, check=sysconfdir, + self.add_option('--sysconfdir', init='', + type=maybe(filepath), check=sysconfdir, help='read-only single-machine data', hidden=False, help_var='DIR', help_def='PREFIX/etc') - self.add_option('--sharedstatedir', init=None, - type=filepath, check=sharedstatedir, + self.add_option('--sharedstatedir', init='', + type=maybe(filepath), check=sharedstatedir, help='modifiable architecture-independent data', hidden=False, help_var='DIR', help_def='PREFIX/com') - self.add_option('--localstatedir', init=None, - type=filepath, check=localstatedir, + self.add_option('--localstatedir', init='', + type=maybe(filepath), check=localstatedir, help='modifiable single-machine data', hidden=False, help_var='DIR', help_def='PREFIX/var') - self.add_option('--libdir', init=None, - type=filepath, check=libdir, + self.add_option('--libdir', init='', + type=maybe(filepath), check=libdir, help='object code libraries', hidden=False, help_var='DIR', help_def='EPREFIX/lib') - self.add_option('--includedir', init=None, - type=filepath, check=includedir, + self.add_option('--includedir', init='', + type=maybe(filepath), check=includedir, help='C header files', hidden=False, help_var='DIR', help_def='PREFIX/include') self.add_option('--oldincludedir', init='/usr/include', type=filepath, check=oldincludedir, help='C header files for non-gcc', hidden=False, help_var='DIR') - self.add_option('--datarootdir', init=None, - type=filepath, check=datarootdir, + self.add_option('--datarootdir', init='', + type=maybe(filepath), check=datarootdir, help='read-only arch.-independent data root', hidden=False, help_var='DIR', help_def='PREFIX/share') - self.add_option('--datadir', init=None, - type=filepath, check=datadir, + self.add_option('--datadir', init='', + type=maybe(filepath), check=datadir, help='read-only architecture-independent data', hidden=False, help_var='DIR', help_def='DATAROOTDIR') - self.add_option('--packagedatadir', init=None, - type=filepath, check=packagedatadir, + self.add_option('--packagedatadir', init='', + type=maybe(filepath), check=packagedatadir, help='data specific to this package (please set datadir instead)', hidden=False, help_var='DIR', help_def='DATADIR/PACKAGE') - self.add_option('--infodir', init=None, - type=filepath, check=infodir, + self.add_option('--infodir', init='', + type=maybe(filepath), check=infodir, help='info documentation', hidden=False, help_var='DIR', help_def='DATAROOTDIR/info') - self.add_option('--localedir', init=None, - type=filepath, check=localedir, + self.add_option('--localedir', init='', + type=maybe(filepath), check=localedir, help='locale-dependent data', hidden=False, help_var='DIR', help_def='DATAROOTDIR/locale') - self.add_option('--mandir', init=None, - type=filepath, check=mandir, + self.add_option('--mandir', init='', + type=maybe(filepath), check=mandir, help='man documentation', hidden=False, help_var='DIR', help_def='DATAROOTDIR/man') - self.add_option('--docdir', init=None, - type=filepath, check=docdir, + self.add_option('--docdir', init='', + type=maybe(filepath), check=docdir, help='documentation root', hidden=False, help_var='DIR', help_def='DATAROOTDIR/doc/PACKAGE') - self.add_option('--htmldir', init=None, - type=filepath, check=htmldir, + self.add_option('--htmldir', init='', + type=maybe(filepath), check=htmldir, help='html documentation', hidden=False, help_var='DIR', help_def='DOCDIR') - self.add_option('--dvidir', init=None, - type=filepath, check=dvidir, + self.add_option('--dvidir', init='', + type=maybe(filepath), check=dvidir, help='dvi documentation', hidden=False, help_var='DIR', help_def='DOCDIR') - self.add_option('--pdfdir', init=None, - type=filepath, check=pdfdir, + self.add_option('--pdfdir', init='', + type=maybe(filepath), check=pdfdir, help='pdf documentation', hidden=False, help_var='DIR', help_def='DOCDIR') - self.add_option('--psdir', init=None, - type=filepath, check=psdir, + self.add_option('--psdir', init='', + type=maybe(filepath), check=psdir, help='ps documentation', hidden=False, help_var='DIR', help_def='DOCDIR') diff --git a/attoconf/tests/test_core.py b/attoconf/tests/test_core.py index f60aab6..09c2c64 100644 --- a/attoconf/tests/test_core.py +++ b/attoconf/tests/test_core.py @@ -20,7 +20,7 @@ from __future__ import print_function, division, absolute_import import unittest from attoconf.core import Project, Build -from attoconf.types import uint, shell_word, shell_partial_word +from attoconf.types import uint, shell_word, shell_partial_word, maybe import os from cStringIO import StringIO @@ -44,7 +44,7 @@ class TestProject(unittest.TestCase): proj.add_help('General:', False) proj.add_alias('--help', ['--help=default'], help='display standard help, then exit', hidden=False) - proj.add_option('--help', init=None, + proj.add_option('--help', init='none', type=proj.do_help, check=None, help='display some subset of help', hidden=False, help_var='TYPE') @@ -54,8 +54,8 @@ class TestProject(unittest.TestCase): proj.add_option('--foo', init='asdf', type=shell_word, check=None, help='set frob target', hidden=False) - proj.add_option('--bar', init=None, - type=shell_word, check=None, + proj.add_option('--bar', init='', + type=maybe(shell_word), check=None, help='set frob source', hidden=False, help_def='FOO') @@ -68,7 +68,7 @@ class TestProject(unittest.TestCase): self.assertEqual(out.getvalue(), ''' General: --help display standard help, then exit - --help=TYPE display some subset of help + --help=TYPE display some subset of help [none] --foo=FOO set frob target [asdf] --bar=BAR set frob source [FOO] @@ -81,7 +81,7 @@ General: self.assertEqual(out.getvalue(), ''' General: --help display standard help, then exit - --help=TYPE display some subset of help + --help=TYPE display some subset of help [none] --help=hidden display help you should never ever ever care about --foo=FOO set frob target [asdf] --bar=BAR set frob source [FOO] @@ -101,22 +101,23 @@ General: def check_bar(bld, BAR): self.assertEqual(BAR, 1) def check_qux(bld, QUX): - self.assertEqual(QUX, None) + self.assertEqual(QUX, '') def check_var(bld, VAR): self.assertEqual(VAR, 'value') proj = Project('.') proj.add_alias('--alias', ['--foo=A', '--bar=1', '--foo=B'], help=None, hidden=False) - proj.add_option('--foo', init=None, + proj.add_option('--foo', init='X', type=shell_word, check=check_foo, help='help for string foo', hidden=False) proj.add_option('--bar', init=0, type=uint, check=check_bar, help='help for int bar', hidden=False) - proj.add_option('--qux', init=None, - type=uint, check=check_qux, - help='help for int qux', hidden=False) + proj.add_option('--qux', init='', + type=maybe(uint), check=check_qux, + help='help for int qux', hidden=False, + help_def='auto') proj.add_option('VAR', init='', type=shell_partial_word, check=check_var, help='help for string VAR', hidden=False) @@ -133,6 +134,6 @@ General: { 'FOO': 'B', 'BAR': 1, - 'QUX': None, + 'QUX': '', 'VAR': 'value', }) diff --git a/attoconf/types.py b/attoconf/types.py index 3e73d86..e7c8465 100644 --- a/attoconf/types.py +++ b/attoconf/types.py @@ -51,6 +51,18 @@ class enum(object): raise ValueError('%r not in {%s}' % (s, ', '.join(self.args))) +class maybe(object): + __slots__ = ('inferior') + + def __init__(self, inferior): + self.inferior = inferior + + def __call__(self, s): + if not s: + return s + return (self.inferior)(s) + + class ShellList(object): ''' An argument type representing a sequence of 0 or more arguments ''' @@ -96,9 +108,14 @@ def quoted_string(s): def filepath(s): s = trim_trailing_slashes(s) - # must be absolute *and* canonical - if s != os.path.abspath(s): - raise ValueError('Not an absolute, canonical pathname: %s' % s) + # must be absolute *and* canonical, except joinable + a = os.path.abspath(s) + if a == '/': + # filepaths often directly cat a subpath + # @me@/whatever is invalid if @me@ == / + a = '/.' + if s != a: + raise ValueError('Not an absolute, canonical (except joinable) pathname: %r != %r' % (s, a)) return s |