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

Use cache dirs rather than data dirs, and allow path customisation. #791

Merged
merged 9 commits into from
Jul 15, 2022
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,15 @@ jobs:
framework: ['toga', 'pyside2', 'pyside6', 'ppb']
include:
- platform: macos-latest
briefcase-data-dir: ~/Library/Application Support/briefcase
briefcase-data-dir: ~/Library/Caches/org.beeware.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
briefcase-data-dir: ~\AppData\Local\BeeWare\briefcase\Cache
pip-cache-dir: ~\AppData\Local\pip\Cache
docker-cache-dir: C:\ProgramData\DockerDesktop
- platform: ubuntu-latest
briefcase-data-dir: ~/.local/share/briefcase
briefcase-data-dir: ~/.cache/briefcase
pip-cache-dir: ~/.cache/pip
# cache action cannot cache docker images (actions/cache#31)
# docker-cache-dir: /var/lib/docker
Expand Down
2 changes: 1 addition & 1 deletion changes/374.feature.rst
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SDKs, tools, and other downloads needed to support app builds are now stored in an OS-native user data directory instead of ``~/.briefcase``.
SDKs, tools, and other downloads needed to support app builds are now stored in an OS-native user cache directory instead of ``~/.briefcase``.
1 change: 1 addition & 0 deletions changes/789.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added support for the user to define a ``BRIEFCASE_HOME`` environment variable. This enables the user to specify the location of the Briefcase tool cache, allowing the user to avoid issues with spaces in paths or disk space limitations.
8 changes: 4 additions & 4 deletions docs/how-to/code-signing/android.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,28 +48,28 @@ Google Play.
.. code-block:: bash

$ mkdir -p ~/.android
$ ~/Library/Application\ Support/briefcase/tools/java/Contents/Home/bin/keytool -keyalg RSA -deststoretype pkcs12 -genkey -v -storepass android -keystore ~/.android/upload-key-helloworld.jks -keysize 2048 -dname "cn=Upload Key" -alias upload-key -validity 10000
$ ~/Library/Caches/org.beeware.briefcase/tools/java/Contents/Home/bin/keytool -keyalg RSA -deststoretype pkcs12 -genkey -v -storepass android -keystore ~/.android/upload-key-helloworld.jks -keysize 2048 -dname "cn=Upload Key" -alias upload-key -validity 10000

.. group-tab:: Linux

.. code-block:: bash

$ mkdir -p ~/.android
$ ~/.local/share/briefcase/tools/java/bin/keytool -keyalg RSA -deststoretype pkcs12 -genkey -v -storepass android -keystore ~/.android/upload-key-helloworld.jks -keysize 2048 -dname "cn=Upload Key" -alias upload-key -validity 10000
$ ~/.cache/briefcase/tools/java/bin/keytool -keyalg RSA -deststoretype pkcs12 -genkey -v -storepass android -keystore ~/.android/upload-key-helloworld.jks -keysize 2048 -dname "cn=Upload Key" -alias upload-key -validity 10000

.. group-tab:: Windows (PowerShell)

.. code-block:: powershell

C:\...>If (-Not (Test-Path "$env:HOMEPATH/.android")) { New-Item -Path "$env:HOMEPATH\.android" -ItemType Directory }
C:\...>& "$env:LOCALAPPDATA\BeeWare\briefcase\tools\java\bin\keytool.exe" -keyalg RSA -deststoretype pkcs12 -genkey -v -storepass android -keystore "$env:HOMEPATH\.android\upload-key-helloworld.jks" -keysize 2048 -dname "cn=Upload Key" -alias upload-key -validity 10000
C:\...>& "$env:LOCALAPPDATA\BeeWare\briefcase\Cache\tools\java\bin\keytool.exe" -keyalg RSA -deststoretype pkcs12 -genkey -v -storepass android -keystore "$env:HOMEPATH\.android\upload-key-helloworld.jks" -keysize 2048 -dname "cn=Upload Key" -alias upload-key -validity 10000

.. group-tab:: Windows (cmd)

.. code-block:: doscon

C:\...>IF not exist %HOMEPATH%\.android mkdir %HOMEPATH%\.android
C:\...>%LOCALAPPDATA%\BeeWare\briefcase\tools\java\bin\keytool.exe -keyalg RSA -deststoretype pkcs12 -genkey -v -storepass android -keystore %HOMEPATH%\.android\upload-key-helloworld.jks -keysize 2048 -dname "cn=Upload Key" -alias upload-key -validity 10000
C:\...>%LOCALAPPDATA%\BeeWare\briefcase\Cache\tools\java\bin\keytool.exe -keyalg RSA -deststoretype pkcs12 -genkey -v -storepass android -keystore %HOMEPATH%\.android\upload-key-helloworld.jks -keysize 2048 -dname "cn=Upload Key" -alias upload-key -validity 10000


This creates a 2048-bit key and stores it in a Java keystore located in the
Expand Down
8 changes: 4 additions & 4 deletions docs/how-to/publishing/android.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ name.

.. code-block::

$ ~/Library/Application\ Support/briefcase/tools/java/Contents/Home/bin/jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ~/.android/upload-key-helloworld.jks "android/gradle/Hello World/app/build/outputs/bundle/release/app-release.aab" upload-key -storepass android
$ ~/Library/Caches/org.beeware.briefcase/tools/java/Contents/Home/bin/jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ~/.android/upload-key-helloworld.jks "android/gradle/Hello World/app/build/outputs/bundle/release/app-release.aab" upload-key -storepass android
adding: META-INF/MANIFEST.MF
adding: META-INF/UPLOAD-K.SF
adding: META-INF/UPLOAD-K.RSA
Expand All @@ -101,7 +101,7 @@ name.

.. code-block::

$ ~/.local/share/briefcase/tools/java/bin/jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ~/.android/upload-key-helloworld.jks "android/gradle/Hello World/app/build/outputs/bundle/release/app-release.aab" upload-key -storepass android
$ ~/.cache/briefcase/tools/java/bin/jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ~/.android/upload-key-helloworld.jks "android/gradle/Hello World/app/build/outputs/bundle/release/app-release.aab" upload-key -storepass android
adding: META-INF/MANIFEST.MF
adding: META-INF/UPLOAD-K.SF
adding: META-INF/UPLOAD-K.RSA
Expand All @@ -126,7 +126,7 @@ name.

.. code-block::

C:\...>& "$env:LOCALAPPDATA\BeeWare\briefcase\tools\java\bin\jarsigner.exe" -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore "$env:HOMEPATH\.android\upload-key-helloworld.jks" "android\gradle\Hello World\app\build\outputs\bundle\release\app-release.aab" upload-key -storepass android
C:\...>& "$env:LOCALAPPDATA\BeeWare\briefcase\Cache\tools\java\bin\jarsigner.exe" -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore "$env:HOMEPATH\.android\upload-key-helloworld.jks" "android\gradle\Hello World\app\build\outputs\bundle\release\app-release.aab" upload-key -storepass android
adding: META-INF/MANIFEST.MF
adding: META-INF/UPLOAD-K.SF
adding: META-INF/UPLOAD-K.RSA
Expand All @@ -151,7 +151,7 @@ name.

.. code-block:: doscon

C:\...>%LOCALAPPDATA%\BeeWare\briefcase\tools\java\bin\jarsigner.exe -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore %HOMEPATH%\.android\upload-key-helloworld.jks "android\gradle\Hello World\app\build\outputs\bundle\release\app-release.aab" upload-key -storepass android
C:\...>%LOCALAPPDATA%\BeeWare\briefcase\Cache\tools\java\bin\jarsigner.exe -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore %HOMEPATH%\.android\upload-key-helloworld.jks "android\gradle\Hello World\app\build\outputs\bundle\release\app-release.aab" upload-key -storepass android
adding: META-INF/MANIFEST.MF
adding: META-INF/UPLOAD-K.SF
adding: META-INF/UPLOAD-K.RSA
Expand Down
8 changes: 4 additions & 4 deletions docs/reference/configuration.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
=====================
Configuration options
=====================
=============================
Project configuration options
=============================

Briefcase is a `PEP518 <https://www.python.org/dev/peps/pep-0518/>`__-compliant
build tool. It uses a ``pyproject.toml`` file, in the root directory of your
project, to provide build instructions for the packaged file.

If you have an application called "My App", with source code in the `src/myapp`
If you have an application called "My App", with source code in the ``src/myapp``
directory, the simplest possible ``pyproject.toml`` Briefcase configuration
file would be::

Expand Down
29 changes: 29 additions & 0 deletions docs/reference/environment.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
===============================
Briefcase configuration options
===============================

Environment variables
=====================

``BRIEFCASE_HOME``
~~~~~~~~~~~~~~~~~~

When briefcase runs, it will download the support files, tools, and SDKs
necessary to support building and packaging apps. By default, it will store the
files in a platform-native cache folder:

* macOS: ``~/Library/Caches/org.beeware.briefcase``
* Windows: ``%LOCALAPPDATA%\BeeWare\briefcase\Cache``
* Linux: ``~/.cache/briefcase``

If you want to use a different folder to store the Briefcase resources, you can
define a ``BRIEFCASE_HOME`` environment variable.

There are three restrictions on this path specification:

1. The path must already exist. If it doesn't exist, you should create it manually.
2. It *must not* contain any spaces.
3. It *must not* be on a network drive.

The second two restrictions both exist because some of the tools that Briefcase
uses (in particular, the Android SDK) do not work in these locations.
1 change: 1 addition & 0 deletions docs/reference/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This is the technical reference for public APIs provided by Briefcase.
.. toctree::
:maxdepth: 2

environment
configuration
commands/index
platforms/index
67 changes: 59 additions & 8 deletions src/briefcase/commands/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,24 +117,70 @@ class BaseCommand(ABC):
def __init__(
self,
base_path,
home_path=Path.home(),
data_path=PlatformDirs(appname="briefcase", appauthor="BeeWare").user_data_path,
home_path=None,
data_path=None,
apps=None,
input_enabled=True,
):
# Some details about the host machine
self.host_arch = platform.machine()
self.host_os = platform.system()

self.base_path = base_path
self.home_path = home_path
self.data_path = data_path

# If a home path is provided during construction, use it. This usually
# indicates we're under test conditions.
if home_path is None:
home_path = Path.home()
self.home_path = Path(home_path)

# If a data path is provided during construction, use it. This usually
# indicates we're under test conditions. If there's no data path
# provided, look for a BRIEFCASE_HOME environment variable. If that
# isn't defined, use a platform-specific default data path.
if data_path is None:
try:
data_path = Path(os.environ["BRIEFCASE_HOME"])
if not data_path.exists():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, Path("") returns PosixPath('.')....so this lets an empty BRIEFCASE_HOME sneak by. I wouldn't consider this especially important if I hadn't tried export <ENV VAR>="" too many times in the past instead of unset <ENV VAR>.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - I've added an explicit catch of this case.

raise BriefcaseCommandError(
"The path specified by BRIEFCASE_HOME does not exist."
)
except KeyError:
if self.host_os == "Darwin":
# macOS uses a bundle name, rather than just the app name
app_name = "org.beeware.briefcase"
else:
app_name = "briefcase"

data_path = PlatformDirs(
appname=app_name,
appauthor="BeeWare",
).user_cache_path

if " " in os.fsdecode(data_path):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we really want to be absolute, checking all characters against string.whitespace may be best.....but I think I say this mostly tongue in cheek.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah... but you just know someone is going to put a tab in their username for giggles...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or a non-breaking space ;)

raise BriefcaseCommandError(
f"""
The location Briefcase will use to store tools and support files:

{data_path}

contains spaces. This will cause problems with some tools, preventing
you from building and packaging applications.

You can set the environment variable BRIEFCASE_HOME to specify
a custom location for Briefcase's tools.

"""
)

self.data_path = Path(data_path)

self.tools_path = self.data_path / "tools"

self.global_config = None
self.apps = {} if apps is None else apps
self._path_index = {}

# Some details about the host machine
self.host_arch = platform.machine()
self.host_os = platform.system()

# External service APIs.
# These are abstracted to enable testing without patching.
self.cookiecutter = cookiecutter
Expand Down Expand Up @@ -163,9 +209,14 @@ def check_obsolete_data_dir(self):
"""
dot_briefcase_path = self.home_path / ".briefcase"

# If there's no .briefcase path, no need to check for migration.
if not dot_briefcase_path.exists():
return

# If the data path is user-provided, don't check for migration.
if "BRIEFCASE_HOME" in os.environ:
return

if self.data_path.exists():
self.logger.warning(
f"""\
Expand Down
27 changes: 27 additions & 0 deletions tests/commands/base/test_check_obsolete_data_dir.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from unittest.mock import MagicMock

import pytest
Expand All @@ -18,12 +19,38 @@ def test_skip_if_dot_briefcase_nonexistent(capsys, tmp_path):
home_path=home_path,
data_path=tmp_path / "data_dir",
)
cmd.input.boolean_input = MagicMock()

cmd.check_obsolete_data_dir()

cmd.input.boolean_input.assert_not_called()
assert not dot_briefcase_dir.exists()
assert capsys.readouterr().out == ""


def test_skip_if_data_dir_from_environment(monkeypatch, capsys, tmp_path):
"""If the data directory came from the user environment, don't run the
check, even if .briefcase exists."""
monkeypatch.setenv("BRIEFCASE_HOME", os.fsdecode(tmp_path / "custom"))

home_path = tmp_path / "home"
dot_briefcase_dir = home_path / ".briefcase"
dot_briefcase_dir.mkdir(parents=True)

cmd = DummyCommand(
base_path=tmp_path / "base",
home_path=home_path,
data_path=tmp_path / "data_dir",
)
cmd.input.boolean_input = MagicMock()

cmd.check_obsolete_data_dir()

cmd.input.boolean_input.assert_not_called()
assert dot_briefcase_dir.exists()
assert capsys.readouterr().out == ""


def test_first_notice_if_dot_briefcase_exists(capsys, tmp_path):
"""Obsolete data dir check shows full notice of transition if .briefcase
directory exists but new data directory does not exist."""
Expand Down
Loading