diff --git a/mkosi/__init__.py b/mkosi/__init__.py index f4766ae712..af57b03b43 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -89,7 +89,7 @@ from mkosi.context import Context from mkosi.distribution import Distribution, detect_distribution from mkosi.documentation import show_docs -from mkosi.installer import clean_package_manager_metadata +from mkosi.installer import clean_package_manager_metadata, package_manager_metadata_to_clean from mkosi.kmod import ( filter_devicetrees, gen_required_kernel_modules, @@ -2604,6 +2604,23 @@ def save_manifest(context: Context, manifest: Optional[Manifest]) -> None: manifest.write_package_report(f) +def save_manifest_to_image(context: Context, manifest: Optional[Manifest]) -> None: + """Write manifest to /usr/lib/mkosi-manifest in the image""" + if package_manager_metadata_to_clean(context): + return + + if not manifest: + return + + if context.config.overlay or context.config.output_format.is_extension_image(): + return + + if ManifestFormat.json in context.config.manifest_format and manifest.has_data(): + osmanifest = context.root / "usr/lib/mkosi-manifest" + with osmanifest.open("w") as f: + manifest.write_json(f) + + def print_output_size(path: Path) -> None: if path.is_dir(): log_step(f"{path} size is " + format_bytes(dir_size(path)) + ".") @@ -4031,6 +4048,8 @@ def build_image(context: Context) -> None: if manifest: manifest.record_packages() + save_manifest_to_image(context, manifest) + save_manifest(context, manifest) run_selinux_relabel(context) @@ -4097,7 +4116,6 @@ def build_image(context: Context) -> None: calculate_sha256sum(context) calculate_signature(context) - save_manifest(context, manifest) output_base = context.staging / context.config.output if not output_base.exists() or output_base.is_symlink(): diff --git a/mkosi/installer/__init__.py b/mkosi/installer/__init__.py index 9ebec1b2c4..3cf07bf436 100644 --- a/mkosi/installer/__init__.py +++ b/mkosi/installer/__init__.py @@ -201,16 +201,24 @@ def clean_package_manager_metadata(context: Context) -> None: Try them all regardless of the distro: metadata is only removed if the package manager is not present in the image. """ + pathsToClean = package_manager_metadata_to_clean(context) + rmtree(*pathsToClean, sandbox=context.sandbox) + + +def package_manager_metadata_to_clean(context: Context) -> list[Path]: + """ + Identifies any metadata paths that should be removed + """ subdir = context.config.distribution.installer.package_manager(context.config).subdir(context.config) if context.config.clean_package_metadata == ConfigFeature.disabled: - return + return [] if context.config.clean_package_metadata == ConfigFeature.auto and context.config.output_format in ( OutputFormat.directory, OutputFormat.tar, ): - return + return [] # If cleaning is not explicitly requested, keep the repository metadata if we're building a directory or # tar image (which are often used as a base tree for extension images and thus should retain package @@ -219,7 +227,7 @@ def clean_package_manager_metadata(context: Context) -> None: executable = context.config.distribution.installer.package_manager(context.config).executable( context.config ) - remove = [] + pathsToClean = [] for tool, paths in ( ("rpm", ["var/lib/rpm", "usr/lib/sysimage/rpm"]), @@ -230,6 +238,6 @@ def clean_package_manager_metadata(context: Context) -> None: if context.config.clean_package_metadata == ConfigFeature.enabled or not find_binary( tool, root=context.root ): - remove += [context.root / p for p in paths if (context.root / p).exists()] + pathsToClean += [context.root / p for p in paths if (context.root / p).exists()] - rmtree(*remove, sandbox=context.sandbox) + return pathsToClean diff --git a/mkosi/resources/man/mkosi.1.md b/mkosi/resources/man/mkosi.1.md index f52c427477..63cb744a5f 100644 --- a/mkosi/resources/man/mkosi.1.md +++ b/mkosi/resources/man/mkosi.1.md @@ -626,6 +626,13 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, text format designed for diffing). By default no manifest is generated. + If a `json` manifest is generated, it is also written to + `/usr/lib/mkosi-manifest` inside the image when all of these are true: + + 1. Metadata is not removed by `CleanPackageMetadata=` + 2. `Format=` is not `sysext`, `confext`, or `addon` + 3. `Overlay=` is not set + `Output=`, `--output=`, `-o` : Name to use for the generated output image file or directory. Defaults to `image` or, if `ImageId=` is specified, it is used as the default