Ejemplo n.º 1
0
def test_select_option():
    # Return '3' when prompted
    console = DummyConsole("3")

    options = {
        "first": "The first option",
        "second": "The second option",
        "third": "The third option",
        "fourth": "The fourth option",
    }
    result = select_option(options, input=console)

    # Input is requested once
    assert console.prompts == ["> "]

    # Alphabetically, option 3 will be "the second option"
    assert result == "second"
Ejemplo n.º 2
0
def test_select_option():
    # Return '3' when prompted
    mock_input = mock.MagicMock(return_value='3')

    options = {
        'first': 'The first option',
        'second': 'The second option',
        'third': 'The third option',
        'fourth': 'The fourth option',
    }
    result = select_option(options, input=mock_input)

    # Input is requested once
    assert mock_input.call_count == 1

    # Alphabetically, option 3 will be "the second option"
    assert result == 'second'
Ejemplo n.º 3
0
def test_select_option():
    # Return '3' when prompted
    console = DummyConsole('3')

    options = {
        'first': 'The first option',
        'second': 'The second option',
        'third': 'The third option',
        'fourth': 'The fourth option',
    }
    result = select_option(options, input=console)

    # Input is requested once
    assert console.prompts == ['> ']

    # Alphabetically, option 3 will be "the second option"
    assert result == 'second'
Ejemplo n.º 4
0
def test_select_option_list():
    "If select_option is given a list of tuples, they're presented as provided"
    # Return '3' when prompted
    console = DummyConsole('3')

    options = [
        ('first', 'The first option'),
        ('second', 'The second option'),
        ('third', 'The third option'),
        ('fourth', 'The fourth option'),
    ]
    result = select_option(options, input=console)

    # Input is requested once
    assert console.prompts == ['> ']

    # The third option is the third option :-)
    assert result == 'third'
Ejemplo n.º 5
0
def test_select_option_list():
    """If select_option is given a list of tuples, they're presented as
    provided."""
    # Return '3' when prompted
    console = DummyConsole("3")

    options = [
        ("first", "The first option"),
        ("second", "The second option"),
        ("third", "The third option"),
        ("fourth", "The fourth option"),
    ]
    result = select_option(options, input=console)

    # Input is requested once
    assert console.prompts == ["> "]

    # The third option is the third option :-)
    assert result == "third"
Ejemplo n.º 6
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
Ejemplo n.º 7
0
def test_select_option_bad_input():
    # In order, return:
    #     blank
    #     'asdf'
    #     '10'
    #     '3'
    console = DummyConsole("", "asdf", "10", "3")

    options = {
        "first": "The first option",
        "second": "The second option",
        "third": "The third option",
        "fourth": "The fourth option",
    }
    result = select_option(options, input=console)

    # Input is requested five times; first four cause errors.
    assert console.prompts == ["> "] * 4

    # Alphabetically, option 3 will be "the second option"
    assert result == "second"
Ejemplo n.º 8
0
def test_select_option_bad_input():
    # In order, return:
    #     blank
    #     'asdf'
    #     '10'
    #     '3'
    mock_input = mock.MagicMock(side_effect=['', 'asdf', '10', '3'])

    options = {
        'first': 'The first option',
        'second': 'The second option',
        'third': 'The third option',
        'fourth': 'The fourth option',
    }
    result = select_option(options, input=mock_input)

    # Input is requested five times; first four cause errors.
    assert mock_input.call_count == 4

    # Alphabetically, option 3 will be "the second option"
    assert result == 'second'
Ejemplo n.º 9
0
def test_select_option_bad_input():
    # In order, return:
    #     blank
    #     'asdf'
    #     '10'
    #     '3'
    console = DummyConsole('', 'asdf', '10', '3')

    options = {
        'first': 'The first option',
        'second': 'The second option',
        'third': 'The third option',
        'fourth': 'The fourth option',
    }
    result = select_option(options, input=console)

    # Input is requested five times; first four cause errors.
    assert console.prompts == ['> '] * 4

    # Alphabetically, option 3 will be "the second option"
    assert result == 'second'
Ejemplo n.º 10
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
Ejemplo n.º 11
0
    def select_target_device(self, device_or_avd):
        """
        Select a device to be the target for actions.

        Interrogates the system to get the list of available devices.

        If the user has specified a device at the command line, that device
        will be validated, and then automatically selected.

        :param device_or_avd: The device or AVD to target. Can be a physical
            device id (a hex string), an emulator id ("emulator-5554"), or
            an emulator AVD name ("@robotfriend"). If ``None``, the user will
            be asked to select a device from the list available.
        :returns: A tuple containing ``(device, name, avd)``. ``avd``
            will only be provided if an emulator with that AVD is not currently
            running. If ``device`` is null, a new emulator should be created.
        """
        # Get the list of attached devices (includes running emulators)
        running_devices = self.devices()

        # Choices is an ordered list of options that can be shown to the user.
        # Each device should appear only once, and be keyed by AVD only if
        # a device ID isn't available.
        choices = []
        # Device choices is the full lookup list. Devices can be looked up
        # by any valid key - ID *or* AVD.
        device_choices = {}

        # Iterate over all the running devices.
        # If the device is a virtual device, use ADB to get the emulator AVD name.
        # If it is a physical device, use the device name.
        # Keep a log of all running AVDs
        running_avds = {}
        for d, details in sorted(running_devices.items(),
                                 key=lambda d: d[1]["name"]):
            name = details["name"]
            avd = self.adb(d).avd_name()
            if avd:
                # It's a running emulator
                running_avds[avd] = d
                full_name = "@{avd} (running emulator)".format(avd=avd, )
                choices.append((d, full_name))

                # Save the AVD as a device detail.
                details["avd"] = avd

                # Device can be looked up by device ID or AVD
                device_choices[d] = full_name
                device_choices["@" + avd] = full_name
            else:
                # It's a physical device (might be disabled)
                full_name = "{name} ({d})".format(name=name, d=d)
                choices.append((d, full_name))
                device_choices[d] = full_name

        # Add any non-running emulator AVDs to the list of candidate devices
        for avd in self.emulators():
            if avd not in running_avds:
                name = "@{avd} (emulator)".format(avd=avd)
                choices.append(("@" + avd, name))
                device_choices["@" + avd] = name

        # If a device or AVD has been provided, check it against the available
        # device list.
        if device_or_avd:
            try:
                name = device_choices[device_or_avd]

                if device_or_avd.startswith("@"):
                    # specifier is an AVD
                    try:
                        avd = device_or_avd[1:]
                        device = running_avds[avd]
                    except KeyError:
                        # device_or_avd isn't in the list of running avds;
                        # it must be a non-running emulator.
                        return None, name, avd
                else:
                    # Specifier is a direct device ID
                    avd = None
                    device = device_or_avd

                details = running_devices[device]
                avd = details.get("avd")
                if details["authorized"]:
                    # An authorized, running device (emulator or physical)
                    return device, name, avd
                else:
                    # An unauthorized physical device
                    raise AndroidDeviceNotAuthorized(device)

            except KeyError:
                # Provided device_or_id isn't a valid device identifier.
                if device_or_avd.startswith("@"):
                    id_type = "emulator AVD"
                else:
                    id_type = "device ID"
                raise InvalidDeviceError(id_type, device_or_avd)

        # We weren't given a device/AVD; we have to select from the list.
        # If we're selecting from a list, there's always one last choice
        choices.append((None, "Create a new Android emulator"))

        # Show the choices to the user.
        print()
        print("Select device:")
        print()
        try:
            choice = select_option(choices, input=self.command.input)
        except InputDisabled:
            # If input is disabled, and there's only one actual simulator,
            # select it. If there are no simulators, select "Create simulator"
            if len(choices) <= 2:
                choice = choices[0][0]
            else:
                raise BriefcaseCommandError(
                    "Input has been disabled; can't select a device to target."
                )

        # Proces the user's choice
        if choice is None:
            # Create a new emulator. No device ID or AVD.
            device = None
            avd = None
            name = None
        elif choice.startswith("@"):
            # A non-running emulator. We have an AVD, but no device ID.
            device = None
            name = device_choices[choice]
            avd = choice[1:]
        else:
            # Either a running emulator, or a physical device. Regardless,
            # we need to check if the device is developer enabled
            try:
                details = running_devices[choice]
                if not details["authorized"]:
                    # An unauthorized physical device
                    raise AndroidDeviceNotAuthorized(choice)

                # Return the device ID and name.
                device = choice
                name = device_choices[choice]
                avd = details.get("avd")
            except KeyError:
                raise InvalidDeviceError("device ID", choice)

        if avd:
            print("""
In future, you can specify this device by running:

    briefcase run android -d @{avd}

""".format(avd=avd))
        elif device:
            print("""
In future, you can specify this device by running:

    briefcase run android -d {device}

""".format(device=device))

        return device, name, avd
Ejemplo n.º 12
0
    def select_target_device(self, udid_or_device=None):
        """
        Select the target device to use for iOS builds.

        Interrogates the system to get the list of available simulators

        If there is only a single iOS version available, that version
        will be selected automatically.

        If there is only one simulator available, that version will be selected
        automatically.

        If the user has specified a device at the command line, it will be
        used in preference to any

        :param udid_or_device: The device to target. Can be a device UUID, a
            device name ("iPhone 11"), or a device name and OS version
            ("iPhone 11::13.3"). If ``None``, the user will be asked to select
            a device at runtime.
        :returns: A tuple containing the udid, iOS version, and device name
            for the selected device.
        """
        simulators = self.get_simulators(self, 'iOS')

        try:
            # Try to convert to a UDID. If this succeeds, then the argument
            # is a UDID.
            udid = str(UUID(udid_or_device)).upper()
            # User has provided a UDID at the command line; look for it.
            for iOS_version, devices in simulators.items():
                try:
                    device = devices[udid]
                    return udid, iOS_version, device
                except KeyError:
                    # UDID doesn't exist in this iOS version; try another.
                    pass

            # We've iterated through all available iOS versions and
            # found no match; return an error.
            raise InvalidDeviceError('device UDID', udid)

        except (ValueError, TypeError):
            # Provided value wasn't a UDID.
            # It must be a device or device+version
            if udid_or_device and '::' in udid_or_device:
                # A device name::version.
                device, iOS_version = udid_or_device.split('::')
                try:
                    devices = simulators[iOS_version]
                    try:
                        # Do a reverse lookup for UDID, based on a
                        # case-insensitive name lookup.
                        udid = {
                            name.lower(): udid
                            for udid, name in devices.items()
                        }[device.lower()]

                        # Found a match;
                        # normalize back to the official name and return.
                        device = devices[udid]
                        return udid, iOS_version, device
                    except KeyError:
                        raise InvalidDeviceError('device name', device)
                except KeyError:
                    raise InvalidDeviceError('iOS Version', iOS_version)
            elif udid_or_device:
                # Just a device name
                device = udid_or_device

                # Search iOS versions, looking for most recent version first.
                for iOS_version, devices in sorted(
                        simulators.items(),
                        key=lambda item: tuple(
                            int(v) for v in item[0].split('.')),
                        reverse=True):
                    try:
                        udid = {
                            name.lower(): udid
                            for udid, name in devices.items()
                        }[device.lower()]

                        # Found a match;
                        # normalize back to the official name and return.
                        device = devices[udid]
                        return udid, iOS_version, device
                    except KeyError:
                        # UDID doesn't exist in this iOS version; try another.
                        pass
                raise InvalidDeviceError('device name', device)

        if len(simulators) == 0:
            raise BriefcaseCommandError("No iOS simulators available.")
        elif len(simulators) == 1:
            iOS_version = list(simulators.keys())[0]
        else:
            if self.input.enabled:
                print()
                print("Select iOS version:")
                print()
            iOS_version = select_option(
                {version: version
                 for version in simulators.keys()},
                input=self.input)

        devices = simulators[iOS_version]

        if len(devices) == 0:
            raise BriefcaseCommandError(
                "No simulators available for iOS {iOS_version}.".format(
                    iOS_version=iOS_version))
        elif len(devices) == 1:
            udid = list(devices.keys())[0]
        else:
            if self.input.enabled:
                print()
                print("Select simulator device:")
                print()
            udid = select_option(devices, input=self.input)

        device = devices[udid]

        print("In future, you could specify this device by running:")
        print()
        print('    briefcase {self.command} iOS -d "{device}::{iOS_version}"'.
              format(self=self, device=device, iOS_version=iOS_version))
        print()
        print('or:')
        print()
        print("    briefcase {self.command} iOS -d {udid}".format(self=self,
                                                                  udid=udid))
        return udid, iOS_version, device
Ejemplo n.º 13
0
    def select_target_device(self, udid_or_device=None):
        """Select the target device to use for iOS builds.

        Interrogates the system to get the list of available simulators

        If there is only a single iOS version available, that version
        will be selected automatically.

        If there is only one simulator available, that version will be selected
        automatically.

        If the user has specified a device at the command line, it will be
        used in preference to any

        :param udid_or_device: The device to target. Can be a device UUID, a
            device name ("iPhone 11"), or a device name and OS version
            ("iPhone 11::13.3"). If ``None``, the user will be asked to select
            a device at runtime.
        :returns: A tuple containing the udid, iOS version, and device name
            for the selected device.
        """
        simulators = self.get_simulators(self, "iOS")

        try:
            # Try to convert to a UDID. If this succeeds, then the argument
            # is a UDID.
            udid = str(UUID(udid_or_device)).upper()
            # User has provided a UDID at the command line; look for it.
            for iOS_version, devices in simulators.items():
                try:
                    device = devices[udid]
                    return udid, iOS_version, device
                except KeyError:
                    # UDID doesn't exist in this iOS version; try another.
                    pass

            # We've iterated through all available iOS versions and
            # found no match; return an error.
            raise InvalidDeviceError("device UDID", udid)

        except (ValueError, TypeError) as e:
            # Provided value wasn't a UDID.
            # It must be a device or device+version
            if udid_or_device and "::" in udid_or_device:
                # A device name::version.
                device, iOS_version = udid_or_device.split("::")
                try:
                    # Convert the simulator dict into a dict where
                    # the iOS versions are lower cased, then do a lookup
                    # on the lower case name provided by the user.
                    # However, also return the *unmodified* iOS version string
                    # so we can convert the user-provided iOS version into the
                    # "clean", official capitalization.
                    iOS_version, devices = {
                        clean_iOS_version.lower(): (clean_iOS_version, details)
                        for clean_iOS_version, details in simulators.items()
                    }[iOS_version.lower()]
                    try:
                        # Do a reverse lookup for UDID, based on a
                        # case-insensitive name lookup.
                        udid = {name.lower(): udid for udid, name in devices.items()}[
                            device.lower()
                        ]

                        # Found a match;
                        # normalize back to the official name and return.
                        device = devices[udid]
                        return udid, iOS_version, device
                    except KeyError as e:
                        raise InvalidDeviceError("device name", device) from e
                except KeyError as err:
                    raise InvalidDeviceError("iOS Version", iOS_version) from err
            elif udid_or_device:
                # Just a device name
                device = udid_or_device

                # Search iOS versions, looking for most recent version first.
                # The iOS version string will be something like "iOS 15.4";
                # Drop the prefix (if it exists), convert into the tuple (15, 4),
                # and sort numerically.
                for iOS_version, devices in sorted(
                    simulators.items(),
                    key=lambda item: tuple(
                        int(v) for v in item[0].split()[-1].split(".")
                    ),
                    reverse=True,
                ):
                    try:
                        udid = {name.lower(): udid for udid, name in devices.items()}[
                            device.lower()
                        ]

                        # Found a match;
                        # normalize back to the official name and return.
                        device = devices[udid]
                        return udid, iOS_version, device
                    except KeyError:
                        # UDID doesn't exist in this iOS version; try another.
                        pass
                raise InvalidDeviceError("device name", device) from e

        if len(simulators) == 0:
            raise BriefcaseCommandError("No iOS simulators available.")
        elif len(simulators) == 1:
            iOS_version = list(simulators.keys())[0]
        else:
            self.input.prompt()
            self.input.prompt("Select iOS version:")
            self.input.prompt()
            iOS_version = select_option(
                {version: version for version in simulators.keys()}, input=self.input
            )

        devices = simulators[iOS_version]

        if len(devices) == 0:
            raise BriefcaseCommandError(f"No simulators available for {iOS_version}.")
        elif len(devices) == 1:
            udid = list(devices.keys())[0]
        else:
            self.input.prompt()
            self.input.prompt("Select simulator device:")
            self.input.prompt()
            udid = select_option(devices, input=self.input)

        device = devices[udid]

        self.logger.info(
            f"""
In the future, you could specify this device by running:

    briefcase {self.command} iOS -d "{device}::{iOS_version}"

or:

    briefcase {self.command} iOS -d {udid}
"""
        )
        return udid, iOS_version, device