Skip to content

Commit

Permalink
Merge pull request #1231 from yngvem/issue-1202
Browse files Browse the repository at this point in the history
Issue 1202 - Make wizard work with existing projects
  • Loading branch information
freakboy3742 committed Apr 12, 2024
2 parents 29f6745 + 996eb3b commit f49c65e
Show file tree
Hide file tree
Showing 41 changed files with 2,986 additions and 278 deletions.
1 change: 1 addition & 0 deletions changes/1202.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Existing projects with a ``pyproject.toml`` configuration can now be converted into Briefcase apps using the ``briefcase convert`` command.
56 changes: 56 additions & 0 deletions docs/reference/commands/convert.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
=======
convert
=======

Convert an existing project with a ``pyproject.toml`` configuration into a project that
can be deployed with Briefcase. Runs a wizard to ask questions about your existing
application (reading from the ``pyproject.toml`` file where applicable), adds the
necessary files to the project, and updates the ``pyproject.toml`` file to include the
``briefcase`` section.

Usage
=====

To convert your application, run the following command in the application root
directory (where the ``pyproject.toml`` file is located):

.. code-block:: console
$ briefcase convert
Options
=======

The following options can be provided at the command line.

``-t <template>`` / ``--template <template>``
---------------------------------------------

A local directory path or URL to use as a cookiecutter template for the
project.

``--template-branch <branch>``
------------------------------

The branch of the cookiecutter template repository to use for the project.
If not specified, Briefcase will attempt to use a template branch matching the
version of Briefcase that is being used (i.e., if you're using Briefcase 0.3.14,
Briefcase will use the ``v0.3.14`` template branch when generating the app). If
you're using a development version of Briefcase, Briefcase will use the ``main``
branch of the template.

``-Q <KEY=VALUE>``
------------------

Override the answer to a prompt with the provided value.

For instance, if ``-Q "license=MIT license"`` is specified, then the question
to choose a license will not be presented to the user and the MIT license will
be automatically used for the project. When used in conjunction with
``--no-input``, the provided value overrides the default answer.

The expected keys are specified by the cookiecutter template being used to
create a new project (the same cookiecutter template is used here). Therefore,
the set of possible keys is not listed here but should be expected to remain
consistent for any specific version of Briefcase; with version changes, though,
the keys may change.
1 change: 1 addition & 0 deletions docs/reference/commands/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Command reference
:maxdepth: 1

new
convert
dev
create
update
Expand Down
6 changes: 5 additions & 1 deletion src/briefcase/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from briefcase import __version__
from briefcase.commands import (
BuildCommand,
ConvertCommand,
CreateCommand,
DevCommand,
NewCommand,
Expand All @@ -26,6 +27,7 @@
COMMANDS = [
NewCommand,
DevCommand,
ConvertCommand,
CreateCommand,
OpenCommand,
BuildCommand,
Expand Down Expand Up @@ -126,7 +128,9 @@ def parse_known_args(args):
raise NoCommandError(parser.format_help())

# Commands agnostic to the platform and format
if options.command == "new":
if options.command == "convert":
Command = ConvertCommand
elif options.command == "new":
Command = NewCommand
elif options.command == "dev":
Command = DevCommand
Expand Down
1 change: 1 addition & 0 deletions src/briefcase/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .build import BuildCommand # noqa: F401
from .convert import ConvertCommand # noqa: F401
from .create import CreateCommand # noqa: F401
from .dev import DevCommand # noqa: F401
from .new import NewCommand # noqa: F401
Expand Down
65 changes: 62 additions & 3 deletions src/briefcase/commands/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@

from cookiecutter import exceptions as cookiecutter_exceptions
from cookiecutter.repository import is_repo_url
from packaging.version import Version
from platformdirs import PlatformDirs

if sys.version_info >= (3, 11): # pragma: no-cover-if-lt-py311
import tomllib
else: # pragma: no-cover-if-gte-py311
import tomli as tomllib

import briefcase
from briefcase import __version__
from briefcase.config import AppConfig, GlobalConfig, parse_config
from briefcase.console import MAX_TEXT_WIDTH, Console, Log
Expand Down Expand Up @@ -942,7 +944,7 @@ def update_cookiecutter_cache(self, template: str, branch="master"):

return cached_template

def generate_template(self, template, branch, output_path, extra_context):
def _generate_template(self, template, branch, output_path, extra_context):
"""Ensure the named template is up-to-date for the given branch, and roll out
that template.
Expand All @@ -960,13 +962,14 @@ def generate_template(self, template, branch, output_path, extra_context):
self.logger.configure_stdlib_logging("cookiecutter")

try:
# Unroll the template
# Unroll the template. Use a copy of the context to ensure that any
# mocked calls have an unmodified copy.
self.tools.cookiecutter(
str(cached_template),
no_input=True,
output_dir=str(output_path),
checkout=branch,
extra_context=extra_context,
extra_context=extra_context.copy(),
)
except subprocess.CalledProcessError as e:
# Computer is offline
Expand All @@ -979,3 +982,59 @@ def generate_template(self, template, branch, output_path, extra_context):
except cookiecutter_exceptions.RepositoryCloneFailed as e:
# Branch does not exist.
raise TemplateUnsupportedVersion(branch) from e

def generate_template(
self,
template: str | None,
branch: str | None,
output_path: str | Path,
extra_context: dict[str, str],
) -> None:
# If a branch wasn't supplied through the --template-branch argument,
# use the branch derived from the Briefcase version
version = Version(briefcase.__version__)
if branch is None:
template_branch = f"v{version.base_version}"
else:
template_branch = branch

extra_context = extra_context.copy()
# Additional context that can be used for the Briefcase template pyproject.toml
# header to include the version of Briefcase as well as the source of the template.
extra_context.update(
{
"template_source": template,
"template_branch": template_branch,
"briefcase_version": str(version),
}
)

try:
self.logger.info(
f"Using app template: {template}, branch {template_branch}"
)
# Unroll the new app template
self._generate_template(
template=template,
branch=template_branch,
output_path=output_path,
extra_context=extra_context,
)
except TemplateUnsupportedVersion:
# Only use the main template if we're on a development branch of briefcase
# and the user didn't explicitly specify which branch to use.
if version.dev is None or branch is not None:
raise

# Development branches can use the main template.
self.logger.info(
f"Template branch {branch} not found; falling back to development template"
)

extra_context["template_branch"] = "main"
self._generate_template(
template=template,
branch="main",
output_path=output_path,
extra_context=extra_context,
)

0 comments on commit f49c65e

Please sign in to comment.