Skip to content

Commit 1a0f8a4

Browse files
committed
Added: Support for syncing DEP11 files
This change aims to add support for syncing of DEP11 metadata files, enabling the use of application stores like KDE Discover which are based on Appstream.
1 parent 1f8e97f commit 1a0f8a4

File tree

2 files changed

+116
-2
lines changed

2 files changed

+116
-2
lines changed

pulp_deb/app/tasks/publishing.py

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from datetime import datetime, timezone
1010
from debian import deb822
11-
from gzip import GzipFile
11+
import gzip
1212
import tempfile
1313

1414
from django.conf import settings
@@ -23,6 +23,7 @@
2323
PublishedMetadata,
2424
RemoteArtifact,
2525
RepositoryVersion,
26+
ContentArtifact,
2627
)
2728

2829
from pulp_deb.app.constants import NULL_VALUE
@@ -38,6 +39,7 @@
3839
AptReleaseSigningService,
3940
SourcePackage,
4041
SourcePackageReleaseComponent,
42+
GenericContent,
4143
)
4244

4345
from pulp_deb.app.serializers import (
@@ -244,8 +246,54 @@ def publish(
244246
release=release,
245247
temp_dir=temp_dir,
246248
signing_service=signing_service,
249+
dep11_file_paths=[],
247250
)
248251

252+
log.info(f"publish(): looking for dep11 files ...")
253+
dep11_files = GenericContent.objects.filter(
254+
pk__in=repo_version.content.order_by("-pulp_created"),
255+
relative_path__contains="/dep11/"
256+
)
257+
258+
for dep11_file in dep11_files:
259+
release_helper.dep11_file_paths.append(dep11_file.relative_path)
260+
# make sure that there actually are artifacts for dep11 files
261+
try:
262+
artifact = ContentArtifact.objects.get(content_id=dep11_file.content_ptr_id)
263+
except Exception as e:
264+
log.warning(
265+
f"publish(): could not determine artifact for dep11_file {dep11_file}: {e} (skipped processing this artifact)")
266+
continue
267+
268+
artifact_path = f"{settings.MEDIA_ROOT}/{artifact.artifact.file}"
269+
dep11_metadata = PublishedMetadata.create_from_file(
270+
publication=publication,
271+
file=File(open(artifact_path, "rb")),
272+
relative_path=dep11_file.relative_path,
273+
)
274+
dep11_metadata.save()
275+
release_helper.add_metadata(dep11_metadata)
276+
277+
# this is a "hack" because we need a mention of the uncompressed files in the Release file,
278+
# for Appstream to find them
279+
# We normally don't care about the artifact of the uncompressed files but every logic like
280+
# sync and publish relies on the availability of an artifact.
281+
# We also need to decompress those files to avoid hash mismatch errors
282+
if "CID-Index" not in dep11_file.relative_path:
283+
if dep11_file.relative_path.endswith(".gz"):
284+
dep11_file_uncompressed = dep11_file.relative_path.strip(".gz")
285+
with gzip.open(artifact_path, "rb") as f_in:
286+
with open(dep11_file_uncompressed, "wb") as f_out:
287+
shutil.copyfileobj(f_in, f_out)
288+
289+
dep11_metadata_uncompressed = PublishedMetadata.create_from_file(
290+
publication=publication,
291+
file=File(open(dep11_file_uncompressed, "rb")),
292+
relative_path=dep11_file_uncompressed,
293+
)
294+
dep11_metadata_uncompressed.save()
295+
release_helper.add_metadata(dep11_metadata_uncompressed)
296+
249297
package_release_components = PackageReleaseComponent.objects.filter(
250298
pk__in=repo_version.content.order_by("-pulp_created"),
251299
release_component__in=release_components_filtered,
@@ -301,6 +349,8 @@ def __init__(self, parent, component):
301349
self.plain_component = os.path.basename(component)
302350
self.package_index_files = {}
303351
self.source_index_file_info = None
352+
self.dep11_path = None
353+
self.dep11_file_paths = []
304354

305355
for architecture in self.parent.architectures:
306356
package_index_path = os.path.join(
@@ -329,6 +379,15 @@ def __init__(self, parent, component):
329379
source_index_path,
330380
)
331381

382+
# DEP11 directory
383+
self.dep11_dir = os.path.join(
384+
"dists",
385+
self.parent.dists_subfolder,
386+
self.plain_component,
387+
"dep11"
388+
)
389+
os.makedirs(self.dep11_dir, exist_ok=True)
390+
332391
def add_packages(self, packages, artifact_dict, remote_artifact_dict):
333392
published_artifacts = []
334393
package_data = []
@@ -471,6 +530,7 @@ def __init__(
471530
release,
472531
temp_dir,
473532
signing_service=None,
533+
dep11_file_paths=None,
474534
):
475535
self.publication = publication
476536
self.temp_env = {"PULP_TEMP_WORKING_DIR": _create_random_directory(temp_dir)}
@@ -508,6 +568,7 @@ def __init__(
508568
self.architectures = architectures
509569
self.components = {component: _ComponentHelper(self, component) for component in components}
510570
self.signing_service = publication.signing_service or signing_service
571+
self.dep11_file_paths = dep11_file_paths
511572

512573
def add_metadata(self, metadata):
513574
artifact = metadata._artifacts.get()
@@ -573,7 +634,7 @@ def save_signed_metadata(self):
573634
def _zip_file(file_path):
574635
gz_file_path = file_path + ".gz"
575636
with open(file_path, "rb") as f_in:
576-
with GzipFile(gz_file_path, "wb") as f_out:
637+
with gzip.GzipFile(gz_file_path, "wb") as f_out:
577638
shutil.copyfileobj(f_in, f_out)
578639
return gz_file_path
579640

pulp_deb/app/tasks/synchronizing.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,10 @@ async def _handle_component(
843843
pending_tasks.extend(
844844
[self._handle_source_index(release_file, release_component, file_references)]
845845
)
846+
847+
pending_tasks.extend(
848+
[self._handle_dep11_files(release_file, release_component, file_references)]
849+
)
846850
await asyncio.gather(*pending_tasks)
847851

848852
async def _handle_flat_repo(self, file_references, release_file, distribution):
@@ -871,6 +875,55 @@ async def _handle_flat_repo(self, file_references, release_file, distribution):
871875
# Await all tasks
872876
await asyncio.gather(*pending_tasks)
873877

878+
async def _handle_dep11_files(self, release_file, release_component, file_references):
879+
dep11_dir = os.path.join(release_component.plain_component, "dep11")
880+
paths = [path for path in file_references.keys() if path.startswith(dep11_dir)]
881+
882+
if paths:
883+
# CID-Index-amd64.json.gz is missing in file_references (not in Release file)
884+
# Inject it manually?
885+
dep11s = {}
886+
supported_artifacts = [
887+
"CID-Index-amd64.json.gz",
888+
"Components-amd64.yml.gz",
889+
"Components-amd64.yml.xz",
890+
"icons-48x48.tar.gz",
891+
"icons-48x48@2.tar.gz",
892+
"icons-64x64.tar.gz",
893+
"icons-64x64@2.tar.gz",
894+
"icons-128x128.tar.gz",
895+
"icons-128x128@2.tar.gz"
896+
]
897+
898+
for path in paths:
899+
relative_path = os.path.join(os.path.dirname(release_file.relative_path), path)
900+
basename = os.path.basename(relative_path)
901+
902+
if basename not in supported_artifacts:
903+
log.warning(f"_handle_dep11_files: basename={basename} is not in supported artifacts, skipping")
904+
continue
905+
906+
d_artifact = self._to_d_artifact(relative_path, file_references[path])
907+
key = relative_path
908+
909+
if key not in dep11s:
910+
sha256 = d_artifact.artifact.sha256
911+
dep11s[key] = {"sha256": sha256, "d_artifacts": []}
912+
log.warning(f"_handle_dep11_files: adding key={key}, sha256={sha256}")
913+
914+
dep11s[key]["d_artifacts"].append(d_artifact)
915+
916+
# handle CID-Index-amd64.json.gz separately because it is not listed in upstream Release file
917+
cid_file_path = os.path.join(os.path.dirname(release_file.relative_path), dep11_dir, 'CID-Index-amd64.json.gz')
918+
artifact = self._to_d_artifact(cid_file_path)
919+
dep11s[cid_file_path] = {"sha256": artifact.artifact.sha256, "d_artifacts": []}
920+
dep11s[cid_file_path]["d_artifacts"].append(artifact)
921+
for relative_path, dep11 in dep11s.items():
922+
content_unit = GenericContent(sha256=dep11["sha256"], relative_path=relative_path)
923+
await self.put(
924+
DeclarativeContent(content=content_unit, d_artifacts=dep11["d_artifacts"])
925+
)
926+
874927
async def _handle_package_index(
875928
self,
876929
release_file,

0 commit comments

Comments
 (0)