summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkennyballou <kballou@onyx.boisestate.edu>2013-03-10 20:57:57 -0600
committerkennyballou <kballou@onyx.boisestate.edu>2013-03-10 20:57:57 -0600
commit5a4074d3a042ddd67658a2ecc8c8fdc3745a4676 (patch)
tree2f9f8029bd63b14fbdc6d9d13b1039ec54f9f8fb
parent69874f19c238d4ded308430902238f4e692cb335 (diff)
parentba393af1d25e4a83ea02e11885f7d4c9d1fdf07f (diff)
downloadxnt-5a4074d3a042ddd67658a2ecc8c8fdc3745a4676.tar.gz
xnt-5a4074d3a042ddd67658a2ecc8c8fdc3745a4676.tar.xz
Merge branch 'master' into refactor-logging-levels
Conflicts: xnt/version.py
-rw-r--r--README.rst14
-rw-r--r--docs/source/buildfile.rst6
-rw-r--r--docs/source/taskreference.rst5
-rw-r--r--docs/source/xenant.rst23
-rw-r--r--pylint.conf2
-rw-r--r--xnt/basecommand.py32
-rw-r--r--xnt/cmdoptions.py31
-rw-r--r--xnt/commands/__init__.py41
-rw-r--r--xnt/commands/help.py42
-rw-r--r--xnt/commands/listtargets.py56
-rw-r--r--xnt/commands/target.py78
-rw-r--r--xnt/commands/version.py34
-rw-r--r--xnt/tasks.py10
-rw-r--r--xnt/tests/xenantargparsertests.py158
-rw-r--r--xnt/version.py2
-rw-r--r--xnt/xenant.py149
16 files changed, 309 insertions, 374 deletions
diff --git a/README.rst b/README.rst
index a9b66f2..4b55855 100644
--- a/README.rst
+++ b/README.rst
@@ -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()