diff --git a/superinvoke/collections/env.py b/superinvoke/collections/env.py index 72b90ae..acde669 100644 --- a/superinvoke/collections/env.py +++ b/superinvoke/collections/env.py @@ -39,14 +39,15 @@ def switch(context, environment): if not new_env: context.fail(f"{environment} is not a valid environment") + new_env = new_env[0] if new_env == old_env: - context.info(f"{environment} is already the current environment") + context.info(f"{new_env} is already the current environment") return context.create(utils.path(constants.Paths.ENV), data=[new_env], dir=False) if new_env != __ENVS__.Current: - context.fail(f"Cannot switch to environment {environment}") + context.fail(f"Cannot switch to environment {new_env}") context.print(f"Switched to environment [green3]{new_env}[/green3] from {old_env}") diff --git a/superinvoke/collections/tool.py b/superinvoke/collections/tool.py index 61b9ea7..ea54a89 100644 --- a/superinvoke/collections/tool.py +++ b/superinvoke/collections/tool.py @@ -38,11 +38,12 @@ def run(context, args): """Execute an available tool.""" from ..main import __TOOLS__ - tool, args = utils.next_arg(args) - tool = __TOOLS__.ByName(tool) + tool_name, args = utils.next_arg(args) + tool = __TOOLS__.ByName(tool_name) if not tool: - context.fail("Unknown tool") + context.fail(f"{tool_name} is not a valid tool") + tool = tool[0] install(context, include=tool.name, exclude="", yes=False) @@ -51,8 +52,8 @@ def run(context, args): @task( help={ - "include": "Tags, all or tool names that will be installed. Example: ops,golang-migrate,all...", - "exclude": "Tags, all or tool names that will be excluded. Example: golangci-lint,ci...", + "include": "Tags, globs or tool names that will be installed. Example: ops,golang-migrate,*...", + "exclude": "Tags, globs or tool names that will be excluded. Example: golangci-lint,ci,dev*...", "yes": "Automatically say yes to all prompts.", } ) @@ -61,68 +62,29 @@ def install(context, include, exclude="", yes=False): from ..main import __TOOLS__ include = {tool for tool in include.split(",") if tool and tool != ","} - include_tools = set() for name_or_tag in include: - if name_or_tag == "all": - for tool in __TOOLS__.All: - if tool._managed: - if not context.has(tool, version=tool.version): - include_tools.add(tool) - else: - context.info(f"{tool.name} already installed") - else: - context.info(f"{tool.name} not managed") - continue - - tool = __TOOLS__.ByName(name_or_tag) - if tool: - if tool._managed: - if not context.has(tool, version=tool.version): - include_tools.add(tool) - else: - context.info(f"{tool.name} already installed") - continue - else: - context.info(f"{tool.name} not managed") - - tools = __TOOLS__.ByTag(name_or_tag) - if tools: - for tool in tools: - if tool._managed: - if not context.has(tool, version=tool.version): - include_tools.add(tool) - else: - context.info(f"{tool.name} already installed") - else: - context.info(f"{tool.name} not managed") - continue - - context.warn(f"Ignoring {name_or_tag}") + include_tools.update(__TOOLS__.ByName(name_or_tag)) + include_tools.update(__TOOLS__.ByTag(name_or_tag)) exclude = {tool for tool in exclude.split(",") if tool and tool != ","} - exclude_tools = set() for name_or_tag in exclude: - if name_or_tag == "all": - exclude_tools.update(__TOOLS__.All) - continue + exclude_tools.update(__TOOLS__.ByName(name_or_tag)) + exclude_tools.update(__TOOLS__.ByTag(name_or_tag)) - tool = __TOOLS__.ByName(name_or_tag) - if tool: - exclude_tools.add(tool) - continue - - tools = __TOOLS__.ByTag(name_or_tag) - if tools: - exclude_tools.update(tools) - continue - - context.warn(f"Ignoring {name_or_tag}") - - tools = include_tools - exclude_tools + tools = set() + for tool in include_tools - exclude_tools: + if tool._managed: + if not context.has(tool, version=tool.version): + tools.add(tool) + else: + context.info(f"{tool.name} already installed") + else: + context.info(f"{tool.name} not managed") if not tools: + context.warn("No tools matched") return context.info(f"Tool(s) {', '.join([tool.name for tool in tools])} will be [bold green3]installed[/bold green3]") @@ -171,8 +133,8 @@ def install(context, include, exclude="", yes=False): @task( help={ - "include": "Tags, all or tool names that will be uninstalled. Example: ops,golang-migrate,all...", - "exclude": "Tags, all or tool names that will be excluded. Example: golangci-lint,ci...", + "include": "Tags, globs or tool names that will be uninstalled. Example: ops,golang-migrate,*...", + "exclude": "Tags, globs or tool names that will be excluded. Example: golangci-lint,ci,dev*...", "yes": "Automatically say yes to all prompts.", } ) @@ -181,68 +143,29 @@ def remove(context, include, exclude="", yes=False): from ..main import __TOOLS__ include = {tool for tool in include.split(",") if tool and tool != ","} - include_tools = set() for name_or_tag in include: - if name_or_tag == "all": - for tool in __TOOLS__.All: - if tool._managed: - if context.has(tool, version=tool.version): - include_tools.add(tool) - else: - context.info(f"{tool.name} not installed") - else: - context.info(f"{tool.name} not managed") - continue - - tool = __TOOLS__.ByName(name_or_tag) - if tool: - if tool._managed: - if context.has(tool, version=tool.version): - include_tools.add(tool) - else: - context.info(f"{tool.name} not installed") - else: - context.info(f"{tool.name} not managed") - continue - - tools = __TOOLS__.ByTag(name_or_tag) - if tools: - for tool in tools: - if tool._managed: - if context.has(tool, version=tool.version): - include_tools.add(tool) - else: - context.info(f"{tool.name} not installed") - else: - context.info(f"{tool.name} not managed") - continue - - context.warn(f"Ignoring {name_or_tag}") + include_tools.update(__TOOLS__.ByName(name_or_tag)) + include_tools.update(__TOOLS__.ByTag(name_or_tag)) exclude = {tool for tool in exclude.split(",") if tool and tool != ","} - exclude_tools = set() for name_or_tag in exclude: - if name_or_tag == "all": - exclude_tools.update(__TOOLS__.All) - continue - - tool = __TOOLS__.ByName(name_or_tag) - if tool: - exclude_tools.add(tool) - continue - - tools = __TOOLS__.ByTag(name_or_tag) - if tools: - exclude_tools.update(tools) - continue - - context.warn(f"Ignoring {name_or_tag}") - - tools = include_tools - exclude_tools + exclude_tools.update(__TOOLS__.ByName(name_or_tag)) + exclude_tools.update(__TOOLS__.ByTag(name_or_tag)) + + tools = set() + for tool in include_tools - exclude_tools: + if tool._managed: + if context.has(tool, version=tool.version): + tools.add(tool) + else: + context.info(f"{tool.name} not installed") + else: + context.info(f"{tool.name} not managed") if not tools: + context.warn("No tools matched") return context.info(f"Tool(s) {', '.join([tool.name for tool in tools])} will be [bold red1]uninstalled[/bold red1]") diff --git a/superinvoke/objects/common.py b/superinvoke/objects/common.py index 3179206..ca4a550 100644 --- a/superinvoke/objects/common.py +++ b/superinvoke/objects/common.py @@ -5,4 +5,4 @@ class Tags(utils.StrEnum): @utils.classproperty def ALL(cls): - return "all" + return "*" diff --git a/superinvoke/objects/env.py b/superinvoke/objects/env.py index 10f2be9..ed9b5ed 100644 --- a/superinvoke/objects/env.py +++ b/superinvoke/objects/env.py @@ -1,3 +1,4 @@ +import fnmatch from typing import Any, Callable, List, Optional from .. import constants, utils @@ -48,7 +49,8 @@ def All(cls) -> List[Env]: @utils.classproperty def Current(cls) -> Optional[Env]: if utils.exists(utils.path(constants.Paths.ENV)) == "file": - return cls.ByName(utils.read(utils.path(constants.Paths.ENV))[0]) + env = cls.ByName(utils.read(utils.path(constants.Paths.ENV))[0]) + return env[0] if env else None if hasattr(cls, "Default") and cls.Default is not None: return cls.Default(cls) @@ -56,13 +58,9 @@ def Current(cls) -> Optional[Env]: return None @classmethod - def ByTag(cls, tag) -> List[Env]: - return [env for env in cls.All if tag in env.tags or Tags.ALL in env.tags] + def ByTag(cls, tag: str) -> List[Env]: + return [env for env in cls.All if fnmatch.filter(env.tags, tag) or Tags.ALL in env.tags] @classmethod - def ByName(cls, name) -> Optional[Env]: - for env in cls.All: - if name == env.name: - return env - - return None + def ByName(cls, name: str) -> List[Env]: + return [env for env in cls.All if fnmatch.filter([env.name], name)] diff --git a/superinvoke/objects/tool.py b/superinvoke/objects/tool.py index 0f89f74..39b07fe 100644 --- a/superinvoke/objects/tool.py +++ b/superinvoke/objects/tool.py @@ -1,3 +1,4 @@ +import fnmatch from typing import List, Optional from .. import constants, utils @@ -72,13 +73,9 @@ def All(cls) -> List[Tool]: return all @classmethod - def ByTag(cls, tag) -> List[Tool]: - return [tool for tool in cls.All if tag in tool.tags or Tags.ALL in tool.tags] + def ByTag(cls, tag: str) -> List[Tool]: + return [tool for tool in cls.All if fnmatch.filter(tool.tags, tag) or Tags.ALL in tool.tags] @classmethod - def ByName(cls, name) -> Optional[Tool]: - for tool in cls.All: - if name == tool.name: - return tool - - return None + def ByName(cls, name: str) -> List[Tool]: + return [tool for tool in cls.All if fnmatch.filter([tool.name], name)]