Esempio n. 1
0
    def select_identity(self, identity=None):
        """
        Get the codesigning identity to use.

        :param identity: A pre-specified identity (either the 40-digit
            hex checksum, or the string name of the identity). If provided, it
            will be validated against the list of available identities to
            confirm that it is a valid codesigning identity.
        :returns: The final identity to use
        """
        # Obtain the valid codesigning identities.
        identities = self.get_identities('codesigning')

        if identity:
            try:
                # Try to look up the identity as a hex checksum
                return identities[identity]
            except KeyError:
                # It's not a valid checksum; try to use it as a value.
                if identity in identities.values():
                    return identity

            raise BriefcaseCommandError(
                "Invalid code signing identity {identity!r}".format(
                    identity=identity
                )
            )

        if len(identities) == 0:
            raise BriefcaseCommandError(
                "No code signing identities are available."
            )
        elif len(identities) == 1:
            identity = list(identities.items())[0][1]
        else:
            print()
            print("Select code signing identity to use:")
            print()
            selection = select_option(identities, input=self.input)
            identity = identities[selection]
            print("selected", identity)

        return identity
Esempio n. 2
0
def get_simulators(os_name, sub=subprocess):
    """
    Obtain the simulators available on this machine.

    The return value is a 2 level dictionary. The outer dictionary is
    keyed by OS version; the inner dictionary for each OS version
    contains the details of the available simulators, keyed by UDID.

    :param os_name: The OS that we want to simulate.
        One of `"iOS"`, `"watchOS"`, or `"tvOS"`.
    :param sub: the module for starting subprocesses. Defaults to
        Python's builtin; used for testing purposes.
    :returns: A dictionary of available simulators.
    """
    try:
        simctl_data = json.loads(
            sub.check_output(['xcrun', 'simctl', 'list', '-j'],
                             universal_newlines=True))

        os_versions = {
            runtime['name']: runtime['identifier']
            for runtime in simctl_data['runtimes']
            if runtime['name'].startswith('{os_name} '.format(
                os_name=os_name)) and runtime['isAvailable']
        }

        # For some reason, simctl varies the style of key that is used to
        # identify device versions. The first format is OS identifier (e.g.,
        # 'com.apple.CoreSimulator.SimRuntime.iOS-12-0'). The second is a
        # "human readable" name ('iOS 12.0'). We presume (but can't verify)
        # that any given OS version only exists with a single key.
        # SO - Look for an identifier first; then look for the OS name. If
        # neither exist, return an empty list.
        simulators = {
            version: {
                device['udid']: device['name']
                for device in simctl_data['devices'].get(
                    identifier, simctl_data['devices'].get(version, []))
                if device['isAvailable']
            }
            for version, identifier in os_versions.items()
        }

        # Purge any versions with no devices
        versions_with_no_devices = [
            version for version, devices in simulators.items()
            if len(devices) == 0
        ]
        for version in versions_with_no_devices:
            simulators.pop(version)

        return simulators

    except subprocess.CalledProcessError:
        raise BriefcaseCommandError("Unable to run xcrun simctl.")
Esempio n. 3
0
    def verify(cls, command, install=True):
        """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.
        :param install: Should WiX be installed if it is not found?
        :returns: A valid WiX SDK wrapper. If WiX is not available, and was
            not installed, raises MissingToolError.
        """
        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_home = Path(wix_env)

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

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

        else:
            wix = WiX(command=command, bin_install=True)

            if not wix.exists():
                if install:
                    wix.install()
                else:
                    raise MissingToolError("WiX")

        return wix
Esempio n. 4
0
    def verify_license(self):
        """Verify that all necessary licenses have been accepted.

        If they haven't, prompt the user to do so.

        Raises an error if licenses are not.
        """
        license_path = self.root_path / "licenses" / "android-sdk-license"
        if license_path.exists():
            return

        print(
            "\n"
            + """\
    The Android tools provided by Google have license terms that you must accept
    before you may use those tools.
    """
        )
        try:
            # Using subprocess.run() with no I/O redirection so the user sees
            # the full output and can send input.
            self.command.subprocess.run(
                [os.fsdecode(self.sdkmanager_path), "--licenses"], env=self.env, check=True,
            )
        except subprocess.CalledProcessError:
            raise BriefcaseCommandError(
                """\
    Error while reviewing Android SDK licenses. Please run this command and examine
    its output for errors.

    $ {sdkmanager} --licenses""".format(
                    sdkmanager=self.root_path / "tools" / "bin" / "sdkmanager"
                )
            )

        if not license_path.exists():
            raise BriefcaseCommandError(
                """\
    You did not accept the Android SDK licenses. Please re-run the briefcase command
    and accept the Android SDK license when prompted. You may need an Internet
    connection."""
            )
Esempio n. 5
0
    def __call__(self,
                 appname: Optional[str] = None,
                 update_dependencies: Optional[bool] = False,
                 **kwargs):
        # Confirm all required tools are available
        self.verify_tools()

        # Which app should we run? If there's only one defined
        # in pyproject.toml, then we can use it as a default;
        # otherwise look for a -a/--app option.
        if len(self.apps) == 1:
            app = list(self.apps.values())[0]
        elif appname:
            try:
                app = self.apps[appname]
            except KeyError:
                raise BriefcaseCommandError(
                    "Project doesn't define an application named '{appname}'".
                    format(appname=appname))
        else:
            raise BriefcaseCommandError(
                "Project specifies more than one application; "
                "use --app to specify which one to start.")

        # Look for the existence of a dist-info file.
        # If one exists, assume that the dependencies have already been
        # installed. If a dependency update has been manually requested,
        # do it regardless.
        dist_info_path = self.app_module_path(
            app).parent / '{app.module_name}.dist-info'.format(app=app)
        if update_dependencies or not dist_info_path.exists():
            print()
            print(
                '[{app.app_name}] Installing dependencies...'.format(app=app))
            self.install_dev_dependencies(app, **kwargs)
            write_dist_info(app, dist_info_path)

        print()
        print('[{app.app_name}] Starting in dev mode...'.format(app=app))
        env = self.get_environment(app)
        state = self.run_dev_app(app, env, **kwargs)
        return state
Esempio n. 6
0
    def build_app(self, app: BaseConfig, **kwargs):
        """
        Build an application.

        :param app: The application to build
        """
        print()
        print("[{app.app_name}] Building AppImage...".format(app=app))

        try:
            print()
            # Build the AppImage.
            # For some reason, the version has to be passed in as an
            # environment variable, *not* in the configuration...
            env = {'VERSION': app.version}

            # Find all the .so files in app and app_packages,
            # so they can be passed in to linuxdeploy to have their
            # dependencies added to the AppImage. Looks for any .so file
            # in the application, and make sure it is marked for deployment.
            so_folders = set()
            for so_file in self.appdir_path(app).glob('**/*.so'):
                so_folders.add(so_file.parent)

            deploy_deps_args = []
            for folder in sorted(so_folders):
                deploy_deps_args.extend(["--deploy-deps-only", str(folder)])

            # Build the app image. We use `--appimage-extract-and-run`
            # because AppImages won't run natively inside Docker.
            with self.dockerize(app) as docker:
                docker.run([
                    str(self.linuxdeploy.appimage_path),
                    "--appimage-extract-and-run",
                    "--appdir={appdir_path}".format(
                        appdir_path=self.appdir_path(app)),
                    "-d",
                    str(
                        self.appdir_path(app) /
                        "{app.bundle}.{app.app_name}.desktop".format(
                            app=app, )),
                    "-o",
                    "appimage",
                ] + deploy_deps_args,
                           env=env,
                           check=True,
                           cwd=str(self.platform_path))

            # Make the binary executable.
            self.os.chmod(str(self.binary_path(app)), 0o755)
        except subprocess.CalledProcessError:
            print()
            raise BriefcaseCommandError(
                "Error while building app {app.app_name}.".format(app=app))
Esempio n. 7
0
    def verify_tools(self):
        super().verify_tools()
        if self.host_os != 'Darwin':
            raise BriefcaseCommandError("""
iOS applications require Xcode, which is only available on macOS.
""")

        # Require XCode 10.0.0. There's no particular reason for this
        # specific version, other than it's a nice round number that's
        # not *that* old at time of writing.
        ensure_xcode_is_installed(min_version=(10, 0, 0))
Esempio n. 8
0
    def verify_tools(self):
        """
        Verify that Docker is available; and if it isn't that we're on Linux.
        """
        super().verify_tools()
        if self.use_docker:
            if self.host_os == 'Windows':
                raise BriefcaseCommandError("""
Linux AppImages cannot be generated on Windows.
""")
            else:
                self.Docker = verify_docker(self)
        else:
            if self.host_os == 'Linux':
                # Use subprocess natively. No Docker wrapper is needed
                self.Docker = None
            else:
                raise BriefcaseCommandError("""
Linux AppImages can only be generated on Linux.
""")
Esempio n. 9
0
    def clear_log(self):
        """
        Clear the log for the device.

        Returns `None` on success; raises an exception on failure.
        """
        try:
            # Invoke `adb logcat -c`
            self.run("logcat", "-c")
        except subprocess.CalledProcessError:
            raise BriefcaseCommandError(
                "Unable to clear log on {device}".format(device=self.device, ))
Esempio n. 10
0
    def verify_tools(self):
        if self.host_os != 'Darwin':
            raise BriefcaseCommandError("""
macOS applications require the Xcode command line tools, which are
only available on macOS.
""")
        # Require the XCode command line tools.
        verify_command_line_tools_install(self)

        # Verify superclass tools *after* xcode. This ensures we get the
        # git check *after* the xcode check.
        super().verify_tools()
Esempio n. 11
0
    def verify_tools(self):
        if self.host_os != "Darwin":
            raise BriefcaseCommandError(
                "Code signing and / or building a DMG requires running on macOS."
            )

        # Require the XCode command line tools.
        verify_command_line_tools_install(self)

        # Verify superclass tools *after* xcode. This ensures we get the
        # git check *after* the xcode check.
        super().verify_tools()
Esempio n. 12
0
def ensure_command_line_tools_are_installed(command):
    """Determine if the Xcode command line tools are installed.

    If they are not installed, an exception is raised; in addition, a OS dialog
    will be displayed prompting the user to install Xcode.

    :param command: The command that needs to perform the verification check.
    """
    # We determine if the command line tools are installed by running:
    #
    #   xcode-select --install
    #
    # If that command exits with status 0, it means the tools are *not*
    # installed; but a dialog will be displayed prompting an installation.
    #
    # If it returns a status code of 1, the tools are already installed
    # and outputs the message "command line tools are already installed"
    #
    # Any other status code is a problem.
    try:
        command.subprocess.check_output(["xcode-select", "--install"],
                                        stderr=subprocess.STDOUT)
        raise BriefcaseCommandError("""\
Xcode command line developer tools are not installed.

You should be shown a dialog prompting you to install Xcode and the
command line tools. Select "Install" to install the command line developer
tools.

Re-run Briefcase once that installation is complete.
""")
    except subprocess.CalledProcessError as e:
        if e.returncode != 1:
            command.logger.warning("""
*************************************************************************
** WARNING: Unable to determine if Xcode is installed                  **
*************************************************************************

   Briefcase will proceed, assuming everything is OK. If you experience
   problems, this is almost certainly the cause of those problems.

   Please report this as a bug at:

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

   In your report, please including the output from running:

     xcode-select --install

   from the command prompt.

*************************************************************************
""")
Esempio n. 13
0
    def __call__(self,
                 appname: Optional[str] = None,
                 update: Optional[bool] = False,
                 **kwargs):
        # Confirm all required tools are available
        self.verify_tools()

        # Which app should we run? If there's only one defined
        # in pyproject.toml, then we can use it as a default;
        # otherwise look for a -a/--app option.
        if len(self.apps) == 1:
            app = list(self.apps.values())[0]
        elif appname:
            try:
                app = self.apps[appname]
            except KeyError:
                raise BriefcaseCommandError(
                    "Project doesn't define an application named '{appname}'".
                    format(appname=appname))
        else:
            raise BriefcaseCommandError(
                "Project specifies more than one application; "
                "use --app to specify which one to start.")

        template_file = self.bundle_path(app)
        binary_file = self.binary_path(app)
        if not template_file.exists():
            state = self.create_command(app, **kwargs)
            state = self.build_command(app, **full_kwargs(state, kwargs))
        elif update:
            state = self.update_command(app, **kwargs)
            state = self.build_command(app, **full_kwargs(state, kwargs))
        elif not binary_file.exists():
            state = self.build_command(app, **kwargs)
        else:
            state = None

        state = self.run_app(app, **full_kwargs(state, kwargs))

        return state
Esempio n. 14
0
def test_no_git(update_command):
    "If Git is not installed, an error is raised"
    # Mock a non-existent git
    integrations = mock.MagicMock()
    integrations.git.verify_git_is_installed.side_effect = BriefcaseCommandError(
        "Briefcase requires git, but it is not installed")
    update_command.integrations = integrations

    # The command will fail tool verification.
    with pytest.raises(
            BriefcaseCommandError,
            match=r"Briefcase requires git, but it is not installed"):
        update_command()
Esempio n. 15
0
    def select_identity(self, identity=None):
        """Get the codesigning identity to use.

        :param identity: A pre-specified identity (either the 40-digit
            hex checksum, or the string name of the identity). If provided, it
            will be validated against the list of available identities to
            confirm that it is a valid codesigning identity.
        :returns: The final identity to use
        """
        # Obtain the valid codesigning identities.
        identities = self.get_identities(self, "codesigning")

        if identity:
            try:
                # Try to look up the identity as a hex checksum
                return identities[identity]
            except KeyError as e:
                # Try to look up the identity as readable name
                if identity in identities.values():
                    return identity

                # Not found
                raise BriefcaseCommandError(
                    f"Invalid code signing identity {identity!r}"
                ) from e

        if len(identities) == 0:
            raise BriefcaseCommandError("No code signing identities are available.")
        elif len(identities) == 1:
            identity = list(identities.items())[0][1]
        else:
            self.input.prompt()
            self.input.prompt("Select code signing identity to use:")
            self.input.prompt()
            selection = select_option(identities, input=self.input)
            identity = identities[selection]
            self.logger.info(f"selected {identity}")

        return identity
Esempio n. 16
0
    def verify_tools(self):
        super().verify_tools()
        if self.host_os != 'Windows':
            raise BriefcaseCommandError("""
A Windows MSI installer can only be created on Windows.
""")

        # Look for the WiX environment variable
        wix_path = Path(os.getenv('WIX', ''))

        # Set up the paths for the WiX executables we will use.
        self.heat_exe = wix_path / 'bin' / 'heat.exe'
        self.light_exe = wix_path / 'bin' / 'light.exe'
        self.candle_exe = wix_path / 'bin' / 'candle.exe'
        if not wix_path:
            raise BriefcaseCommandError("""
WiX Toolset is not installed.

Please install the latest stable release from:

    https://wixtoolset.org/

If WiX is already installed, ensure the WIX environment variable has been set,
and that it point to the installed location.

If you're using Windows 10, you may need to enable the .NET 3.5 framework
before installing WiX. Open the Control Panel, select "Programs and Features",
then "Turn Windows features on or off". Ensure ".NET Framework 3.5 (Includes
.NET 2.0 and 3.0)" is enabled.
""")
        elif not (
            self.heat_exe.exists()
            and self.light_exe.exists()
            and self.candle_exe.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))
Esempio n. 17
0
    def app_module_path(self, app):
        """Find the path for the application module for an app.

        :param app: The config object for the app
        :returns: The Path to the dist-info folder.
        """
        app_home = [
            path.split("/") for path in app.sources
            if path.rsplit("/", 1)[-1] == app.module_name
        ]
        try:
            if len(app_home) == 1:
                path = Path(str(self.base_path), *app_home[0])
            else:
                raise BriefcaseCommandError(
                    f"Multiple paths in sources found for application '{app.app_name}'"
                )
        except IndexError as e:
            raise BriefcaseCommandError(
                f"Unable to find code for application '{app.app_name}'") from e

        return path
Esempio n. 18
0
def test_run_app_failed(first_app_config, tmp_path):
    "If there's a problem started the app, an exception is raised"
    command = macOSAppRunCommand(base_path=tmp_path)
    command.subprocess = mock.MagicMock()
    command.subprocess.run.side_effect = BriefcaseCommandError('problem')

    with pytest.raises(BriefcaseCommandError):
        command.run_app(first_app_config)

    # The run command was still invoked, though
    command.subprocess.run.assert_called_with(
        ['open', tmp_path / 'macOS' / 'First App' / 'First App.app'],
        check=True)
Esempio n. 19
0
    def verify_tools(self):
        if self.host_os != "Darwin":
            raise BriefcaseCommandError(
                "macOS applications require the Xcode command line tools, "
                "which are only available on macOS.")
        # Require XCode 10.0.0. There's no particular reason for this
        # specific version, other than it's a nice round number that's
        # not *that* old at time of writing.
        verify_xcode_install(self, min_version=(10, 0, 0))

        # Verify superclass tools *after* xcode. This ensures we get the
        # git check *after* the xcode check.
        super().verify_tools()
Esempio n. 20
0
    def __call__(self, tool_list: List[str], list_tools=False, **options):
        # Verify all the managed SDKs to see which are present.
        managed_tools = {}
        non_managed_tools = set()
        for klass in self.sdks:
            try:
                tool = klass.verify(self, install=False)
                if tool.managed_install:
                    managed_tools[klass.name] = tool
                else:
                    non_managed_tools.add(klass.name)
            except BriefcaseCommandError:
                # Tool doesn't exist, or can't be managed
                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(
                    "Briefcase doesn't know how to manage the tool '{name}'".
                    format(name=name))

        if found_tools:
            if list_tools:
                print("Briefcase is managing the following tools:")
                for name in found_tools:
                    print(" - {name}".format(name=name))
            else:
                print('Briefcase will upgrade the following tools:')
                for name in found_tools:
                    print(" - {name}".format(name=name))
                print()

                for name in found_tools:
                    tool = managed_tools[name]
                    print("[{tool.name}] Upgrading {tool.full_name}...".format(
                        tool=tool))
                    print()
                    tool.upgrade()

                print()

        else:
            print("Briefcase is not managing any tools.")
Esempio n. 21
0
    def has_booted(self):
        """Determine if the device has completed booting.

        :returns True if it has booted; False otherwise.
        """
        try:
            # When the sys.boot_completed property of the device
            # returns '1', the boot is complete. Any other response indicates
            # booting is underway.
            output = self.run('shell', 'getprop', 'sys.boot_completed')
            return output.strip() == '1'
        except subprocess.CalledProcessError:
            raise BriefcaseCommandError(
                "Unable to determine if emulator {device} has booted.".format(
                    device=self.device))
Esempio n. 22
0
def test_run_app_failed(first_app_config, tmp_path):
    "If there's a problem started the app, an exception is raised"
    command = WindowsMSIRunCommand(base_path=tmp_path)
    command.subprocess = mock.MagicMock()
    command.subprocess.run.side_effect = BriefcaseCommandError('problem')

    with pytest.raises(BriefcaseCommandError):
        command.run_app(first_app_config)

    # The run command was still invoked, though
    command.subprocess.run.assert_called_with([
        str(tmp_path / 'windows' / 'msi' / 'First App' / 'src' / 'python' /
            'pythonw.exe'), "-m", "first_app"
    ],
                                              check=True)
Esempio n. 23
0
    def run_dev_app(self, app: BaseConfig, env: dict, **options):
        """Run the app in the dev environment.

        :param app: The config object for the app
        :param env: environment dictionary for sub command
        """
        try:
            # Invoke the app.
            self.subprocess.run(
                [sys.executable, "-m", app.module_name],
                env=env,
                check=True,
            )
        except subprocess.CalledProcessError as e:
            raise BriefcaseCommandError(
                f"Unable to start application '{app.app_name}'") from e
Esempio n. 24
0
    def build_app(self, app: BaseConfig, **kwargs):
        """
        Build an application.

        :param app: The application to build
        """
        print("[{app.app_name}] Building Android APK...".format(app=app))
        try:
            env = {**self.os.environ, "ANDROID_SDK_ROOT": str(self.sdk_path)}
            self.subprocess.run(["./gradlew", "assembleDebug"],
                                env=env,
                                cwd=str(self.bundle_path(app)),
                                check=True)
        except subprocess.CalledProcessError:
            print()
            raise BriefcaseCommandError("Error while building project.")
Esempio n. 25
0
    def verify_tools(self):
        """
        Verify that the tools needed to run this command exist

        Raises MissingToolException if a required system tool is missing.
        """
        # Check whether the git executable could be imported.
        if self.git is None:
            raise BriefcaseCommandError("""
Briefcase requires git, but it is not installed (or is not on your PATH). Visit:

    https://git-scm.com/

to download and install git. If you have installed git recently and are still
getting this error, you may need to restart your terminal session.
""")
Esempio n. 26
0
    def install_apk(self, apk_path):
        """
        Install an APK file on an Android device.

        :param apk_path: The path of the Android APK file to install.

        Returns `None` on success; raises an exception on failure.
        """
        try:
            self.run("install", str(apk_path))
        except subprocess.CalledProcessError:
            raise BriefcaseCommandError(
                "Unable to install APK {apk_path} on {device}".format(
                    apk_path=apk_path,
                    device=self.device,
                ))
Esempio n. 27
0
    def devices(self):
        """Find the devices that are attached and available to ADB

        """
        try:
            # Capture `stderr` so that if the process exits with failure, the
            # stderr data is in `e.output`.
            output = self.command.subprocess.check_output(
                [str(self.adb_path), "devices", "-l"],
                universal_newlines=True,
                stderr=subprocess.STDOUT,
            ).strip()

            # Process the output of `adb devices -l`.
            # The first line is header information.
            # Each subsequent line is a single device descriptor.
            devices = {}
            header_found = False
            for line in output.split("\n"):
                if line == 'List of devices attached':
                    header_found = True
                elif header_found and line:
                    parts = re.sub(r"\s+", " ", line).split(" ")

                    details = {}
                    for part in parts[2:]:
                        key, value = part.split(":")
                        details[key] = value

                    if parts[1] == "device":
                        name = details["model"].replace("_", " ")
                        authorized = True
                    elif parts[1] == "offline":
                        name = "Unknown device (offline)"
                        authorized = False
                    else:
                        name = "Unknown device (not authorized for development)"
                        authorized = False

                    devices[parts[0]] = {
                        "name": name,
                        "authorized": authorized,
                    }

            return devices
        except subprocess.CalledProcessError:
            raise BriefcaseCommandError("Unable to obtain Android device list")
Esempio n. 28
0
def test_run_app_failed(first_app_config, tmp_path):
    "If there's a problem started the app, an exception is raised"
    command = LinuxAppImageRunCommand(base_path=tmp_path)

    # Set the host architecture for test purposes.
    command.host_arch = 'wonky'

    command.subprocess = MagicMock()
    command.subprocess.run.side_effect = BriefcaseCommandError('problem')

    with pytest.raises(BriefcaseCommandError):
        command.run_app(first_app_config)

    # The run command was still invoked, though
    command.subprocess.run.assert_called_with(
        [os.fsdecode(tmp_path / 'linux' / 'First_App-0.0.1-wonky.AppImage')],
        check=True)
Esempio n. 29
0
def get_identities(command, policy):
    """Obtain a set of valid identities for the given policy.

    :param command: The command that needs the identities.
    :param policy: The identity policy to evaluate (e.g., ``codesigning``)
    """
    try:
        output = command.subprocess.check_output(
            ["security", "find-identity", "-v", "-p", policy], )

        return dict(
            IDENTITY_RE.match(line).groups() for line in output.split("\n")
            if IDENTITY_RE.match(line))

    except subprocess.CalledProcessError as e:
        raise BriefcaseCommandError(
            "Unable to run security find-identity.") from e
Esempio n. 30
0
    def avd_name(self):
        """Get the AVD name for the device.

        :returns: The AVD name for the device; or ``None`` if the device isn't
            an emulator
        """
        try:
            output = self.run("emu", "avd", "name")
            return output.split("\n")[0]
        except subprocess.CalledProcessError as e:
            # Status code 1 is a normal "it's not an emulator" error response
            if e.returncode == 1:
                return None
            else:
                raise BriefcaseCommandError(
                    "Unable to interrogate AVD name of device {device}".format(
                        device=self.device))