Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
docs/_build
.coverage
*.egg-info
.tox
*.egg-info
*.pyc
2 changes: 1 addition & 1 deletion dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Docs
Sphinx>=1.1.2
releases>=0.2.0
releases>=0.2.4
# Testing (explicit dependencies to get around a Travis/pip issue)
# For now, need master as 1.3 isn't out yet :(
#nose>=1.3
Expand Down
7 changes: 0 additions & 7 deletions docs/api/loader.rst

This file was deleted.

11 changes: 5 additions & 6 deletions invoke/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

from .vendor import six

from .collection import Collection
from .context import Context
from .loader import Loader
from .parser import Parser, Context as ParserContext, Argument
from .executor import Executor
from .exceptions import Failure, CollectionNotFound, ParseError
from .exceptions import Failure, ParseError
from .util import debug, pty_size
from ._version import __version__

Expand Down Expand Up @@ -48,7 +48,6 @@ def print_help(tuples):
print('')



def parse_gracefully(parser, argv):
"""
Run ``parser.parse_argv(argv)`` & gracefully handle ``ParseError``.
Expand Down Expand Up @@ -148,7 +147,7 @@ def parse(argv, collection=None):
# TODO: if this wants to display context sensitive help (e.g. a combo help
# and available tasks listing; or core flags modified by plugins/task
# modules) it will have to move farther down.
if args.help.value == True:
if args.help.value is True:
print("Usage: inv[oke] [--core-opts] task1 [--task1-opts] ... taskN [--taskN-opts]")
print("")
print("Core options:")
Expand All @@ -159,8 +158,8 @@ def parse(argv, collection=None):
# (Skip loading if somebody gave us an explicit task collection.)
if not collection:
debug("No collection given, loading from %r" % args.root.value)
loader = Loader(root=args.root.value)
collection = loader.load_collection(args.collection.value)
name, root = args.collection.value, args.root.value
collection = Collection.load_collection(name, root)
parser = Parser(contexts=collection.to_contexts())
debug("Parsing actual tasks against collection %r" % collection)
tasks = parse_gracefully(parser, core.unparsed)
Expand Down
48 changes: 46 additions & 2 deletions invoke/collection.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
import copy
from operator import add
import imp
import os
import types

from .vendor import six
from .vendor.lexicon import Lexicon

from .parser import Context, Argument
from .exceptions import CollectionNotFound
from .parser import Context
from .tasks import Task


def _parent_dirs(root=None):
if root is None:
root = os.getcwd()
roots = [os.path.abspath(root)]
# Accumulate all parent directories
roots.append(os.path.dirname(roots[-1]))
while roots[-1] != roots[-2]:
roots.append(os.path.dirname(roots[-1]))
# Make sure we haven't got duplicates on the end
if roots[-1] == roots[-2]:
roots = roots[:-1]
return roots


class Collection(object):
"""
A collection of executable tasks.
"""

default_module_name = 'tasks'

def __init__(self, *args, **kwargs):
"""
Create a new task collection/namespace.
Expand Down Expand Up @@ -294,3 +313,28 @@ def configure(self, options):
:returns: ``None``.
"""
self._configuration.update(options)

@classmethod
def load_collection(cls, name=None, root=None):
"""
Try find find the module ``name``, recursively from the
directory ``root``.

default: name = 'tasks', root = current working directory.
"""
if name is None:
# TODO: make this configurable
name = cls.default_module_name
roots = _parent_dirs(root)
# Try to find the module
try:
file, pathname, desc = imp.find_module(name, roots)
except ImportError:
raise CollectionNotFound(name=name, root=root)
# Try to load it, then close the file we found
try:
module = imp.load_module(name, file, pathname, desc)
finally:
file.close()

return Collection.from_module(module)
66 changes: 0 additions & 66 deletions invoke/loader.py

This file was deleted.

1 change: 0 additions & 1 deletion tests/_support/tree.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
│   ├── cli.rst
│   ├── collection.rst
│   ├── exceptions.rst
│   ├── loader.rst
│   ├── parser
│   │   ├── argument.rst
│   │   ├── context.rst
Expand Down