Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Tool base class #1093

Merged
merged 21 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c609f31
Implement `Tool` base class; complete typing for tools
rmartin16 Feb 11, 2023
408f156
Bump required Xcode version from 10.0.0 to 13.0.0
rmartin16 Feb 18, 2023
0377125
Reimplement `upgrade` Command for `Tool` base class
rmartin16 Feb 25, 2023
458cdbe
Add Tool base class to `WindowsSDK`
rmartin16 Apr 21, 2023
7cd992e
Catch tools up to main
rmartin16 Apr 21, 2023
ecffe45
`typing.Callable` is deprecated; use `collections.abc.Callable` instead
rmartin16 Apr 25, 2023
5f2f772
Satisfy new `docformatter` requirements
rmartin16 Apr 25, 2023
4fe2741
Finalize Upgrade command semantics
rmartin16 Apr 25, 2023
05c04c1
Add tests for `Tool` base class implementation
rmartin16 May 2, 2023
f479c45
Merge branch 'main' into tool-base-class
rmartin16 May 13, 2023
0bb0699
Stop passing `app_name` to `Flatpak.run()` after `bundle_identifier` …
rmartin16 May 13, 2023
c8348af
Finish typing Tools' interfaces
rmartin16 May 14, 2023
dc0e58b
Merge branch 'main' into tool-base-class
rmartin16 May 21, 2023
08ce029
Minor tweaks to tests for Tool base
rmartin16 May 21, 2023
20f4ffb
Add `None` type for arguments that default to `None` and misc fixes
rmartin16 May 22, 2023
d1cf602
Convert Xcode verification functions to methods
rmartin16 May 22, 2023
7d07c5c
Revert typing hack for `ensure_console_is_safe` decorator
rmartin16 May 22, 2023
c6f274b
[WIP] type checking for integrations
rmartin16 May 26, 2023
a1564bf
Revert "[WIP] type checking for integrations"
rmartin16 May 29, 2023
dd083ad
Merge branch 'main' into tool-base-class
rmartin16 May 29, 2023
cf396d6
Add clarifying comment about test.
freakboy3742 May 29, 2023
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
1 change: 1 addition & 0 deletions changes/1093.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The ``Tool`` and ``ManagedTool`` base classes were implemented to unify tool functionality.
4 changes: 2 additions & 2 deletions src/briefcase/commands/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
TemplateUnsupportedVersion,
UnsupportedPlatform,
)
from briefcase.integrations import git
from briefcase.integrations.git import Git
from briefcase.integrations.subprocess import NativeAppContext

from .base import BaseCommand, full_options
Expand Down Expand Up @@ -811,7 +811,7 @@ def verify_tools(self):
Raises MissingToolException if a required system tool is missing.
"""
super().verify_tools()
git.verify_git_is_installed(tools=self.tools)
Git.verify(tools=self.tools)

def verify_app_tools(self, app: BaseConfig):
"""Verify that tools needed to run the command for this app exist."""
Expand Down
4 changes: 2 additions & 2 deletions src/briefcase/commands/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
make_class_name,
)
from briefcase.exceptions import BriefcaseCommandError, TemplateUnsupportedVersion
from briefcase.integrations import git
from briefcase.integrations.git import Git

from .base import BaseCommand

Expand Down Expand Up @@ -519,7 +519,7 @@ def verify_tools(self):
Raises MissingToolException if a required system tool is missing.
"""
super().verify_tools()
git.verify_git_is_installed(tools=self.tools)
Git.verify(tools=self.tools)

def __call__(
self,
Expand Down
136 changes: 66 additions & 70 deletions src/briefcase/commands/upgrade.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import sys
from typing import List
from operator import attrgetter
from typing import List, Set, Type

from briefcase.exceptions import BriefcaseCommandError
from briefcase.integrations.android_sdk import AndroidSDK
from briefcase.integrations.java import JDK
from briefcase.integrations.linuxdeploy import LinuxDeploy
from briefcase.integrations.rcedit import RCEdit
from briefcase.integrations.wix import WiX
from briefcase.exceptions import (
BriefcaseCommandError,
UnsupportedHostError,
UpgradeToolError,
)
from briefcase.integrations.base import ManagedTool, Tool, tool_registry

from .base import BaseCommand

Expand All @@ -17,16 +18,6 @@ class UpgradeCommand(BaseCommand):
output_format = None
description = "Upgrade Briefcase-managed tools."

def __init__(self, *args, **options):
super().__init__(*args, **options)
self.sdks = [
AndroidSDK,
LinuxDeploy,
JDK,
WiX,
RCEdit,
]

@property
def platform(self):
"""The upgrade command always reports as the local platform."""
Expand Down Expand Up @@ -59,62 +50,67 @@ def add_options(self, parser):
help="The Briefcase-managed tool to upgrade. If no tool is named, all tools will be upgraded.",
)

def __call__(self, tool_list: List[str], list_tools=False, **options):
# Verify all the managed SDKs and plugins to see which are present.
managed_tools = {}
non_managed_tools = set()

for klass in self.sdks:
try:
tool = klass.verify(self.tools, install=False)
if tool.managed_install:
managed_tools[klass.name] = tool
try:
for plugin_klass in tool.plugins.values():
try:
plugin = plugin_klass.verify(self.tools, install=False)
# All plugins are managed
managed_tools[plugin.name] = plugin
except BriefcaseCommandError:
# Plugin doesn't exist
non_managed_tools.add(klass.name)
except AttributeError:
# Tool doesn't have plugins
pass
def get_tools_to_upgrade(self, tool_list: Set[str]) -> List[ManagedTool]:
"""Returns set of managed Tools that can be upgraded.

Raises ``BriefcaseCommandError`` if user list contains any invalid tool names.
"""
upgrade_list: set[Type[Tool]]
tools_to_upgrade: set[ManagedTool] = set()

# Validate user tool list against tool registry
if tool_list:
if invalid_tools := tool_list - set(tool_registry):
raise UpgradeToolError(
f"Briefcase does not know how to manage {', '.join(sorted(invalid_tools))}."
)
upgrade_list = {
tool for name, tool in tool_registry.items() if name in tool_list
}
else:
upgrade_list = set(tool_registry.values())

# Filter list of tools to those that are being managed
for tool_klass in upgrade_list:
if issubclass(tool_klass, ManagedTool):
try:
tool = tool_klass.verify(tools=self.tools, install=False)
except (BriefcaseCommandError, UnsupportedHostError):
pass
else:
non_managed_tools.add(klass.name)
except BriefcaseCommandError:
# Tool doesn't exist
non_managed_tools.add(klass.name)

# If a tool list wasn't provided, use the list of installed tools
if not tool_list:
tool_list = sorted(managed_tools.keys())

# Build a list of requested tools that are managed.
found_tools = []
for name in tool_list:
if name in managed_tools:
found_tools.append(name)
elif name not in non_managed_tools:
raise BriefcaseCommandError(
f"Briefcase doesn't know how to manage the tool '{name}'"
if tool.managed_install:
tools_to_upgrade.add(tool)

# Let the user know if any requested tools are not being managed
if tool_list:
if unmanaged_tools := tool_list - {tool.name for tool in tools_to_upgrade}:
error_msg = (
f"Briefcase is not managing {', '.join(sorted(unmanaged_tools))}."
)

if found_tools:
if list_tools:
self.logger.info("Briefcase is managing the following tools:")
for name in found_tools:
self.logger.info(f" - {name}")
else:
self.logger.info("Briefcase will upgrade the following tools:")
for name in found_tools:
self.logger.info(f" - {name}")

for name in found_tools:
tool = managed_tools[name]
if not tools_to_upgrade:
raise UpgradeToolError(error_msg)
else:
self.logger.warning(error_msg)

return sorted(list(tools_to_upgrade), key=attrgetter("name"))

def __call__(self, tool_list: List[str], list_tools: bool = False, **options):
"""Perform tool upgrades or list tools qualifying for upgrade.

:param tool_list: List of tool names from user to upgrade.
:param list_tools: Boolean to only list upgradeable tools (default False).
"""
if tools_to_upgrade := self.get_tools_to_upgrade(set(tool_list)):
self.logger.info(
f"Briefcase {'is managing' if list_tools else 'will upgrade'} the following tools:",
prefix=self.command,
)
for tool in tools_to_upgrade:
self.logger.info(f" - {tool.full_name} ({tool.name})")

if not list_tools:
for tool in tools_to_upgrade:
self.logger.info(f"Upgrading {tool.full_name}...", prefix=tool.name)
tool.upgrade()

else:
self.logger.info("Briefcase is not managing any tools.")
9 changes: 7 additions & 2 deletions src/briefcase/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ def __str__(self):


class BriefcaseCommandError(BriefcaseError):
def __init__(self, msg):
super().__init__(error_code=200)
def __init__(self, msg, skip_logfile=False):
super().__init__(error_code=200, skip_logfile=skip_logfile)
self.msg = msg

def __str__(self):
Expand Down Expand Up @@ -109,6 +109,11 @@ def __init__(self, tool):
super().__init__(msg=f"{tool!r} is using an install that is user managed.")


class UpgradeToolError(BriefcaseCommandError):
def __init__(self, error_msg):
super().__init__(msg=error_msg, skip_logfile=True)


class TemplateUnsupportedVersion(BriefcaseCommandError):
def __init__(self, briefcase_version):
self.briefcase_version = briefcase_version
Expand Down
Loading