Ejemplo n.º 1
0
    def install(self):
        """
        Download and install WiX.
        """
        try:
            wix_zip_path = self.command.download_url(
                url=WIX_DOWNLOAD_URL,
                download_path=self.command.tools_path,
            )
        except requests_exceptions.ConnectionError:
            raise NetworkFailure("download WiX")

        try:
            print("Installing WiX...")
            # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
            self.command.shutil.unpack_archive(os.fsdecode(wix_zip_path),
                                               extract_dir=os.fsdecode(
                                                   self.wix_home))
        except (shutil.ReadError, EOFError):
            raise BriefcaseCommandError("""
Unable to unpack WiX ZIP file. The download may have been
interrupted or corrupted.

Delete {wix_zip_path} and run briefcase again.""".format(
                wix_zip_path=wix_zip_path))

        # Zip file no longer needed once unpacked.
        wix_zip_path.unlink()
Ejemplo n.º 2
0
    def generate_app_template(self, app: BaseConfig):
        """
        Create an application bundle.

        :param app: The config object for the app
        """
        # If the app config doesn't explicitly define a template,
        # use a default template.
        if app.template is None:
            app.template = self.app_template_url

        print("Using app template: {app_template}".format(
            app_template=app.template,
        ))

        # Make sure we have an updated cookiecutter template,
        # checked out to the right branch
        cached_template = self.update_cookiecutter_cache(
            template=app.template,
            branch=self.python_version_tag
        )

        # Construct a template context from the app configuration.
        extra_context = app.__dict__.copy()
        # Augment with some extra fields.
        extra_context.update({
            # Transformations of explicit properties into useful forms
            'module_name': app.module_name,

            # Properties that are a function of the execution
            'year': date.today().strftime('%Y'),
            'month': date.today().strftime('%B'),
        })

        # Add in any extra template context required by the output format.
        extra_context.update(self.output_format_template_context(app))

        try:
            # Create the platform directory (if it doesn't already exist)
            output_path = self.bundle_path(app).parent
            output_path.mkdir(parents=True, exist_ok=True)
            # Unroll the template
            self.cookiecutter(
                str(cached_template),
                no_input=True,
                output_dir=str(output_path),
                checkout=self.python_version_tag,
                extra_context=extra_context
            )
        except subprocess.CalledProcessError:
            # Computer is offline
            # status code == 128 - certificate validation error.
            raise NetworkFailure("clone template repository")
        except cookiecutter_exceptions.RepositoryNotFound:
            # Either the template path is invalid,
            # or it isn't a cookiecutter template (i.e., no cookiecutter.json)
            raise InvalidTemplateRepository(app.template)
        except cookiecutter_exceptions.RepositoryCloneFailed:
            # Branch does not exist for python version
            raise TemplateUnsupportedVersion(self.python_version_tag)
Ejemplo n.º 3
0
    def install_app_support_package(self, app: BaseConfig):
        """
        Install the application support packge.

        :param app: The config object for the app
        """
        try:
            # Work out if the app defines a custom override for
            # the support package URL.
            try:
                support_package_url = app.support_package
                print("Using custom support package {support_package_url}".
                      format(support_package_url=support_package_url))
            except AttributeError:
                support_package_url = self.support_package_url
                print("Using support package {support_package_url}".format(
                    support_package_url=support_package_url))

            if support_package_url.startswith(
                    'https://') or support_package_url.startswith('http://'):
                try:
                    print(
                        "... pinned to revision {app.support_revision}".format(
                            app=app))
                    # If a revision has been specified, add the revision
                    # as an query argument in the support package URL.
                    # This is a lot more painful than "add arg to query" should
                    # be because (a) url splits aren't appendable, and
                    # (b) Python 3.5 doesn't guarantee dictionary order.
                    url_parts = list(urlsplit(support_package_url))
                    query = []
                    for key, value in parse_qsl(url_parts[3]):
                        query.append((key, value))
                    query.append(('revision', app.support_revision))
                    url_parts[3] = urlencode(query)
                    support_package_url = urlunsplit(url_parts)

                except AttributeError:
                    # No support revision specified.
                    print("... using most recent revision")

                # Download the support file, caching the result
                # in the user's briefcase support cache directory.
                support_filename = self.download_url(
                    url=support_package_url,
                    download_path=self.dot_briefcase_path / 'support')
            else:
                support_filename = Path(support_package_url)
        except requests_exceptions.ConnectionError:
            raise NetworkFailure('downloading support package')

        try:
            print("Unpacking support package...")
            support_path = self.support_path(app)
            support_path.mkdir(parents=True, exist_ok=True)
            self.shutil.unpack_archive(str(support_filename),
                                       extract_dir=str(support_path))
        except (shutil.ReadError, EOFError):
            print()
            raise InvalidSupportPackage(support_package_url)
Ejemplo n.º 4
0
    def install(self):
        """
        Download and install a JDK.
        """
        try:
            jdk_zip_path = self.command.download_url(
                url=self.adoptOpenJDK_download_url,
                download_path=self.command.tools_path,
            )
        except requests_exceptions.ConnectionError:
            raise NetworkFailure("download Java 8 JDK")

        try:
            print("Installing AdoptOpenJDK...")
            # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
            self.command.shutil.unpack_archive(os.fsdecode(jdk_zip_path),
                                               extract_dir=os.fsdecode(
                                                   self.command.tools_path))
        except (shutil.ReadError, EOFError):
            raise BriefcaseCommandError("""\
Unable to unpack AdoptOpenJDK ZIP file. The download may have been interrupted
or corrupted.

Delete {jdk_zip_path} and run briefcase again.""".format(
                jdk_zip_path=jdk_zip_path))
        jdk_zip_path.unlink()  # Zip file no longer needed once unpacked.

        # The tarball will unpack into ~.briefcase/tools/jdk8u242-b08
        # (or whatever name matches the current release).
        # We turn this into ~.briefcase/tools/java so we have a consistent name.
        java_unpack_path = self.command.tools_path / "jdk{self.release}-{self.build}".format(
            self=self)
        java_unpack_path.rename(self.command.tools_path / "java")
Ejemplo n.º 5
0
 def install(self):
     """Download and install linuxdeploy."""
     try:
         linuxdeploy_appimage_path = self.command.download_url(
             url=self.linuxdeploy_download_url,
             download_path=self.command.tools_path)
         self.command.os.chmod(linuxdeploy_appimage_path, 0o755)
         self.patch_elf_header()
     except requests_exceptions.ConnectionError as e:
         raise NetworkFailure("downloading linuxdeploy AppImage") from e
Ejemplo n.º 6
0
    def new_app(self, template: Optional[str] = None, **options):
        """
        Ask questions to generate a new application, and generate a stub
        project from the briefcase-template.
        """
        if template is None:
            template = 'https://github.com/Satireven/milkui-template'
        
        if self.input.enabled:
            print()
            print("Let's build a new MilkUI app!")
            print()

        context = self.build_app_context()

        print()
        print("Generating a new application '{formal_name}'".format(
            **context
        ))

        cached_template = self.update_cookiecutter_cache(
            template=template,
            branch='v0.3'
        )

        # Make extra sure we won't clobber an existing application.
        if (self.base_path / context['app_name']).exists():
            print()
            raise BriefcaseCommandError(
                "A directory named '{app_name}' already exists.".format(
                    **context
                )
            )

        try:
            # Unroll the new app template
            self.cookiecutter(
                str(cached_template),
                no_input=True,
                output_dir=str(self.base_path),
                checkout="v0.3",
                extra_context=context
            )
        except subprocess.CalledProcessError:
            # Computer is offline
            # status code == 128 - certificate validation error.
            raise NetworkFailure("clone template repository")

        print("""
Application '{formal_name}' has been generated. To run your application, type:

    cd {app_name}
    milkui dev
""".format(**context))
Ejemplo n.º 7
0
    def verify_tools(self):
        super().verify_tools()

        try:
            print()
            print("Ensure we have the linuxdeploy AppImage...")
            self.linuxdeploy_appimage = self.download_url(
                url=self.linuxdeploy_download_url,
                download_path=self.dot_briefcase_path / 'tools')
            self.os.chmod(str(self.linuxdeploy_appimage), 0o755)
        except requests_exceptions.ConnectionError:
            raise NetworkFailure('downloading linuxdeploy AppImage')
Ejemplo n.º 8
0
 def install(self):
     """
     Download and install linuxdeploy.
     """
     try:
         linuxdeploy_appimage_path = self.command.download_url(
             url=self.linuxdeploy_download_url,
             download_path=self.command.tools_path
         )
         self.command.os.chmod(str(linuxdeploy_appimage_path), 0o755)
     except requests_exceptions.ConnectionError:
         raise NetworkFailure('downloading linuxdeploy AppImage')
Ejemplo n.º 9
0
    def new_app(self, template: Optional[str] = None, **options):
        """Ask questions to generate a new application, and generate a stub
        project from the briefcase-template."""
        if template is None:
            template = "https://github.com/beeware/briefcase-template"

        self.input.prompt()
        self.input.prompt("Let's build a new Briefcase app!")
        self.input.prompt()

        context = self.build_app_context()

        self.logger.info()
        self.logger.info(
            f"Generating a new application '{context['formal_name']}'")

        cached_template = self.update_cookiecutter_cache(template=template,
                                                         branch="v0.3")

        # Make extra sure we won't clobber an existing application.
        if (self.base_path / context["app_name"]).exists():
            raise BriefcaseCommandError(
                f"A directory named '{context['app_name']}' already exists.")

        try:
            # Unroll the new app template
            self.cookiecutter(
                str(cached_template),
                no_input=True,
                output_dir=os.fsdecode(self.base_path),
                checkout="v0.3",
                extra_context=context,
            )
        except subprocess.CalledProcessError as e:
            # Computer is offline
            # status code == 128 - certificate validation error.
            raise NetworkFailure("clone template repository") from e
        except cookiecutter_exceptions.RepositoryNotFound as e:
            # Either the template path is invalid,
            # or it isn't a cookiecutter template (i.e., no cookiecutter.json)
            raise InvalidTemplateRepository(template) from e

        self.logger.info(f"""
Application '{context['formal_name']}' has been generated. To run your application, type:

    cd {context['app_name']}
    briefcase dev
""")
Ejemplo n.º 10
0
    def install_app_support_package(self, app: BaseConfig):
        """
        Install the application support packge.

        :param app: The config object for the app
        """
        try:
            # Work out if the app defines a custom override for
            # the support package URL.
            try:
                support_package_url = app.support_package
                print("Using custom support package {support_package_url}".format(
                    support_package_url=support_package_url
                ))
            except AttributeError:
                support_package_url = self.support_package_url
                print("Using support package {support_package_url}".format(
                    support_package_url=support_package_url
                ))

            if support_package_url.startswith('https://') or support_package_url.startswith('http://'):
                # Download the support file, caching the result
                # in the user's briefcase support cache directory.
                support_filename = self.download_url(
                    url=support_package_url,
                    download_path=Path.home() / '.briefcase' / 'support'
                )
            else:
                support_filename = support_package_url
        except requests_exceptions.ConnectionError:
            raise NetworkFailure('downloading support package')

        try:
            print("Unpacking support package...")
            support_path = self.support_path(app)
            support_path.mkdir(parents=True, exist_ok=True)
            self.shutil.unpack_archive(
                str(support_filename),
                extract_dir=str(support_path)
            )
        except shutil.ReadError:
            raise InvalidSupportPackage(support_filename.name)
Ejemplo n.º 11
0
    def verify_sdk(self):
        """
        Install the Android SDK if needed.
        """
        tools_path = self.sdk_path / "tools" / "bin"
        sdkmanager_exe = "sdkmanager.exe" if self.host_os == "Windows" else "sdkmanager"
        # This method marks some files as executable, so `tools_ok` checks for
        # that as well. On Windows, all generated files are executable.
        tools_ok = (tools_path.exists() and all([
            self.os.access(str(tool), self.os.X_OK)
            for tool in tools_path.glob("*")
        ]) and (tools_path / sdkmanager_exe).exists())
        if tools_ok:
            return

        print("Setting up Android SDK...")
        try:
            sdk_zip_path = self.download_url(
                url=self.sdk_url,
                download_path=self.dot_briefcase_path / "tools",
            )
        except requests_exceptions.ConnectionError:
            raise NetworkFailure("download Android SDK")
        try:
            with ZipFile(str(sdk_zip_path)) as sdk_zip:
                sdk_zip.extractall(path=str(self.sdk_path))
        except BadZipFile:
            raise BriefcaseCommandError("""\
Unable to unpack Android SDK ZIP file. The download may have been interrupted
or corrupted.

Delete {sdk_zip_path} and run briefcase again.""".format(
                sdk_zip_path=sdk_zip_path))
        sdk_zip_path.unlink()  # Zip file no longer needed once unpacked.
        # `ZipFile` ignores the permission metadata in the Android SDK ZIP
        # file, so we manually fix permissions.
        for binpath in tools_path.glob("*"):
            if not self.os.access(str(binpath), self.os.X_OK):
                binpath.chmod(0o755)
Ejemplo n.º 12
0
    def install(self):
        """
        Download and install the Android SDK.
        """
        try:
            sdk_zip_path = self.command.download_url(
                url=self.sdk_url, download_path=self.command.tools_path,
            )
        except requests_exceptions.ConnectionError:
            raise NetworkFailure("download Android SDK")

        try:
            print("Install Android SDK...")
            # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
            self.command.shutil.unpack_archive(os.fsdecode(sdk_zip_path), extract_dir=os.fsdecode(self.root_path))
        except (shutil.ReadError, EOFError):
            raise BriefcaseCommandError(
                """\
Unable to unpack Android SDK ZIP file. The download may have been interrupted
or corrupted.

Delete {sdk_zip_path} and run briefcase again.""".format(
                    sdk_zip_path=sdk_zip_path
                )
            )

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

        # Python zip unpacking ignores permission metadata.
        # On non-Windows, we manually fix permissions.
        if self.command.host_os != "Windows":
            for binpath in (self.root_path / "tools" / "bin").glob("*"):
                if not self.command.os.access(binpath, self.command.os.X_OK):
                    binpath.chmod(0o755)

        # Licences must be accepted.
        self.verify_license()
Ejemplo n.º 13
0
    def install_app_support_package(self, app: BaseConfig):
        """Install the application support package.

        :param app: The config object for the app
        """
        try:
            # Work out if the app defines a custom override for
            # the support package URL.
            try:
                support_package_url = app.support_package
                custom_support_package = True
                self.logger.info(
                    f"Using custom support package {support_package_url}")
            except AttributeError:
                support_package_url = self.support_package_url
                custom_support_package = False
                self.logger.info(
                    f"Using support package {support_package_url}")

            if support_package_url.startswith(
                    "https://") or support_package_url.startswith("http://"):
                try:
                    self.logger.info(
                        f"... pinned to revision {app.support_revision}")
                    # If a revision has been specified, add the revision
                    # as a query argument in the support package URL.
                    # This is a lot more painful than "add arg to query" should
                    # be because (a) url splits aren't appendable, and
                    # (b) Python 3.5 doesn't guarantee dictionary order.
                    url_parts = list(urlsplit(support_package_url))
                    query = list(parse_qsl(url_parts[3]))
                    query.append(("revision", app.support_revision))
                    url_parts[3] = urlencode(query)
                    support_package_url = urlunsplit(url_parts)

                except AttributeError:
                    # No support revision specified.
                    self.logger.info("... using most recent revision")

                # Download the support file, caching the result
                # in the user's briefcase support cache directory.
                support_filename = self.download_url(
                    url=support_package_url,
                    download_path=self.dot_briefcase_path / "support",
                )
            else:
                support_filename = Path(support_package_url)
        except MissingNetworkResourceError as e:
            # If there is a custom support package, report the missing resource as-is.
            if custom_support_package:
                raise
            else:
                raise MissingSupportPackage(
                    python_version_tag=self.python_version_tag,
                    host_arch=self.host_arch,
                ) from e

        except requests_exceptions.ConnectionError as e:
            raise NetworkFailure("downloading support package") from e
        try:
            self.logger.info("Unpacking support package...")
            support_path = self.support_path(app)
            support_path.mkdir(parents=True, exist_ok=True)
            # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
            self.shutil.unpack_archive(os.fsdecode(support_filename),
                                       extract_dir=os.fsdecode(support_path))
        except (shutil.ReadError, EOFError) as e:
            raise InvalidSupportPackage(support_package_url) from e
Ejemplo n.º 14
0
def verify_jdk(command):
    """
    Verify that a Java 8 JDK exists.

    If ``JAVA_HOME`` is set, try that version. If it is a JRE, or its *not*
    a Java 8 JDK, download one.

    On macOS, also try invoking /usr/libexec/java_home. If that location points
    to a Java 8 JDK, use it.

    Otherwise, download a JDK from AdoptOpenJDK and unpack it into the
    ``~.briefcase`` path.

    :param command: The command that needs to perform the verification check.
    :returns: The value for ``JAVA_HOME``
    """
    java_home = command.os.environ.get('JAVA_HOME', '')
    install_message = None

    # macOS has a helpful system utility to determine JAVA_HOME. Try it.
    if not java_home and command.host_os == 'Darwin':
        try:
            # If no JRE/JDK is installed, /usr/libexec/java_home
            # raises an error.
            java_home = command.subprocess.check_output(
                ['/usr/libexec/java_home'],
                universal_newlines=True,
                stderr=subprocess.STDOUT,
            ).strip('\n')
        except subprocess.CalledProcessError:
            # No java on this machine.
            pass

    if java_home:
        try:
            # If JAVA_HOME is defined, try to invoke javac.
            # This verifies that we have a JDK, not a just a JRE.
            output = command.subprocess.check_output(
                [
                    str(Path(java_home) / 'bin' / 'javac'),
                    '-version',
                ],
                universal_newlines=True,
                stderr=subprocess.STDOUT,
            )
            # This should be a string of the form "javac 1.8.0_144\n"
            version_str = output.strip('\n').split(' ')[1]
            vparts = version_str.split('.')
            if len(vparts) == 3 and vparts[:2] == ['1', '8']:
                # It appears to be a Java 8 JDK.
                return Path(java_home)
            else:
                # It's not a Java 8 JDK.
                java_home = None
                install_message = """
*************************************************************************
** WARNING: JAVA_HOME does not point to a Java 8 JDK                   **
*************************************************************************

    Android requires a Java 8 JDK, but the location pointed to by the
    JAVA_HOME environment variable:

     {java_home}

    isn't a Java 8 JDK (it appears to be Java {version_str}).

    Briefcase will use its own JDK instance.

*************************************************************************

""".format(java_home=java_home, version_str=version_str)

        except FileNotFoundError:
            java_home = None
            install_message = """
*************************************************************************
** WARNING: JAVA_HOME does not point to a JDK                          **
*************************************************************************

    The location pointed to by the JAVA_HOME environment variable:

     {java_home}

    does not appear to be a JDK. It may be a Java Runtime Environment.

    Briefcase will use its own JDK instance.

*************************************************************************

""".format(java_home=java_home)

        except subprocess.CalledProcessError:
            java_home = None
            install_message = """
*************************************************************************
** WARNING: Unable to invoke the Java compiler                         **
*************************************************************************

   Briefcase received an unexpected error when trying to invoke javac,
   the Java compiler, at the location indicated by the JAVA_HOME
   environment variable.

   Briefcase will continue by downloading and using its own JDK.

   Please report this as a bug at:

     https://github.com/beeware/briefcase/issues/new


   In your report, please including the output from running:

     {java_home}/bin/javac -version

   from the command prompt.

*************************************************************************

""".format(java_home=java_home)

        except IndexError:
            java_home = None
            install_message = """
*************************************************************************
** WARNING: Unable to determine the version of Java that is installed  **
*************************************************************************

   Briefcase was unable to interpret the version information returned
   by the Java compiler at the location indicated by the JAVA_HOME
   environment variable.

   Briefcase will continue by downloading and using its own JDK.

   Please report this as a bug at:

     https://github.com/beeware/briefcase/issues/new


   In your report, please including the output from running:

     {java_home}/bin/javac -version

   from the command prompt.

*************************************************************************

""".format(java_home=java_home)

    # If we've reached this point, any user-provided JAVA_HOME is broken;
    # use the Briefcase one.
    java_home = command.dot_briefcase_path / 'tools' / 'java'

    # The macOS download has a weird layout (inherited from the official Oracle
    # release). The actual JAVA_HOME is deeper inside the directory structure.
    if command.host_os == 'Darwin':
        java_home = java_home / 'Contents' / 'Home'

    if (java_home / 'bin').exists():
        # Using briefcase cached Java version
        return java_home

    # We only display the warning messages on the pass where we actually
    # install the JDK.
    if install_message:
        print(install_message)

    print("Obtaining a Java 8 JDK...")

    # As of April 10 2020, 8u242-b08 is the current AdoptOpenJDK
    # https://adoptopenjdk.net/releases.html
    jdk_release = '8u242'
    jdk_build = 'b08'
    jdk_platform = {
        'Darwin': 'mac',
        'Windows': 'windows',
        'Linux': 'linux',
    }.get(command.host_os)
    extension = {
        'Windows': 'zip',
    }.get(command.host_os, 'tar.gz')

    jdk_url = (
        'https://github.com/AdoptOpenJDK/openjdk8-binaries/'
        'releases/download/jdk{jdk_release}-{jdk_build}/'
        'OpenJDK8U-jdk_x64_{jdk_platform}_hotspot_{jdk_release}{jdk_build}.{extension}'
    ).format(
        jdk_release=jdk_release,
        jdk_build=jdk_build,
        jdk_platform=jdk_platform,
        extension=extension,
    )

    try:
        jdk_zip_path = command.download_url(
            url=jdk_url,
            download_path=command.dot_briefcase_path / "tools",
        )
    except requests_exceptions.ConnectionError:
        raise NetworkFailure("download Java 8 JDK")
    try:
        command.shutil.unpack_archive(
            str(jdk_zip_path),
            extract_dir=str(command.dot_briefcase_path / "tools")
        )
    except (shutil.ReadError, EOFError):
        raise BriefcaseCommandError(
            """\
Unable to unpack AdoptOpenJDK ZIP file. The download may have been interrupted
or corrupted.

Delete {jdk_zip_path} and run briefcase again.""".format(
                jdk_zip_path=jdk_zip_path
            )
        )
    jdk_zip_path.unlink()  # Zip file no longer needed once unpacked.

    # The tarball will unpack into ~.briefcase/tools/jdk8u242-b08
    # (or whatever name matches the current release).
    # We turn this into ~.briefcase/tools/java so we have a consistent name.
    java_unpack_path = command.dot_briefcase_path / "tools" / "jdk{jdk_release}-{jdk_build}".format(
        jdk_release=jdk_release,
        jdk_build=jdk_build,
    )
    java_unpack_path.rename(command.dot_briefcase_path / "tools" / "java")
    print()

    return java_home
Ejemplo n.º 15
0
    def create_emulator(self):
        """Create a new Android emulator.

        :returns: The AVD of the newly created emulator.
        """
        # Get the list of existing emulators
        emulators = set(self.emulators())

        default_avd = 'beePhone'
        i = 1
        # Make sure the default name is unique
        while default_avd in emulators:
            i += 1
            default_avd = 'beePhone{i}'.format(i=i)

        # Prompt for a device avd until a valid one is provided.
        print("""
You need to select a name for your new emulator. This is an identifier that
can be used to start the emulator in future. It should follow the same naming
conventions as a Python package (i.e., it may only contain letters, numbers,
hyphens and underscores). If you don't provide a name, Briefcase will use the
a default name '{default_avd}'.

""".format(default_avd=default_avd))
        avd_is_invalid = True
        while avd_is_invalid:
            avd = self.command.input("Emulator name [{default_avd}]: ".format(
                default_avd=default_avd))
            # If the user doesn't provide a name, use the default.
            if avd == '':
                avd = default_avd

            if not PEP508_NAME_RE.match(avd):
                print("""
'{avd}' is not a valid emulator name. An emulator name may only contain
letters, numbers, hyphens and underscores

""".format(avd=avd))
            elif avd in emulators:
                print("""
An emulator named '{avd}' already exists.

""".format(avd=avd))
                print()
            else:
                avd_is_invalid = False

        # TODO: Provide a list of options for device types with matching skins
        device_type = 'pixel'
        skin = 'pixel_3a'

        try:
            print()
            print("Creating Android emulator {avd}...".format(avd=avd))
            print()
            self.command.subprocess.check_output(
                [
                    str(self.avdmanager_path),
                    "--verbose",
                    "create",
                    "avd",
                    "--name",
                    avd,
                    "--abi",
                    "x86",
                    "--package",
                    'system-images;android-28;default;x86',
                    "--device",
                    device_type,
                ],
                env=self.env,
                universal_newlines=True,
                stderr=subprocess.STDOUT,
            )
        except subprocess.CalledProcessError:
            raise BriefcaseCommandError("Unable to create Android emulator")

        # Check for a device skin. If it doesn't exist, download it.
        skin_path = self.root_path / "skins" / skin
        if skin_path.exists():
            print("Device skin '{skin}' already exists".format(skin=skin))
        else:
            print("Obtaining device skin...")
            skin_url = (
                "https://android.googlesource.com/platform/tools/adt/idea/"
                "+archive/refs/heads/mirror-goog-studio-master-dev/"
                "artwork/resources/device-art-resources/{skin}.tar.gz".format(
                    skin=skin))

            try:
                skin_tgz_path = self.command.download_url(
                    url=skin_url,
                    download_path=self.root_path,
                )
            except requests_exceptions.ConnectionError:
                raise NetworkFailure(
                    "download {skin} device skin".format(skin=skin))

            # Unpack skin archive
            try:
                self.command.shutil.unpack_archive(str(skin_tgz_path),
                                                   extract_dir=str(skin_path))
            except (shutil.ReadError, EOFError):
                raise BriefcaseCommandError(
                    "Unable to unpack {skin} device skin".format(skin=skin))

            # Delete the downloaded file.
            skin_tgz_path.unlink()

        print("Adding extra device configuration...")
        with (self.avd_path / '{avd}.avd'.format(avd=avd) /
              'config.ini').open('a') as f:
            f.write("""
disk.dataPartition.size=4096M
hw.keyboard=yes
skin.dynamic=yes
skin.name={skin}
skin.path=skins/{skin}
showDeviceFrame=yes
""".format(skin=skin))

            print("""
Android emulator '{avd}' created.

In future, you can specify this device by running:

    briefcase run android -d @{avd}
""".format(avd=avd))

        return avd
Ejemplo n.º 16
0
def verify_android_sdk(command):
    """
    Verify an Android SDK is available.

    If the ANDROID_SDK_ROOT environment variable is set, that location will
    be checked for a valid SDK.

    If the location provided doesn't contain an SDK, or no location is provided,
    an SDK is downloaded.

    :param command: The command making the verification request.
    :returns: An AndroidSDK instance, bound to command.
    """
    sdk_root = command.os.environ.get("ANDROID_SDK_ROOT")
    if sdk_root:
        sdk = AndroidSDK(command=command, root_path=Path(sdk_root))

        if sdk.exists():
            # Ensure licenses have been accepted
            sdk.verify_license()
            return sdk
        else:
            print("""
*************************************************************************
** WARNING: ANDROID_SDK_ROOT does not point to an Android SDK          **
*************************************************************************

    The location pointed to by the ANDROID_SDK_ROOT environment variable:

     {sdk_root}

    doesn't appear to contain an Android SDK.

    Briefcase will use its own SDK instance.

*************************************************************************

""".format(sdk_root=sdk_root))

    # Build an SDK wrapper for the Briefcase SDK instance.
    sdk = AndroidSDK(command=command,
                     root_path=command.dot_briefcase_path / "tools" /
                     "android_sdk")

    if sdk.exists():
        # Ensure licenses have been accepted
        sdk.verify_license()
        return sdk

    print("Setting up Android SDK...")
    try:
        sdk_zip_path = command.download_url(
            url=sdk.sdk_url,
            download_path=command.dot_briefcase_path / "tools",
        )
    except requests_exceptions.ConnectionError:
        raise NetworkFailure("download Android SDK")
    try:
        command.shutil.unpack_archive(str(sdk_zip_path),
                                      extract_dir=str(sdk.root_path))
    except (shutil.ReadError, EOFError):
        raise BriefcaseCommandError("""\
Unable to unpack Android SDK ZIP file. The download may have been interrupted
or corrupted.

Delete {sdk_zip_path} and run briefcase again.""".format(
            sdk_zip_path=sdk_zip_path))

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

    # Python zip unpacking ignores permission metadata.
    # On non-Windows, we manually fix permissions.
    if command.host_os != "Windows":
        for binpath in (sdk.root_path / "tools" / "bin").glob("*"):
            if not command.os.access(str(binpath), command.os.X_OK):
                binpath.chmod(0o755)

    # Licences must be accepted.
    sdk.verify_license()

    return sdk
Ejemplo n.º 17
0
def verify_wix(command):
    """
    Verify that there is a WiX install available.

    If the WIX environment variable is set, that location will be checked
    for a valid WiX installation.

    If the location provided doesn't contain an SDK, or no location is provided,
    an SDK is downloaded.

    :param command: The command making the verification request.
    :returns: A triple containing the paths to the heat, light, and candle
        executables.
    """
    if command.host_os != 'Windows':
        raise BriefcaseCommandError("""
A Windows MSI installer can only be created on Windows.
""")

    # Look for the WIX environment variable
    wix_env = command.os.environ.get("WIX")
    if wix_env:
        wix_path = Path(wix_env)

        # Set up the paths for the WiX executables we will use.
        wix = WiX(wix_path)

        if not wix.exists():
            raise BriefcaseCommandError("""
The WIX environment variable does not point to an install of the
WiX Toolset. Current value: {wix_path!r}
""".format(wix_path=wix_path))

    else:
        wix_path = command.dot_briefcase_path / 'tools' / 'wix'
        wix = WiX(wix_path, bin_install=True)

        if not wix.exists():
            print("Downloading WiX...")
            try:
                wix_zip_path = command.download_url(
                    url=WIX_DOWNLOAD_URL,
                    download_path=command.dot_briefcase_path / "tools",
                )
            except requests_exceptions.ConnectionError:
                raise NetworkFailure("download WiX")

            try:
                command.shutil.unpack_archive(str(wix_zip_path),
                                              extract_dir=str(wix_path))
            except (shutil.ReadError, EOFError):
                raise BriefcaseCommandError("""
Unable to unpack WiX ZIP file. The download may have been
interrupted or corrupted.

Delete {wix_zip_path} and run briefcase again.""".format(
                    wix_zip_path=wix_zip_path))

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

    return wix