Coverage for src/lektor_ng/cli/build.py: 0%
50 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-09-05 15:42 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-09-05 15:42 +0000
1# pylint: disable=import-outside-toplevel
2import os
3import sys
4from itertools import chain
5from pathlib import Path
6from lektor_ng.project import Project
7from lektor_ng import cli_utils
8import click
10from lektor_ng.cli_utils import (
11 ResolvedPath,
12)
13from lektor_ng.version import get_version
16def add_options(fn):
17 fn = click.argument(
18 "project_path",
19 type=lambda p: Path(p).expanduser().resolve(),
20 )(fn)
22 fn = click.version_option(prog_name="Lektor", version=get_version())(fn)
24 fn = click.option(
25 "-v",
26 "--verbose",
27 "verbosity",
28 count=True,
29 help="Increases the verbosity of the logging.",
30 )(fn)
32 fn = cli_utils.extraflag(fn)
34 fn = click.option(
35 "--buildstate-path",
36 type=click.Path(writable=True, file_okay=False),
37 default=None,
38 help="Path to a directory that Lektor will use for coordinating "
39 "the state of the build. Defaults to a directory named "
40 "`.lektor` inside the output path.",
41 )(fn)
43 fn = click.option(
44 "--source-info-only",
45 is_flag=True,
46 help="Instead of building only updates the source infos. The "
47 "source info is used by the web admin panel to quickly find "
48 "information about the source files (for instance jump to "
49 "files).",
50 )(fn)
52 fn = cli_utils.pruneflag(fn)
54 fn = click.option(
55 "--watch",
56 is_flag=True,
57 help="If this is enabled the build "
58 "process goes into an automatic loop where it watches the "
59 "file system for changes and rebuilds.",
60 )(fn)
62 fn = click.option(
63 "-O",
64 "--output-path",
65 type=ResolvedPath(writable=True, file_okay=False),
66 default=None,
67 help="The output path.",
68 )(fn)
70 return fn
73@click.command()
74@add_options
75def main(
76 output_path,
77 watch,
78 prune,
79 verbosity,
80 source_info_only,
81 buildstate_path,
82 extra_flags,
83 project_path,
84):
85 """Builds the entire project into the final artifacts.
87 The default behavior is to build the project into the default build
88 output path which can be discovered with the `project-info` command
89 but an alternative output folder can be provided with the `--output-path`
90 option.
92 The default behavior is to perform a build followed by a pruning step
93 which removes no longer referenced artifacts from the output folder.
94 Lektor will only build the files that require rebuilding if the output
95 folder is reused.
97 To enforce a clean build you have to issue a `clean` command first.
99 If the build fails the exit code will be `1` otherwise `0`. This can be
100 used by external scripts to only deploy on successful build for instance.
101 """
102 from lektor_ng.builder import Builder
103 from lektor_ng.reporter import CliReporter
105 project = Project.from_path(project_path)
107 output_path = output_path or os.getenv("LEKTOR_BUILD_OUTPUT_PATH") or project.get_output_path()
109 from lektor_ng.environment import Environment
111 env = Environment(project, load_plugins=False)
113 # TODO re-instate load_plugins
114 from ..pluginsystem import initialize_plugins
116 initialize_plugins(env)
118 with CliReporter(env, verbosity=verbosity):
119 builds = ["first"]
120 if watch:
121 from lektor_ng.watcher import watch_project
123 click.secho("Watching for file system changes", fg="cyan")
124 builds = chain(builds, watch_project(env, output_path, raise_interrupt=False))
126 success = False
127 for _ in builds:
128 builder = Builder(
129 env.new_pad(),
130 output_path,
131 buildstate_path=buildstate_path,
132 extra_flags=extra_flags,
133 )
134 if source_info_only:
135 builder.update_all_source_infos()
136 success = True
137 else:
138 failures = builder.build_all()
139 if prune:
140 builder.prune()
141 success = failures == 0
143 return sys.exit(0 if success else 1)
146if __name__ == "__main__":
147 main()