Skip to content

Commit

Permalink
Merge pull request #3585 from DaanDeMeyer/doc
Browse files Browse the repository at this point in the history
  • Loading branch information
DaanDeMeyer authored Mar 7, 2025
2 parents 396bc68 + 75f0b29 commit c8db79c
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 52 deletions.
98 changes: 56 additions & 42 deletions mkosi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3928,10 +3928,7 @@ def build_image(context: Context) -> None:
check_root_populated(context)
run_build_scripts(context)

if context.config.output_format == OutputFormat.none or (
context.args.run_build_scripts
and (context.config.output_dir_or_cwd() / context.config.output).exists()
):
if context.config.output_format == OutputFormat.none or context.args.rerun_build_scripts:
return

if wantrepo:
Expand Down Expand Up @@ -5106,6 +5103,13 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
Verb.sandbox: run_sandbox,
}[args.verb](args, last)

if last.output_format == OutputFormat.none:
if args.verb != Verb.build:
die(f"Cannot run '{args.verb}' verb on image with output format 'none'")

if args.rerun_build_scripts:
die("Cannot use --run-build-scripts on image with output format 'none'")

output = last.output_dir_or_cwd() / last.output_with_compression

if (
Expand All @@ -5114,50 +5118,61 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
and output.exists()
and not output.is_symlink()
and last.output_format != OutputFormat.none
and not args.run_build_scripts
and not args.rerun_build_scripts
):
logging.info(f"Output path {output} exists already. (Use --force to rebuild.)")
return

if args.verb.needs_build():
if args.verb != Verb.build and not args.force and not output.exists():
die(
f"Image '{last.image}' has not been built yet",
hint="Make sure to build the image first with 'mkosi build' or use '--force'",
)
if args.rerun_build_scripts and not output.exists():
die(
f"Image '{last.image}' must be built once before --rerun-build-scripts can be used",
hint="Build the image once with 'mkosi build'",
)

if not last.repart_offline and os.getuid() != 0:
die(f"Must be root to build {last.image} image configured with RepartOffline=no")
if args.verb != Verb.build and not args.force and not output.exists():
die(
f"Image '{last.image}' has not been built yet",
hint="Make sure to build the image first with 'mkosi build' or use '--force'",
)

check_workspace_directory(last)
if not last.repart_offline and os.getuid() != 0:
die(f"Must be root to build {last.image} image configured with RepartOffline=no")

if last.is_incremental():
for a, b in itertools.combinations(images, 2):
if a.expand_key_specifiers(a.cache_key) == b.expand_key_specifiers(b.cache_key):
die(
f"Image {a.image} and {b.image} have the same cache key '{a.expand_key_specifiers(a.cache_key)}'", # noqa: E501
hint="Add the &I specifier to the cache key to avoid this issue",
)
check_workspace_directory(last)

if last.is_incremental() and last.incremental == Incremental.strict:
if args.force > 1:
if args.rerun_build_scripts and not last.is_incremental():
die("Incremental= must be enabled to be able to use --rerun-build-scripts")

if last.is_incremental():
for a, b in itertools.combinations(images, 2):
if a.expand_key_specifiers(a.cache_key) == b.expand_key_specifiers(b.cache_key):
die(
"Cannot remove incremental caches when building with Incremental=strict",
hint="Build once with '-i yes' to update the image cache",
f"Image {a.image} and {b.image} have the same cache key '{a.expand_key_specifiers(a.cache_key)}'", # noqa: E501
hint="Add the &I specifier to the cache key to avoid this issue",
)

for config in images:
if have_cache(config):
continue
if last.is_incremental() and (last.incremental == Incremental.strict or args.rerun_build_scripts):
if args.force > 1:
die(
"Cannot remove incremental caches when building with Incremental=strict",
hint="Build once with '-i yes' to update the image cache",
)

if any((c := config).is_incremental() and not have_cache(config) for config in images):
if args.rerun_build_scripts:
die(
f"Strict incremental mode is enabled and cache for image {config.image} is out-of-date",
f"Cannot use --rerun-build-scripts as the cache for image {c.image} is out-of-date",
hint="Rebuild the image to update the image cache",
)
else:
die(
f"Strict incremental mode is enabled and cache for image {c.image} is out-of-date",
hint="Build once with '-i yes' to update the image cache",
)

# First, process all directory removals because otherwise if different images share directories
# a later image build could end up deleting the output generated by an earlier image build.
if args.verb.needs_build() and (needs_build(args, last) or args.wipe_build_dir):
if needs_build(args, last) or args.wipe_build_dir:
for config in images:
run_clean(args, config)

Expand All @@ -5167,21 +5182,20 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
if args.force > 1 or not have_cache(initrd):
remove_cache_entries(initrd)

for i, config in enumerate(images):
if args.verb != Verb.build:
check_tools(config, args.verb)

images[i] = config = run_configure_scripts(config)
if not have_history(args):
for i, config in enumerate(images):
if args.verb != Verb.build:
check_tools(config, args.verb)

# The images array has been modified so we need to reevaluate last again.
# Also ensure that all other images are reordered in case their dependencies were modified.
last = images[-1]
images[i] = config = run_configure_scripts(config)

if not have_history(args):
# The images array has been modified so we need to reevaluate last again.
# Also ensure that all other images are reordered in case their dependencies were modified.
last = images[-1]
images = resolve_deps(images[:-1], last.dependencies) + [last]

if (
args.run_build_scripts
args.rerun_build_scripts
or last.output_format == OutputFormat.none
or not (last.output_dir_or_cwd() / last.output).exists()
):
Expand Down Expand Up @@ -5233,7 +5247,7 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
# nothing to do so exit early.
if (
config.output_format == OutputFormat.none
or (args.run_build_scripts and (config.output_dir_or_cwd() / config.output).exists())
or (args.rerun_build_scripts and (config.output_dir_or_cwd() / config.output).exists())
) and not config.build_scripts:
continue

Expand Down Expand Up @@ -5267,7 +5281,7 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
if args.auto_bump:
bump_image_version()

if last.history:
if last.history and not args.rerun_build_scripts:
Path(".mkosi-private/history").mkdir(parents=True, exist_ok=True)
Path(".mkosi-private/history/latest.json").write_text(
json.dumps(
Expand Down
9 changes: 6 additions & 3 deletions mkosi/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1697,7 +1697,7 @@ class Args:
doc_format: DocFormat
json: bool
wipe_build_dir: bool
run_build_scripts: bool
rerun_build_scripts: bool

@classmethod
def default(cls) -> "Args":
Expand Down Expand Up @@ -4207,7 +4207,7 @@ def create_argument_parser(chdir: bool = True) -> argparse.ArgumentParser:
)
parser.add_argument(
"-R",
"--run-build-scripts",
"--rerun-build-scripts",
help="Run build scripts even if the image is not rebuilt",
action="store_true",
default=False,
Expand Down Expand Up @@ -4710,7 +4710,7 @@ def have_history(args: Args) -> bool:
return (
args.directory is not None
and args.verb.needs_build()
and args.verb != Verb.build
and (args.verb != Verb.build or args.rerun_build_scripts)
and not args.force
and Path(".mkosi-private/history/latest.json").exists()
)
Expand Down Expand Up @@ -4746,6 +4746,9 @@ def parse_config(
if args.cmdline and not args.verb.supports_cmdline():
die(f"Arguments after verb are not supported for {args.verb}.")

if args.rerun_build_scripts and args.force:
die("--force cannot be used together with --rerun-build-scripts")

# If --debug was passed, apply it as soon as possible.
if ARG_DEBUG.get():
logging.getLogger().setLevel(logging.DEBUG)
Expand Down
19 changes: 14 additions & 5 deletions mkosi/resources/man/mkosi.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,12 @@ Those settings cannot be configured in the configuration files.
`--wipe-build-dir`, `-w`
: Wipe the build directory if one is configured before building the image.

`--rerun-build-scripts`, `-R`
: Rerun build scripts. Requires the `Incremental=` option to be
enabled and the image to have been built once already. If `History=`
is enabled, the config from the previous build will be reused and no
new history will be written.

## Supported output formats

The following output formats are supported:
Expand Down Expand Up @@ -1552,11 +1558,14 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
up in the generated XFS filesystem.

`History=`, `--history=`
: Takes a boolean. If enabled, **mkosi** will write information about the
latest build to the `.mkosi-private` subdirectory in the directory
from which it was invoked. This information is then used to restore
the config of the latest build when running any verb that needs a
build without specifying `--force`.
: Takes a boolean. If enabled, **mkosi** will write information about
the latest build to the `.mkosi-private` subdirectory in the
directory from which it was invoked. This information is then used
to restore the config of the latest build when running any verb that
needs a build without specifying `--force`.

Note that configure scripts will not be executed if we reuse the
history from a previous build.

To give an example of why this is useful, if you run
`mkosi -O my-custom-output-dir -f` followed by `mkosi vm`, **mkosi**
Expand Down
4 changes: 2 additions & 2 deletions tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def test_args(path: Optional[Path]) -> None:
"GenkeyValidDays": "100",
"Json": false,
"Pager": true,
"RunBuildScripts": true,
"RerunBuildScripts": true,
"Verb": "build",
"WipeBuildDir": true
}}
Expand All @@ -88,7 +88,7 @@ def test_args(path: Optional[Path]) -> None:
genkey_valid_days="100",
json=False,
pager=True,
run_build_scripts=True,
rerun_build_scripts=True,
verb=Verb.build,
wipe_build_dir=True,
)
Expand Down

0 comments on commit c8db79c

Please sign in to comment.