Skip to content

Commit be14363

Browse files
authored
Store and serve windows binary downloads for releases (boostorg#1797)
1 parent 9191e16 commit be14363

File tree

4 files changed

+135
-86
lines changed

4 files changed

+135
-86
lines changed

templates/versions/detail.html

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
{% block title %}{% blocktrans with version_name=version.display_name %}Boost {{ version_name }}{% endblocktrans %}{% endblock %}
88
{% block description %}{% blocktrans with version_name=version.display_name %}Discover what's new in Boost {{ version_name }}{% endblocktrans %}{% endblock %}
99
{% block content %}
10-
<main class="content">
10+
<main>
1111
{% if selected_version %}
1212
<div class="py-3 px-3 md:mt-3 md:px-0 mb-0 w-full flex flex-row flex-nowrap items-center"
1313
x-data="{'showSearch': false}"
@@ -29,26 +29,61 @@
2929

3030
<section class="content">
3131
<div class="pb-2 w-full h-auto md:pb-0 md:w-auto">
32-
<div class="flex flex-col">
32+
<div class="flex flex-col h-full max-w-md">
3333
<div class="h-8">
3434
<span class="block pb-1 text-xs md:text-base font-bold">{{ version.release_date|date:"F j, Y" }}</span>
3535
</div>
3636
<div class="-ml-2 h-3"></div>
37-
<div class="-ml-2 h-14">
38-
<a class="block items-center py-1 px-2 rounded cursor-pointer hover:bg-gray-100 dark:hover:bg-slate text-sky-600 dark:text-sky-300 hover:text-orange dark:hover:text-orange"
39-
href="{{ documentation_url }}">
40-
<span class="dark:text-white text-slate">Documentation</span>
41-
<span class="block text-xs">{{ request.scheme }}://{{ request.get_host }}{{ documentation_url }}</span>
42-
</a>
43-
</div>
44-
<div class="-ml-2 h-14">
45-
<a class="block items-center py-1 px-2 rounded cursor-pointer hover:bg-gray-100 dark:hover:bg-slate text-sky-600 dark:text-sky-300 hover:text-orange dark:hover:text-orange"
46-
href="{{ version.github_url }}">
47-
<i class="float-right mt-1 fab fa-github"></i>
48-
<span class="dark:text-white text-slate">Source Code</span>
49-
<span class="block text-xs">{{ version.github_url|cut:"https://" }}</span>
50-
</a>
51-
</div>
37+
<div class="flex flex-col h-full justify-between">
38+
<div>
39+
<div class="-ml-2 h-14">
40+
<a class="block items-center py-1 px-2 rounded cursor-pointer hover:bg-gray-100 dark:hover:bg-slate text-sky-600 dark:text-sky-300 hover:text-orange dark:hover:text-orange"
41+
href="{{ documentation_url }}">
42+
<span class="dark:text-white text-slate">Documentation</span>
43+
<span class="block text-xs">{{ request.scheme }}://{{ request.get_host }}{{ documentation_url }}</span>
44+
</a>
45+
</div>
46+
<div class="-ml-2 h-14">
47+
<a class="block items-center py-1 px-2 rounded cursor-pointer hover:bg-gray-100 dark:hover:bg-slate text-sky-600 dark:text-sky-300 hover:text-orange dark:hover:text-orange"
48+
href="{{ version.github_url }}">
49+
<i class="float-right mt-1 fab fa-github"></i>
50+
<span class="dark:text-white text-slate">Source Code</span>
51+
<span class="block text-xs">{{ version.github_url|cut:"https://" }}</span>
52+
</a>
53+
</div>
54+
</div>
55+
{% if not version.beta %}
56+
{% if deps.added or deps.removed %}
57+
<div class="-ml-2">
58+
<div class="block items-center py-1 px-2">
59+
<span class="dark:text-white text-slate font-semibold">Dependencies</span>
60+
<div class="text-base whitespace-normal">
61+
{% if deps.added %}
62+
There {{ deps.added|pluralize:"was,were" }}
63+
<span class="text-red-700">
64+
{{ deps.added }} dependenc{{ deps.added|pluralize:"y,ies"}} added
65+
</span>
66+
(in {{ deps.increased_dep_lib_count }} librar{{ deps.increased_dep_lib_count|pluralize:"y,ies" }})
67+
{% endif %}
68+
{% if deps.added and deps.removed %}
69+
and
70+
{% endif %}
71+
{% if deps.removed %}
72+
{% if not deps.added %}
73+
There {{ deps.removed|pluralize:"was,were" }}
74+
{% endif %}
75+
<span class="text-[rgb(14,174,96)] dark:text-green">
76+
{{ deps.removed }} dependenc{{ deps.removed|pluralize:"y,ies"}} removed
77+
</span>
78+
(in {{ deps.decreased_dep_lib_count }} librar{{ deps.decreased_dep_lib_count|pluralize:"y,ies" }})
79+
{% endif %}
80+
this release.
81+
</div>
82+
</div>
83+
</div>
84+
</div>
85+
{% endif %}
86+
{% endif %}
5287

5388
</div>
5489
</div>
@@ -80,7 +115,7 @@
80115
{% if forloop.first %}
81116
<th scope="row"
82117
rowspan="{{ download_files|length }}"
83-
class="p-2 h-14 whitespace-nowrap border border-r-0 {% if not forloop.parentloop.last %}border-b-0 {% endif %}border-gray-400 dark:border-slate dark:bg-charcoal text-center">
118+
class="p-2 h-14 whitespace-normal border border-r-0 {% if not forloop.parentloop.last %}border-b-0 {% endif %}border-gray-400 dark:border-slate dark:bg-charcoal text-center">
84119
<i class="fab fa-{% if os == 'Unix' %}linux{% else %}windows{% endif %}"></i> {{ os }}
85120
</th>
86121
{% endif %}
@@ -96,7 +131,7 @@
96131
</svg>
97132
</button>
98133
</td>
99-
<td class="border pr-2 {% if not forloop.last or not forloop.parentloop.last %}border-b-0 {% endif %}border-l-0 border-gray-400 dark:border-slate truncCell dark:bg-charcoal"
134+
<td class="border pr-2 text-xs {% if not forloop.last or not forloop.parentloop.last %}border-b-0 {% endif %}border-l-0 border-gray-400 dark:border-slate truncCell dark:bg-charcoal"
100135
title="{{ download.checksum }}">
101136
<span class="hidden xl:block">{{ download.checksum }}</span>
102137
<span class="hidden md:block xl:hidden">{{ download.checksum|truncate_middle:20 }}</span>
@@ -120,41 +155,6 @@
120155
</section>
121156
{% endif %}
122157

123-
{% if not version.beta %}
124-
{% if deps.added or deps.removed %}
125-
<section id="dependencyChanges"
126-
class="p-6 my-4 bg-white md:rounded-lg md:shadow-lg dark:text-white text-slate dark:bg-charcoal dark:bg-neutral-700">
127-
<h2 class="text-2xl mt-0">Dependencies</h2>
128-
<div>
129-
{% if deps.added %}
130-
There {{ deps.added|pluralize:"was,were" }}
131-
<span class="text-red-700">
132-
{{ deps.added }} dependenc{{ deps.added|pluralize:"y,ies"}} added
133-
</span>
134-
<span>
135-
(in {{ deps.increased_dep_lib_count }} librar{{ deps.increased_dep_lib_count|pluralize:"y,ies" }})
136-
</span>
137-
{% endif %}
138-
{% if deps.added and deps.removed %}
139-
and
140-
{% endif %}
141-
{% if deps.removed %}
142-
{% if not deps.added %}
143-
There {{ deps.removed|pluralize:"was,were" }}
144-
{% endif %}
145-
<span class="text-[rgb(14,174,96)] dark:text-green">
146-
{{ deps.removed }} dependenc{{ deps.removed|pluralize:"y,ies"}} removed
147-
</span>
148-
<span>
149-
(in {{ deps.decreased_dep_lib_count }} librar{{ deps.decreased_dep_lib_count|pluralize:"y,ies" }})
150-
</span>
151-
{% endif %}
152-
this release.
153-
</div>
154-
</section>
155-
{% endif %}
156-
{% endif %}
157-
158158
{% if top_contributors_release %}
159159
<section id="releaseContributors"
160160
class="p-6 my-4 bg-white md:rounded-lg md:shadow-lg dark:text-white text-slate dark:bg-charcoal dark:bg-neutral-700">

versions/management/commands/import_archives_release_data.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
get_archives_download_data,
1010
get_archives_download_uris_for_release,
1111
store_release_downloads_for_version,
12+
get_binaries_download_data,
13+
get_binary_checksums,
14+
get_binary_download_uris_for_release,
1215
)
1316

1417

@@ -32,18 +35,26 @@ def command(release):
3235
for v in versions:
3336
version_num = v.name.replace("boost-", "")
3437
try:
35-
archives_data = get_archives_download_uris_for_release(version_num)
38+
archives_urls = get_archives_download_uris_for_release(version_num)
39+
binaries_urls = get_binary_download_uris_for_release(version_num)
40+
file_urls = archives_urls + binaries_urls
3641
except requests.exceptions.HTTPError:
3742
print(f"Skipping {version_num}, error retrieving release data")
3843
continue
3944

4045
download_data = []
41-
for d in archives_data:
46+
checksums = dict()
47+
for url in file_urls:
4248
try:
43-
data = get_archives_download_data(d)
49+
if "/binaries/" in url:
50+
if not checksums:
51+
checksums = get_binary_checksums(url)
52+
data = get_binaries_download_data(url, checksums)
53+
else:
54+
data = get_archives_download_data(url)
4455
download_data.append(data)
4556
except (requests.exceptions.HTTPError, ValueError):
46-
print(f"Skipping {d}, error retrieving download data")
57+
print(f"Skipping {url}; error retrieving download data")
4758
continue
4859

4960
store_release_downloads_for_version(v, download_data)

versions/releases.py

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,17 @@
2020
session = requests.Session()
2121

2222

23-
def get_archives_download_uris_for_release(release: str = "1.81.0") -> list:
24-
"""Get the download information for a Boost release from the Boost Archives.
25-
26-
Args:
27-
release (str): The Boost release to get download information for. Defaults to
28-
"1.81.0".
29-
30-
Returns:
31-
list: A list of URLs to download the release data from.
32-
"""
33-
file_extensions = [".tar.bz2", ".tar.gz", ".7z", ".zip"]
34-
file_name_excludes = ["_rc"]
35-
36-
if "beta" in release:
37-
release_path = f"{settings.ARCHIVES_URL}beta/{release}/source/"
38-
else:
39-
release_path = f"{settings.ARCHIVES_URL}release/{release}/source/"
23+
def get_download_uris_for_release(
24+
release: str,
25+
subdir: str,
26+
file_extensions: list[str],
27+
file_name_excludes: list[str] = None,
28+
) -> list[str]:
29+
"""Get the download URIs for a Boost release from the Boost Archives."""
30+
file_name_excludes = file_name_excludes or []
31+
32+
release_type = "beta" if "beta" in release else "release"
33+
release_path = f"{settings.ARCHIVES_URL}{release_type}/{release}/{subdir}/"
4034

4135
try:
4236
resp = session.get(release_path)
@@ -47,18 +41,32 @@ def get_archives_download_uris_for_release(release: str = "1.81.0") -> list:
4741
)
4842
raise
4943

50-
# Get the list of archives downloads for this release
5144
soup = BeautifulSoup(resp.text, "html.parser")
52-
uris = []
53-
for a in soup.find_all("a"):
54-
uri = a.get("href")
55-
# Only include the download links with valid file extensions.
56-
if any(uri.endswith(ext) for ext in file_extensions):
57-
# Exclude release candidates
58-
if not any(exclude in uri for exclude in file_name_excludes):
59-
uris.append(f"{release_path}{uri}")
45+
return [
46+
f"{release_path}{a.get('href')}"
47+
for a in soup.find_all("a")
48+
if a.get("href")
49+
and any(a.get("href").endswith(ext) for ext in file_extensions)
50+
and not any(exclude in a.get("href") for exclude in file_name_excludes)
51+
]
52+
53+
54+
def get_archives_download_uris_for_release(release: str = "1.81.0") -> list[str]:
55+
return get_download_uris_for_release(
56+
release=release,
57+
subdir="source",
58+
file_extensions=[".tar.bz2", ".tar.gz", ".7z", ".zip"],
59+
file_name_excludes=["_rc"],
60+
)
6061

61-
return uris
62+
63+
def get_binary_download_uris_for_release(release: str) -> list[str]:
64+
return get_download_uris_for_release(
65+
release=release,
66+
subdir="binaries",
67+
file_extensions=[".exe", ".7z"],
68+
file_name_excludes=["_rc"],
69+
)
6270

6371

6472
def get_artifactory_download_uris_for_release(release: str = "1.81.0") -> list:
@@ -145,6 +153,33 @@ def get_archives_download_data(url):
145153
}
146154

147155

156+
def get_binaries_download_data(url: str, checksums: dict) -> dict:
157+
filename = url.split("/")[-1]
158+
return {
159+
"url": url,
160+
"operating_system": "Windows (Bin)",
161+
"checksum": checksums[filename],
162+
"display_name": filename,
163+
}
164+
165+
166+
def get_binary_checksums(url: str) -> dict:
167+
binaries_url = "/".join(url.split("/")[:-1])
168+
checksum_url = binaries_url + "/SHA256SUMS"
169+
try:
170+
resp = session.get(checksum_url)
171+
resp.raise_for_status()
172+
except requests.exceptions.HTTPError as e:
173+
logger.error("get_binary_checksums", exc_msg=str(e), url=checksum_url)
174+
raise
175+
176+
checksums = {}
177+
for line in resp.text.strip().splitlines():
178+
checksum, filename = line.split(maxsplit=1)
179+
checksums[filename] = checksum
180+
return checksums
181+
182+
148183
def get_artifactory_download_data(url):
149184
"""Get the download information for a Boost release from the Boost artifactory."""
150185
try:

versions/views.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ def get_context_data(self, **kwargs):
5151
context["is_current_release"] = False
5252
return context
5353

54-
downloads = obj.downloads.all().order_by("operating_system")
54+
downloads = obj.downloads.all().order_by("operating_system", "display_name")
55+
for dl in downloads:
56+
dl.operating_system = dl.operating_system.replace("Bin", "Binary")
57+
5558
context["downloads"] = {
5659
k: list(v)
5760
for k, v in groupby(downloads, key=attrgetter("operating_system"))

0 commit comments

Comments
 (0)