deb-mock/mock/py/mockbuild/file_downloader.py
robojerk 4c0dcb2522
Some checks failed
Build Deb-Mock Package / build (push) Successful in 54s
Lint Code / Lint All Code (push) Failing after 1s
Test Deb-Mock Build / test (push) Failing after 36s
enhance: Add comprehensive .gitignore for deb-mock project
- Add mock-specific build artifacts (chroot/, mock-*, mockroot/)
- Include package build files (*.deb, *.changes, *.buildinfo)
- Add development tools (.coverage, .pytest_cache, .tox)
- Include system files (.DS_Store, Thumbs.db, ._*)
- Add temporary and backup files (*.tmp, *.bak, *.backup)
- Include local configuration overrides (config.local.yaml, .env.local)
- Add test artifacts and documentation builds
- Comprehensive coverage for Python build system project

This ensures build artifacts, chroot environments, and development
tools are properly ignored in version control.
2025-08-18 23:37:49 -07:00

96 lines
2.9 KiB
Python

# -*- coding: utf-8 -*-
# vim: noai:ts=4:sw=4:expandtab
from email.message import Message
import shutil
import tempfile
from urllib.parse import urlsplit
import backoff
import requests
from .trace_decorator import getLog
def _filename_from_response(response):
if 'content-disposition' in response.headers:
# https://peps.python.org/pep-0594/#cgi
parser = Message()
parser["content-type"] = response.headers['content-disposition']
if parser.get_param("filename"):
return parser.get_param("filename")
return urlsplit(response.url).path.rsplit('/', 1)[1]
class FileDownloader:
"""
Download files into a temporary storage with automatic cleanup with
cls.cleanup(), remembering both original URL and the local path name.
"""
tmpdir = None
@classmethod
def _initialize(cls):
if cls.tmpdir:
return
cls.backmap = {}
cls.tmpdir = tempfile.mkdtemp()
@classmethod
def get(cls, pkg_url_or_local_file):
"""
If the pkg_url_or_local_file looks like a link, try to download it and
store it to a temporary directory - and return path to the local
downloaded file.
If the pkg_url_or_local_file is not a link, do nothing - just return
the pkg_url_or_local_file argument.
"""
pkg = pkg_url_or_local_file
log = getLog()
url_prefixes = ['http://', 'https://', 'ftp://']
if not any(pkg.startswith(pfx) for pfx in url_prefixes):
log.debug("Local file: %s", pkg)
return pkg
cls._initialize()
try:
log.info('Fetching remote file %s', pkg)
return cls._get_inner(pkg)
except requests.exceptions.RequestException as e:
log.error('Downloading error %s: %s', pkg, str(e))
return None
@classmethod
@backoff.on_exception(backoff.expo, requests.exceptions.RequestException,
max_tries=3, max_time=100)
def _get_inner(cls, url):
req = requests.get(url, timeout=30)
req.raise_for_status()
filename = _filename_from_response(req)
pkg = cls.tmpdir + '/' + filename
with open(pkg, 'wb') as filed:
for chunk in req.iter_content(4096):
filed.write(chunk)
cls.backmap[pkg] = url
return pkg
@classmethod
def original_name(cls, localname):
""" Get the URL from the local name """
if getattr(cls, 'backmap', None):
return cls.backmap.get(localname, localname)
return localname
@classmethod
def cleanup(cls):
""" Remove the temporary storage with downloaded RPMs """
if not cls.tmpdir:
return
getLog().debug("Cleaning the temporary download directory: %s", cls.tmpdir)
cls.backmap = {}
# cleaning up our download dir
shutil.rmtree(cls.tmpdir, ignore_errors=True)
cls.tmpdir = None