Skip to content

Commit

Permalink
Merge pull request #777 from rmartin16/dirs
Browse files Browse the repository at this point in the history
Adopt OS-native Filesystem Location for File Caching
  • Loading branch information
freakboy3742 authored Jul 13, 2022
2 parents c58095e + 75b4e41 commit baf2942
Show file tree
Hide file tree
Showing 29 changed files with 427 additions and 109 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,23 +141,27 @@ jobs:
framework: ['toga', 'pyside2', 'pyside6', 'ppb']
include:
- platform: macos-latest
briefcase-data-dir: ~/Library/Application Support/briefcase
pip-cache-dir: ~/Library/Caches/pip
docker-cache-dir: ~/Library/Containers/com.docker.docker/Data/vms/0/
- platform: windows-latest
briefcase-data-dir: ~\AppData\Local\BeeWare\briefcase
pip-cache-dir: ~\AppData\Local\pip\Cache
docker-cache-dir: C:\ProgramData\DockerDesktop
- platform: ubuntu-latest
briefcase-data-dir: ~/.local/share/briefcase
pip-cache-dir: ~/.cache/pip
docker-cache-dir: /var/lib/docker
# cache action cannot cache docker images (actions/cache#31)
# docker-cache-dir: /var/lib/docker
runs-on: ${{ matrix.platform }}
steps:
- name: Cache Briefcase tools
uses: actions/cache@v3
with:
key: briefcase-${{ matrix.platform }}
path: |
~/.briefcase
~/.cookiecutters
${{ matrix.briefcase-data-dir }}
${{ matrix.pip-cache-dir }}
${{ matrix.docker-cache-dir }}
- uses: actions/checkout@v3
Expand Down
1 change: 1 addition & 0 deletions changes/374.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SDKs, tools, and other downloads needed to support app builds are now stored in an OS-native user data directory instead of ``~/.briefcase``.
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ install_requires =
dmgbuild >= 1.3.3; sys_platform == "darwin"
psutil >= 5.9.0
rich >= 12.4.1
appdirs >= 1.4.4

[options.packages.find]
where = src
Expand Down
1 change: 1 addition & 0 deletions src/briefcase/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def main():
command = None
try:
command, options = parse_cmdline(sys.argv[1:])
command.check_obsolete_data_dir()
command.parse_config("pyproject.toml")
command(**options)
result = 0
Expand Down
90 changes: 87 additions & 3 deletions src/briefcase/commands/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from urllib.parse import urlparse

import requests
from appdirs import AppDirs
from cookiecutter.main import cookiecutter
from cookiecutter.repository import is_repo_url

Expand All @@ -26,6 +27,7 @@
BadNetworkResourceError,
BriefcaseCommandError,
BriefcaseConfigError,
InfoHelpText,
MissingNetworkResourceError,
)
from briefcase.integrations.subprocess import Subprocess
Expand Down Expand Up @@ -112,11 +114,18 @@ class BaseCommand(ABC):
GLOBAL_CONFIG_CLASS = GlobalConfig
APP_CONFIG_CLASS = AppConfig

def __init__(self, base_path, home_path=Path.home(), apps=None, input_enabled=True):
def __init__(
self,
base_path,
home_path=Path.home(),
data_path=Path(AppDirs(appname="briefcase", appauthor="BeeWare").user_data_dir),
apps=None,
input_enabled=True,
):
self.base_path = base_path
self.home_path = home_path
self.dot_briefcase_path = home_path / ".briefcase"
self.tools_path = self.dot_briefcase_path / "tools"
self.data_path = data_path
self.tools_path = self.data_path / "tools"

self.global_config = None
self.apps = {} if apps is None else apps
Expand All @@ -143,6 +152,81 @@ def __init__(self, base_path, home_path=Path.home(), apps=None, input_enabled=Tr
self.logger = Log()
self.save_log = False

def check_obsolete_data_dir(self):
"""Inform user if obsolete data directory exists.
TODO: Remove this check after 1 JAN 2023 since most users will have transitioned by then
Previous versions used the ~/.briefcase directory to store
downloads, tools, etc. This check lets users know the old
directory still exists and their options to migrate or clean up.
"""
dot_briefcase_path = self.home_path / ".briefcase"

if not dot_briefcase_path.exists():
return

if self.data_path.exists():
self.logger.warning(
f"""\
Briefcase is no longer using the data directory:
{dot_briefcase_path}
This directory can be safely deleted.
"""
)
else:
self.logger.warning(
f"""\
*************************************************************************
** NOTICE: Briefcase is changing its data directory **
*************************************************************************
Briefcase is moving its data directory from:
{dot_briefcase_path}
to:
{self.data_path}
If you continue, Briefcase will re-download the tools and data it
uses to build and package applications.
To avoid potentially large downloads and long installations, you
can manually move the old data directory to the new location.
If you continue and allow Briefcase to re-download its tools, the
old data directory can be safely deleted.
*************************************************************************
"""
)
self.input.prompt()
if not self.input.boolean_input(
"Do you want to re-download the Briefcase support tools",
# Default to continuing for non-interactive runs
default=not self.input.enabled,
):
raise InfoHelpText(
f"""\
Move the Briefcase data directory from:
{dot_briefcase_path}
to:
{self.data_path}
or delete the old data directory, and re-run Briefcase.
"""
)

# Create data directory to prevent full notice showing again.
self.data_path.mkdir(parents=True, exist_ok=True)

@property
def create_command(self):
"""Factory property; return an instance of a create command for the
Expand Down
2 changes: 1 addition & 1 deletion src/briefcase/commands/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ def install_app_support_package(self, app: BaseConfig):
# in the user's briefcase support cache directory.
support_filename = self.download_url(
url=support_package_url,
download_path=self.dot_briefcase_path / "support",
download_path=self.data_path / "support",
)
else:
support_filename = Path(support_package_url)
Expand Down
23 changes: 14 additions & 9 deletions src/briefcase/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ class HelpText(BriefcaseError):
an error."""


class InfoHelpText(HelpText):
def __init__(self, msg):
super().__init__(0)
self.msg = msg

def __str__(self):
return self.msg


class NoCommandError(HelpText):
def __init__(self, msg):
super().__init__(-10)
Expand All @@ -17,20 +26,16 @@ def __str__(self):
return self.msg


class ShowOutputFormats(HelpText):
class ShowOutputFormats(InfoHelpText):
def __init__(self, platform, default, choices):
super().__init__(0)
super().__init__(
f"Available formats for {platform}: {', '.join(sorted(choices))}\n"
f"Default format: {default}"
)
self.platform = platform
self.default = default
self.choices = choices

def __str__(self):
choices = ", ".join(sorted(self.choices))
return (
f"Available formats for {self.platform}: {choices}\n"
f"Default format: {self.default}"
)


class InvalidFormatError(BriefcaseError):
def __init__(self, requested, choices):
Expand Down
20 changes: 9 additions & 11 deletions src/briefcase/integrations/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def verify_docker(command):
{install_url}
to download and install git manually.
to download and install Docker manually.
{extra_content}
If you have installed Docker recently and are still getting this error, you may
need to restart your terminal session.
Expand Down Expand Up @@ -243,9 +243,11 @@ def prepare(self):

def run(self, args, env=None, **kwargs):
"""Run a process inside a Docker container."""
# briefcase data directory used inside container
docker_data_path = "/home/brutus/.local/share/briefcase"
# Set up the `docker run` with volume mounts for the platform &
# .briefcase directories and to delete the temporary container
# after running the command.
# briefcase data and tools directories and to delete the
# temporary container after running the command.
# The :z suffix allows SELinux to modify the host mount; it is
# ignored on non-SELinux platforms.
docker_args = [
Expand All @@ -254,7 +256,7 @@ def run(self, args, env=None, **kwargs):
"--volume",
f"{self.command.platform_path}:/app:z",
"--volume",
f"{self.command.dot_briefcase_path}:/home/brutus/.briefcase:z",
f"{self.command.data_path}:{docker_data_path}:z",
"--rm",
]

Expand All @@ -268,20 +270,16 @@ def run(self, args, env=None, **kwargs):
docker_args.append(self.command.docker_image_tag(self.app))

# ... then add the command (and its arguments) to run in the container
for arg in args:
arg = str(arg)
for arg in map(str, args):
if arg == sys.executable:
docker_args.append(f"python{self.command.python_version_tag}")
elif os.fsdecode(self.command.platform_path) in arg:
docker_args.append(
arg.replace(os.fsdecode(self.command.platform_path), "/app")
)
elif os.fsdecode(self.command.dot_briefcase_path) in arg:
elif os.fsdecode(self.command.data_path) in arg:
docker_args.append(
arg.replace(
os.fsdecode(self.command.dot_briefcase_path),
"/home/brutus/.briefcase",
)
arg.replace(os.fsdecode(self.command.data_path), docker_data_path)
)
else:
docker_args.append(arg)
Expand Down
10 changes: 5 additions & 5 deletions src/briefcase/integrations/java.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def verify(cls, command, install=True):
points to a Java 8 JDK, use it.
Otherwise, download a JDK from AdoptOpenJDK and unpack it into the
``~.briefcase`` path.
briefcase data directory.
:param command: The command that needs to perform the verification
check.
Expand Down Expand Up @@ -223,8 +223,8 @@ def exists(self):
@property
def managed_install(self):
try:
# Determine if java_home is relative to the .briefcase folder.
# If java_home isn't inside .briefcase, this will raise a ValueError,
# Determine if java_home is relative to the briefcase data directory.
# If java_home isn't inside this directory, this will raise a ValueError,
# indicating it is a non-managed install.
self.java_home.relative_to(self.command.tools_path)
return True
Expand Down Expand Up @@ -260,9 +260,9 @@ def install(self):

jdk_zip_path.unlink() # Zip file no longer needed once unpacked.

# The tarball will unpack into ~.briefcase/tools/jdk8u242-b08
# The tarball will unpack into <briefcase data dir>/tools/jdk8u242-b08
# (or whatever name matches the current release).
# We turn this into ~.briefcase/tools/java so we have a consistent name.
# We turn this into <briefcase data dir>/tools/java so we have a consistent name.
java_unpack_path = (
self.command.tools_path / f"jdk{self.release}-{self.build}"
)
Expand Down
4 changes: 2 additions & 2 deletions src/briefcase/integrations/wix.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ def exists(self):
@property
def managed_install(self):
try:
# Determine if wix_home is relative to the .briefcase folder.
# If wix_home isn't inside .briefcase, this will raise a ValueError,
# Determine if wix_home is relative to the briefcase data directory.
# If wix_home isn't inside this directory, this will raise a ValueError,
# indicating it is a non-managed install.
self.wix_home.relative_to(self.command.tools_path)
return True
Expand Down
Loading

0 comments on commit baf2942

Please sign in to comment.