Example #1
0
    def download_url(self, url, download_path):
        """
        Download a given URL, caching it. If it has already been downloaded,
        return the value that has been cached.

        This is a utility method used to obtain assets used by the
        install process. The cached filename will be the filename portion of
        the URL, appended to the download path.

        :param url: The URL to download
        :param download_path: The path to the download cache folder. This path
            will be created if it doesn't exist.
        :returns: The filename of the downloaded (or cached) file.
        """
        download_path.mkdir(parents=True, exist_ok=True)

        response = self.requests.get(url, stream=True)
        if response.status_code == 404:
            raise MissingNetworkResourceError(url=url, )
        elif response.status_code != 200:
            raise BadNetworkResourceError(url=url,
                                          status_code=response.status_code)

        # The initial URL might (read: will) go through URL redirects, so
        # we need the *final* response. We look at either the `Content-Disposition`
        # header, or the final URL, to extract the cache filename.
        cache_full_name = urlparse(response.url).path
        header_value = response.headers.get('Content-Disposition')
        if header_value:
            # See also https://tools.ietf.org/html/rfc6266
            value, parameters = parse_header(header_value)
            if (value.split(':', 1)[-1].strip().lower() == 'attachment'
                    and parameters.get('filename')):
                cache_full_name = parameters['filename']
        cache_name = cache_full_name.split('/')[-1]
        filename = download_path / cache_name
        if not filename.exists():
            # We have meaningful content, and it hasn't been cached previously,
            # so save it in the requested location
            print('Downloading {cache_name}...'.format(cache_name=cache_name))
            with filename.open('wb') as f:
                total = response.headers.get('content-length')
                if total is None:
                    f.write(response.content)
                else:
                    downloaded = 0
                    total = int(total)
                    for data in response.iter_content(chunk_size=1024 * 1024):
                        downloaded += len(data)
                        f.write(data)
                        done = int(50 * downloaded / total)
                        print('\r{}{} {}%'.format('#' * done,
                                                  '.' * (50 - done), 2 * done),
                              end='',
                              flush=True)
            print()
        else:
            print('{cache_name} already downloaded'.format(
                cache_name=cache_name))
        return filename
Example #2
0
    def download_url(self, url, download_path):
        """Download a given URL, caching it. If it has already been downloaded,
        return the value that has been cached.

        This is a utility method used to obtain assets used by the
        install process. The cached filename will be the filename portion of
        the URL, appended to the download path.

        :param url: The URL to download
        :param download_path: The path to the download cache folder. This path
            will be created if it doesn't exist.
        :returns: The filename of the downloaded (or cached) file.
        """
        download_path.mkdir(parents=True, exist_ok=True)

        response = self.requests.get(url, stream=True)
        if response.status_code == 404:
            raise MissingNetworkResourceError(url=url, )
        elif response.status_code != 200:
            raise BadNetworkResourceError(url=url,
                                          status_code=response.status_code)

        # The initial URL might (read: will) go through URL redirects, so
        # we need the *final* response. We look at either the `Content-Disposition`
        # header, or the final URL, to extract the cache filename.
        cache_full_name = urlparse(response.url).path
        header_value = response.headers.get("Content-Disposition")
        if header_value:
            # See also https://tools.ietf.org/html/rfc6266
            value, parameters = parse_header(header_value)
            if value.split(":", 1)[-1].strip().lower(
            ) == "attachment" and parameters.get("filename"):
                cache_full_name = parameters["filename"]
        cache_name = cache_full_name.split("/")[-1]
        filename = download_path / cache_name
        if not filename.exists():
            # We have meaningful content, and it hasn't been cached previously,
            # so save it in the requested location
            self.logger.info(f"Downloading {cache_name}...")
            with filename.open("wb") as f:
                total = response.headers.get("content-length")
                if total is None:
                    f.write(response.content)
                else:
                    downloaded = 0
                    with self.input.progress_bar(
                            total=int(total)) as progress_bar:
                        for data in response.iter_content(chunk_size=1024 *
                                                          1024):
                            f.write(data)
                            downloaded += len(data)
                            progress_bar.update(completed=downloaded)
        else:
            self.logger.info(f"{cache_name} already downloaded")
        return filename
Example #3
0
    def download_url(self, url, download_path):
        """
        Download a given URL, caching it. If it has already been downloaded,
        return the value that has been cached.

        This is a utility method used to obtain assets used by the
        install process. The cached filename will be the filename portion of
        the URL, appended to the download path.

        :param url: The URL to download
        :param download_path: The path to the download cache folder. This path
            will be created if it doesn't exist.
        :returns: The filename of the downloaded (or cached) file.
        """
        cache_name = urlparse(url).path.split('/')[-1]
        download_path.mkdir(parents=True, exist_ok=True)
        filename = download_path / cache_name

        if not filename.exists():
            response = self.requests.get(url, stream=True)
            if response.status_code == 404:
                raise MissingNetworkResourceError(
                    url=url,
                )
            elif response.status_code != 200:
                raise BadNetworkResourceError(
                    url=url,
                    status_code=response.status_code
                )

            # We have meaningful content, so save it in the requested location
            with filename.open('wb') as f:
                total = response.headers.get('content-length')
                if total is None:
                    f.write(response.content)
                else:
                    downloaded = 0
                    total = int(total)
                    for data in response.iter_content(chunk_size=1024 * 1024):
                        downloaded += len(data)
                        f.write(data)
                        done = int(50 * downloaded / total)
                        print('\r{}{} {}%'.format('#' * done, '.' * (50-done), 2*done), end='', flush=True)
            print()
        else:
            print('{cache_name} already downloaded'.format(cache_name=cache_name))
        return filename
Example #4
0
def test_support_package_url_with_unsupported_platform(create_command, myapp):
    """An unsupported platform raises MissingSupportPackage."""
    # Set the host architecture to something unsupported
    create_command.host_arch = "unknown"

    # Modify download_url to raise an exception due to missing support package
    create_command.download_url = mock.MagicMock(
        side_effect=MissingNetworkResourceError(
            "https://briefcase-support.org/python?platform=tester&version=3.X&arch=unknown"
        ))

    # The unknown platform should cause a missing support package error
    with pytest.raises(MissingSupportPackage):
        create_command.install_app_support_package(myapp)

    # However, there will have a been a download attempt
    create_command.download_url.assert_called_with(
        download_path=create_command.dot_briefcase_path / "support",
        url=
        "https://briefcase-support.org/python?platform=tester&version=3.X&arch=unknown",
    )
Example #5
0
def test_support_package_url_with_invalid_custom_support_packge_url(
        create_command, myapp):
    """Invalid URL for a custom support package raises
    MissingNetworkResourceError."""

    # Provide an custom support URL
    url = "https://example.com/custom/support.zip"
    myapp.support_package = url

    # Modify download_url to raise an exception
    create_command.download_url = mock.MagicMock(
        side_effect=MissingNetworkResourceError(url))

    # The bad URL should raise a MissingNetworkResourceError
    with pytest.raises(MissingNetworkResourceError):
        create_command.install_app_support_package(myapp)

    # However, there will have a been a download attempt
    create_command.download_url.assert_called_with(
        download_path=create_command.dot_briefcase_path / "support",
        url=url,
    )