Source code for reuse.download
# SPDX-FileCopyrightText: 2019 Free Software Foundation Europe e.V. <https://fsfe.org>
# SPDX-FileCopyrightText: 2023 Nico Rikken <nico.rikken@fsfe.org>
#
# SPDX-License-Identifier: GPL-3.0-or-later
"""Functions for downloading license files from spdx/license-list-data."""
import errno
import logging
import os
import shutil
import urllib.request
from pathlib import Path
from urllib.error import URLError
from urllib.parse import urljoin
from ._util import find_licenses_directory
from .extract import _LICENSEREF_PATTERN
from .project import Project
from .types import StrPath
from .vcs import VCSStrategyNone
_LOGGER = logging.getLogger(__name__)
# All raw text files are available as files underneath this path.
_SPDX_REPOSITORY_BASE_URL = (
"https://raw.githubusercontent.com/spdx/license-list-data/master/text/"
)
[docs]
def download_license(spdx_identifier: str) -> str:
"""Download the license text from the SPDX repository.
Args:
spdx_identifier: SPDX identifier of the license.
Raises:
URLError: if the license could not be downloaded.
Returns:
The license text.
"""
# This is fairly naive, but I can't see anything wrong with it.
url = urljoin(_SPDX_REPOSITORY_BASE_URL, "".join((spdx_identifier, ".txt")))
_LOGGER.debug("downloading license from '%s'", url)
# TODO: Cache result?
with urllib.request.urlopen(url) as response:
if response.getcode() == 200:
return response.read().decode("utf-8")
raise URLError("Status code was not 200")
def _path_to_license_file(spdx_identifier: str, project: Project) -> Path:
root: Path | None = project.root
# Hack
if (
root
and root.name == "LICENSES"
and isinstance(project.vcs_strategy, VCSStrategyNone)
):
root = None
licenses_path = find_licenses_directory(root=root)
return licenses_path / "".join((spdx_identifier, ".txt"))
[docs]
def put_license_in_file(
spdx_identifier: str,
destination: StrPath,
source: StrPath | None = None,
) -> None:
"""Download a license and put it in the destination file.
This function exists solely for convenience.
Args:
spdx_identifier: SPDX License Identifier of the license.
destination: Where to put the license.
source: Path to file or directory containing the text for LicenseRef
licenses.
Raises:
URLError: if the license could not be downloaded.
FileExistsError: if the license file already exists.
FileNotFoundError: if the source could not be found in the directory.
"""
header = ""
destination = Path(destination)
destination.parent.mkdir(exist_ok=True)
if destination.exists():
raise FileExistsError(
errno.EEXIST, os.strerror(errno.EEXIST), str(destination)
)
# LicenseRef- license; don't download anything.
if _LICENSEREF_PATTERN.match(spdx_identifier):
if source:
source = Path(source)
if source.is_dir():
source = source / f"{spdx_identifier}.txt"
if not source.exists():
raise FileNotFoundError(
errno.ENOENT, os.strerror(errno.ENOENT), str(source)
)
shutil.copyfile(source, destination)
else:
destination.touch()
else:
text = download_license(spdx_identifier)
with destination.open("w", encoding="utf-8") as fp:
fp.write(header)
fp.write(text)