diff options
author | kennyballou <kballou@onyx.boisestate.edu> | 2013-03-10 20:57:57 -0600 |
---|---|---|
committer | kennyballou <kballou@onyx.boisestate.edu> | 2013-03-10 20:57:57 -0600 |
commit | 5a4074d3a042ddd67658a2ecc8c8fdc3745a4676 (patch) | |
tree | 2f9f8029bd63b14fbdc6d9d13b1039ec54f9f8fb | |
parent | 69874f19c238d4ded308430902238f4e692cb335 (diff) | |
parent | ba393af1d25e4a83ea02e11885f7d4c9d1fdf07f (diff) | |
download | xnt-5a4074d3a042ddd67658a2ecc8c8fdc3745a4676.tar.gz xnt-5a4074d3a042ddd67658a2ecc8c8fdc3745a4676.tar.xz |
Merge branch 'master' into refactor-logging-levels
Conflicts:
xnt/version.py
-rw-r--r-- | README.rst | 14 | ||||
-rw-r--r-- | docs/source/buildfile.rst | 6 | ||||
-rw-r--r-- | docs/source/taskreference.rst | 5 | ||||
-rw-r--r-- | docs/source/xenant.rst | 23 | ||||
-rw-r--r-- | pylint.conf | 2 | ||||
-rw-r--r-- | xnt/basecommand.py | 32 | ||||
-rw-r--r-- | xnt/cmdoptions.py | 31 | ||||
-rw-r--r-- | xnt/commands/__init__.py | 41 | ||||
-rw-r--r-- | xnt/commands/help.py | 42 | ||||
-rw-r--r-- | xnt/commands/listtargets.py | 56 | ||||
-rw-r--r-- | xnt/commands/target.py | 78 | ||||
-rw-r--r-- | xnt/commands/version.py | 34 | ||||
-rw-r--r-- | xnt/tasks.py | 10 | ||||
-rw-r--r-- | xnt/tests/xenantargparsertests.py | 158 | ||||
-rw-r--r-- | xnt/version.py | 2 | ||||
-rw-r--r-- | xnt/xenant.py | 149 |
16 files changed, 309 insertions, 374 deletions
@@ -224,7 +224,10 @@ Command Usage: Where ``[options]`` are one of the following: -* ``-v``: verbose, turn on logging +* ``-v`` or ``--verbose``: verbose, turn on logging + +* ``-b BUILDFILE`` or ``--build-file BUILDFILE``: Specify build file + for Xnt to load And where ``[target]+`` are any target(s) method in your ``build.py`` file or: @@ -235,13 +238,14 @@ file or: Other Commands -------------- -* ``list-targets``: Xnt will print all targets marked by the - ``@target`` decorator and possibly their docstrings if they are +* ``-l`` or ``--list-targets``: Xnt will print all targets marked by + the ``@target`` decorator and possibly their docstrings if they are defined -* ``version``: Print the current version of Xnt and quit +* ``--version``: Print the current version of Xnt and quit -* ``help``: Print summary information about Xnt and command usage +* ``-h`` or ``--help``: Print summary information about Xnt and + command usage For more information about Xnt and the build in functions, see the `Package Documentation`_. diff --git a/docs/source/buildfile.rst b/docs/source/buildfile.rst index cec8e30..8200fff 100644 --- a/docs/source/buildfile.rst +++ b/docs/source/buildfile.rst @@ -134,16 +134,16 @@ Build Properties As mentioned in :ref:`xntPropertiesParameters`, Xnt can accept parameters from the command line and pass them into the build file. Xnt doesn't necessarily -expect the dictionary (named `properties`) to exist; but if you ever intend to +expect the dictionary (named `PROPERTIES`) to exist; but if you ever intend to use it, it will have to be defined one way or another (either to an empty dictionary or actually hold values). For example, to define an empty -`properties` dictionary, one could write their build file as such:: +`PROPERTIES` dictionary, one could write their build file as such:: #!/usr/bin/env python from xnt import target - properties = {} + PROPERTIES = {} @target def foo(): diff --git a/docs/source/taskreference.rst b/docs/source/taskreference.rst index a65f00e..3a36d21 100644 --- a/docs/source/taskreference.rst +++ b/docs/source/taskreference.rst @@ -89,15 +89,14 @@ Miscellaneous Tasks change; I'm not sure how I feel about that yet.] .. _xnt.tasks.xntcall: -.. function:: xntcall(path, targets=None, props=None) +.. function:: xntcall(buildfile, targets=None, props=None) Invoke the *target(s)* of a build file in a different *path*. *target* is the name of the target to invoke (similar to *target* of a regular invocation. - *path* is the relative or full path to where the "sub" *build.py* file can - be found. + *buildfile* is the path (relative or full) and build file to use Compile Tasks ============= diff --git a/docs/source/xenant.rst b/docs/source/xenant.rst index e9456fa..f5907bb 100644 --- a/docs/source/xenant.rst +++ b/docs/source/xenant.rst @@ -47,27 +47,27 @@ Xnt has a number of other commands that can be invoked besides those defined in the current directory's `build.py` file. One will need a build file to run. The others, however, do not. -* ``help`` prints a summary message, including information about the version of - Xnt, license, and usage. +* ``-h`` or ``--help`` prints a summary message, including information about + the version of Xnt, license, and usage. Usage:: - $ xnt help + $ xnt --help -* ``list-targets`` does exactly what the name should suggest: it prints a list - of the targets found in the current directory's `build.py` script, along with - any docstrings that may be defined with them. +* ``-l`` or ``--list-targets`` does exactly what the name should suggest: it + prints a list of the targets found in the current directory's `build.py` + script, along with any docstrings that may be defined with them. Usage:: - $ xnt list-targets + $ xnt --list-targets -* ``version`` prints Xnt's installed version. +* ``--version`` prints Xnt's installed version. Usage:: - $ xnt version + $ xnt --version .. _xntOptions: @@ -82,7 +82,10 @@ Usage:: Where options can be any and all of the following (unless otherwise specified): -* ``-v``: add verbose output to the execution of Xnt +* ``-v`` or ``--verbose``: add verbose output to the execution of Xnt + +* ``-b BUILDFILE`` or ``--build-file BUILDFILE``: specifiy to Xnt the build + module to load .. _xntPropertiesParameters: diff --git a/pylint.conf b/pylint.conf index 5282466..aa74eda 100644 --- a/pylint.conf +++ b/pylint.conf @@ -249,7 +249,7 @@ max-attributes=7 min-public-methods=1 # Maximum number of public methods for a class (see R0904). -max-public-methods=50 +max-public-methods=60 [EXCEPTIONS] diff --git a/xnt/basecommand.py b/xnt/basecommand.py deleted file mode 100644 index 6433918..0000000 --- a/xnt/basecommand.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python -"""Basecommand class for xnt commands""" - -# Xnt -- A Wrapper Build Tool -# Copyright (C) 2012 Kenny Ballou - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -class Command(object): - """Base Command Class Definition""" - name = None - usage = None - hidden = False - need_build = False - - def __init__(self): - pass - - def run(self, arguments=None): - """Invoke the Command""" - pass diff --git a/xnt/cmdoptions.py b/xnt/cmdoptions.py deleted file mode 100644 index 529f060..0000000 --- a/xnt/cmdoptions.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -"""Xenant Options Defintion - -All available options for Xenant (and there actions) -""" - -# Xnt -- A Wrapper Build Tool -# Copyright (C) 2012 Kenny Ballou - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import logging - -def __flip_verbose_flag(): - """Turn on logging for xnt (and submodules)""" - logging.getLogger("xnt").setLevel(logging.INFO) - -OPTIONS = { - "-v": __flip_verbose_flag, -} diff --git a/xnt/commands/__init__.py b/xnt/commands/__init__.py deleted file mode 100644 index 583558b..0000000 --- a/xnt/commands/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python -"""Commands Module""" - -# Xnt -- A Wrapper Build Tool -# Copyright (C) 2012 Kenny Ballou - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from xnt.commands.help import HelpCommand -from xnt.commands.listtargets import ListTargetsCommand -from xnt.commands.version import VersionCommand -from xnt.commands.target import TargetCommand - -COMMANDS = { - HelpCommand.name: HelpCommand, - ListTargetsCommand.name: ListTargetsCommand, - VersionCommand.name: VersionCommand, - TargetCommand.name: TargetCommand, -} - -def get_summaries(ignore_hidden=True): - """Return a list of summaries about each command""" - items = [] - - for name, command_class in COMMANDS.items(): - if ignore_hidden and command_class.hidden: - continue - items.append((name, command_class.summary)) - - return sorted(items) diff --git a/xnt/commands/help.py b/xnt/commands/help.py deleted file mode 100644 index 79584be..0000000 --- a/xnt/commands/help.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -"""Xnt Help Command""" - -# Xnt -- A Wrapper Build Tool -# Copyright (C) 2012 Kenny Ballou - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from xnt.basecommand import Command -from xnt.status_codes import SUCCESS - -class HelpCommand(Command): - """Help Command""" - name = 'help' - usage = """""" - summary = 'Print Usage Summary' - needs_build = False - - def run(self, arguments=None): - """Invoke Help""" - from xnt.commands import get_summaries - from xnt import __version__, __license__ - commands = get_summaries() - print(__version__) - print(__license__) - print("Available Commands:") - for name, summary in commands: - print(name) - print("\t" + summary) - - return SUCCESS diff --git a/xnt/commands/listtargets.py b/xnt/commands/listtargets.py deleted file mode 100644 index 2885905..0000000 --- a/xnt/commands/listtargets.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -"""List Targets Xnt Command""" - -# Xnt -- A Wrapper Build Tool -# Copyright (C) 2012 Kenny Ballou - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from xnt.basecommand import Command -from xnt.status_codes import SUCCESS, ERROR -import logging - -LOGGER = logging.getLogger(__name__) - -class ListTargetsCommand(Command): - """List Targets Command""" - name = 'list-targets' - usage = """""" - summary = "Prints targets in build file" - needs_build = True - - def __init__(self, build): - """Initialization""" - Command.__init__(self) - self.build = build - - def run(self, arguments=None): - """Invoke ListTargets""" - LOGGER.debug("build is null? %s", self.build == None) - try: - for attr in dir(self.build): - LOGGER.debug("Attribute %s:", attr) - try: - func = getattr(self.build, attr) - if func.decorator == "target": - print(attr + ":") - if func.__doc__: - print(func.__doc__) - print("\n") - except AttributeError: - pass - except AttributeError as ex: - LOGGER.error(ex) - return ERROR - return SUCCESS diff --git a/xnt/commands/target.py b/xnt/commands/target.py deleted file mode 100644 index 0520c74..0000000 --- a/xnt/commands/target.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python -"""(Generic) Target Xnt Command for invoking build targets""" - -# Xnt -- A Wrapper Build Tool -# Copyright (C) 2012 Kenny Ballou - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from xnt.basecommand import Command -from xnt.status_codes import SUCCESS, ERROR, UNKNOWN_ERROR -import logging - -LOGGER = logging.getLogger("xnt") - -class TargetCommand(Command): - """Target Command""" - name = '<target>' - usage = """""" - summary = "Invokes target(s) in build.py" - needs_build = True - - def __init__(self, build): - """Initialization""" - Command.__init__(self) - self.build = build - - def run(self, targets=None, props=None): #pylint: disable-msg=W0221 - """Invoke Target Command""" - if targets: - for target in targets: - error_code = self.call_target(target, props) - if error_code: - return error_code - return SUCCESS - else: - return self.call_target("default", props) - - def call_target(self, target_name, props): - """Invoke build target""" - def process_params(params, buildproperties=None): - """Parse the passed properties and append to build properties""" - properties = buildproperties if buildproperties is not None else {} - for param in params: - name, value = param[2:].split("=") - properties[name] = value - return properties - def __get_properties(): - """Return the properties dictionary of the build module""" - try: - return getattr(self.build, "properties") - except AttributeError: - return None - try: - if props and len(props) > 0: - setattr(self.build, - "properties", - process_params(props, __get_properties())) - target = getattr(self.build, target_name) - error_code = target() - return error_code if error_code else 0 - except AttributeError: - LOGGER.warning("There was no target: %s", target_name) - return ERROR - except Exception as ex: - LOGGER.error(ex) - return UNKNOWN_ERROR - diff --git a/xnt/commands/version.py b/xnt/commands/version.py deleted file mode 100644 index 9c2e302..0000000 --- a/xnt/commands/version.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -"""Version Xnt Command""" - -# Xnt -- A Wrapper Build Tool -# Copyright (C) 2012 Kenny Ballou - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from xnt.basecommand import Command -from xnt.status_codes import SUCCESS - -class VersionCommand(Command): - """Version Command""" - name = 'version' - usage = """""" - summary = "Print Version of Xnt" - needs_build = False - - def run(self, arguments=None): - """Invoke Version""" - from xnt import __version__ - print(__version__) - return SUCCESS diff --git a/xnt/tasks.py b/xnt/tasks.py index 5140618..1981e9b 100644 --- a/xnt/tasks.py +++ b/xnt/tasks.py @@ -121,19 +121,19 @@ def log(msg="", lvl=logging.INFO): """Log message using tasks global logger""" LOGGER.log(lvl, msg) -def xntcall(path, targets=None, props=None): +def xntcall(buildfile, targets=None, props=None): """Invoke xnt on another build file in a different directory param: path - to the build file (including build file) param: targets - list of targets to execute param: props - dictionary of properties to pass to the build module """ - import xnt.xenant - from xnt.commands.target import TargetCommand + from xnt.xenant import invoke_build, load_build + build = load_build(buildfile) + path = os.path.dirname(buildfile) cwd = os.getcwd() - command = TargetCommand(xnt.xenant.load_build(path)) os.chdir(path) - error_code = command.run(targets=targets, props=props) + error_code = invoke_build(build, targets=targets, props=props) os.chdir(cwd) return error_code diff --git a/xnt/tests/xenantargparsertests.py b/xnt/tests/xenantargparsertests.py new file mode 100644 index 0000000..04c8d1c --- /dev/null +++ b/xnt/tests/xenantargparsertests.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +"""Xenant Arg Parser Tests""" + +# Xnt -- A Wrapper Build Tool +# Copyright (C) 2012 Kenny Ballou + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import xnt.xenant +import unittest + +#pylint: disable-msg=C0103 +class XenantArgParserTests(unittest.TestCase): + """Test Cases for Xenant Args Parsing""" + + def test_nil_args(self): + """Test the empty case (no arguements)""" + args_in = [] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertFalse(args["verbose"]) + self.assertFalse(args["list-targets"]) + self.assertIsNone(args["properties"]) + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 0) + + def test_single_target(self): + """Test the single target case""" + args_in = ["my_target"] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertFalse(args["verbose"]) + self.assertFalse(args["list-targets"]) + self.assertIsNone(args["properties"]) + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 1) + + def test_verbose(self): + """Test verbose flag""" + args_in = ["-v"] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertTrue(args["verbose"]) + self.assertFalse(args["list-targets"]) + self.assertIsNone(args["properties"]) + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 0) + + def test_list_targets_short(self): + """Test list targets flag, short hand""" + args_in = ["-l"] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertFalse(args["verbose"]) + self.assertTrue(args["list-targets"]) + self.assertIsNone(args["properties"]) + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 0) + + def test_list_targets_long(self): + """Test list targets flag, long hand""" + args_in = ["--list-targets"] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertFalse(args["verbose"]) + self.assertTrue(args["list-targets"]) + self.assertIsNone(args["properties"]) + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 0) + + def test_single_verbose(self): + """Test the verbose single case""" + args_in = ["-v", "my_verbose_target"] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertTrue(args["verbose"]) + self.assertFalse(args["list-targets"]) + self.assertIsNone(args["properties"]) + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 1) + + def test_multi_target(self): + """Test the verbose single case""" + args_in = ["my_first_target", "my_second_target"] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertFalse(args["verbose"]) + self.assertFalse(args["list-targets"]) + self.assertIsNone(args["properties"]) + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 2) + + def test_properties_no_target(self): + """Test property parsing""" + args_in = ["-Dmyvar=myvalue"] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertFalse(args["verbose"]) + self.assertFalse(args["list-targets"]) + self.assertIsNotNone(args["properties"]) + self.assertEqual(len(args["properties"]), 1) + self.assertEqual(args["properties"][0], "myvar=myvalue") + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 0) + + def test_more_properties(self): + """Test property parsing""" + args_in = ["-Dmyvar=myvalue", "-Dmyothervar=myothervalue"] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertFalse(args["verbose"]) + self.assertFalse(args["list-targets"]) + self.assertIsNotNone(args["properties"]) + self.assertEqual(len(args["properties"]), 2) + self.assertEqual(args["properties"][0], "myvar=myvalue") + self.assertEqual(args["properties"][1], "myothervar=myothervalue") + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 0) + + def test_build_file_spec_short(self): + """Test build file option""" + args_in = ["-b", "mybuildfile.py"] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertFalse(args["verbose"]) + self.assertFalse(args["list-targets"]) + self.assertIsNotNone(args["build-file"]) + self.assertEqual(args["build-file"], "mybuildfile.py") + self.assertIsNone(args["properties"]) + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 0) + + def test_build_file_spec_long(self): + """Test build file option""" + args_in = ["--build-file", "mybuildfile.py"] + args = xnt.xenant.parse_args(args_in) + self.assertIsNotNone(args) + self.assertFalse(args["verbose"]) + self.assertFalse(args["list-targets"]) + self.assertIsNotNone(args["build-file"]) + self.assertEqual(args["build-file"], "mybuildfile.py") + self.assertIsNone(args["properties"]) + self.assertIsNotNone(args["targets"]) + self.assertEqual(len(args["targets"]), 0) + +if __name__ == "__main__": + unittest.main() diff --git a/xnt/version.py b/xnt/version.py index 7db0124..77cf994 100644 --- a/xnt/version.py +++ b/xnt/version.py @@ -17,5 +17,5 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -__version_info__ = (0, 5, 2, "logging_refactor", "dev") +__version_info__ = (0, 5, 3) __version__ = '.'.join(list(str(i) for i in __version_info__ if True)) diff --git a/xnt/xenant.py b/xnt/xenant.py index 10be9b9..f11f281 100644 --- a/xnt/xenant.py +++ b/xnt/xenant.py @@ -21,9 +21,9 @@ import os import sys import time import logging -from xnt.cmdoptions import OPTIONS -from xnt.commands import COMMANDS -from xnt.commands.target import TargetCommand +import argparse +from xnt import __version__ +from xnt.status_codes import SUCCESS, ERROR, UNKNOWN_ERROR logging.basicConfig(format="%(message)s") LOGGER = logging.Logger(name=__name__) @@ -33,45 +33,38 @@ LOGGER.setLevel(logging.WARNING) def main(): """Xnt Entry Point""" start_time = time.time() - params = list(p for p in sys.argv[1:] if p.startswith('-D')) - flags = list(o for o in sys.argv[1:] - if o.startswith('-') and o not in params) - cmds = list(c for c in sys.argv[1:] - if c not in flags and c not in params) - #Loop flags and apply them - for flag in flags: - if flag in OPTIONS: - OPTIONS[flag]() - else: - LOGGER.debug("%s is not a vaild option", flag) - #run things - cmd_found = False - for cmd in cmds: - if cmd in COMMANDS: - cmd_found = True - if COMMANDS[cmd].needs_build: - command = COMMANDS[cmd](load_build()) - else: - command = COMMANDS[cmd]() - error_code = command.run() - if cmd_found == False: - command = TargetCommand(load_build()) - error_code = command.run(targets=cmds, props=params) + args = parse_args(sys.argv[1:]) + build_file = "./build.py" + if args["verbose"]: + LOGGER.setLevel(logging.DEBUG) + if args["build-file"]: + build_file = args["build-file"] + if args["list-targets"]: + error_code = list_targets(load_build(build_file)) + else: + error_code = invoke_build(load_build(build_file), + args["targets"], + args["properties"]) elapsed_time = time.time() - start_time print("Execution time: %.3f", elapsed_time) if error_code != 0: LOGGER.error("Failure") from xnt.tasks import rm rm("build.pyc", - "__pycache__") + "__pycache__", + build_file + "c", + os.path.join(os.path.dirname(build_file), "__pycache__")) if error_code != 0: sys.exit(error_code) -def load_build(path=""): +def load_build(buildfile="./build.py"): """Load build file Load the build.py and return the resulting import """ + path = os.path.dirname(buildfile) + build = os.path.basename(buildfile) + buildmodule = os.path.splitext(build)[0] if not path: path = os.getcwd() else: @@ -79,18 +72,110 @@ def load_build(path=""): sys.path.append(path) cwd = os.getcwd() os.chdir(path) - if not os.path.exists("build.py"): + if not os.path.exists(build): LOGGER.error("There was no build file") sys.exit(1) try: - return __import__("build", fromlist=[]) + return __import__(buildmodule, fromlist=[]) except ImportError: LOGGER.error("HOW?!") return None finally: sys.path.remove(path) - del sys.modules["build"] + del sys.modules[buildmodule] os.chdir(cwd) +def invoke_build(build, targets=None, props=None): + """Invoke Build with `targets` passing `props`""" + def call_target(target_name, props): + """Call target on build module""" + def process_params(params, existing_props=None): + """Parse and separate properties and append to build module""" + properties = existing_props if existing_props is not None else {} + for param in params: + name, value = param.split("=") + properties[name] = value + return properties + def __get_properties(): + """Return the properties dictionary of the build module""" + try: + return getattr(build, "PROPERTIES") + except AttributeError: + LOGGER.warning("Build file specifies no properties") + return None + try: + if props and len(props) > 0: + setattr(build, + "PROPERTIES", + process_params(props, __get_properties())) + target = getattr(build, target_name) + error_code = target() + return error_code if error_code else 0 + except AttributeError: + LOGGER.error("There was no target: %s", target_name) + return ERROR + except Exception as ex: + LOGGER.critical(ex) + return UNKNOWN_ERROR + if targets and len(targets) > 0: + for target in targets: + error_code = call_target(target, props) + if error_code: + return error_code + return SUCCESS + else: + return call_target("default", props) + +def list_targets(build): + """List targets (and doctstrings) of the provided build module""" + try: + for attr in dir(build): + try: + func = getattr(build, attr) + if func.decorator == "target": + print(attr + ":") + if func.__doc__: + print(func.__doc__) + print("") + except AttributeError: + pass + except AttributeError as ex: + LOGGER.error(ex) + return ERROR + return SUCCESS + +def parse_args(args_in): + """Parse and group arguments""" + parser = argparse.ArgumentParser(prog="Xnt") + parser.add_argument("-v", "--verbose", + help="Enable verbose output", + action="store_true", + dest="verbose") + parser.add_argument( + "--version", + action="version", + version=__version__, + help="Print Xnt Version and quit") + parser.add_argument( + "-b", "--build-file", + dest="build-file", + help="""Specify a build file if different than defaut or in different + path""") + parser.add_argument("-l", "--list-targets", + action="store_true", + dest="list-targets", + help="Print build targets") + # Properties Group + params_group = parser.add_argument_group("Properties") + params_group.add_argument( + "-D", dest="properties", action="append", + help="Property values to be passed to the build module") + target_group = parser.add_argument_group("Targets") + + # Targets Group + target_group.add_argument("targets", nargs=argparse.REMAINDER, + help="Name(s) of targets to invoke") + return vars(parser.parse_args(args_in)) + if __name__ == "__main__": main() |