in src/buildstream_plugins/sources/_utils.py [0:0]
def download_file(url, etag, directory, auth_scheme):
opener_creator = _UrlOpenerCreator(_parse_netrc())
opener = opener_creator.get_url_opener(auth_scheme == "bearer")
default_name = os.path.basename(url)
request = urllib.request.Request(url)
request.add_header("Accept", "*/*")
request.add_header("User-Agent", "BuildStream/2")
if opener_creator.netrc_config and auth_scheme == "bearer":
parts = urllib.parse.urlsplit(url)
entry = opener_creator.netrc_config.authenticators(parts.hostname)
if entry:
_, _, password = entry
auth_header = "Bearer " + password
request.add_header("Authorization", auth_header)
if etag is not None:
request.add_header("If-None-Match", etag)
try:
with contextlib.closing(opener.open(request)) as response:
info = response.info()
# some servers don't honor the 'If-None-Match' header
if etag and info["ETag"] == etag:
return None, None, None
etag = info["ETag"]
length = info.get("Content-Length")
filename = info.get_filename(default_name)
filename = os.path.basename(filename)
local_file = os.path.join(directory, filename)
with open(local_file, "wb") as dest:
shutil.copyfileobj(response, dest)
actual_length = dest.tell()
if length and actual_length < int(length):
raise ValueError(f"Partial file {actual_length}/{length}")
except urllib.error.HTTPError as e:
if e.code == 304:
# 304 Not Modified.
# Because we use etag only for matching ref, currently specified ref is what
# we would have downloaded.
return None, None, None
return None, None, str(e)
except (urllib.error.URLError, OSError, ValueError) as e:
# Note that urllib.request.Request in the try block may throw a
# ValueError for unknown url types, so we handle it here.
return None, None, str(e)
return local_file, etag, None