Coverage for src/lektor_ng/cli/build.py: 0%

50 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-08-30 13:49 +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 

9 

10from lektor_ng.cli_utils import ( 

11 ResolvedPath, 

12) 

13from lektor_ng.version import get_version 

14 

15 

16def add_options(fn): 

17 fn = click.argument( 

18 "project_path", 

19 type=lambda p: Path(p).expanduser().resolve(), 

20 )(fn) 

21 

22 fn = click.version_option(prog_name="Lektor", version=get_version())(fn) 

23 

24 fn = click.option( 

25 "-v", 

26 "--verbose", 

27 "verbosity", 

28 count=True, 

29 help="Increases the verbosity of the logging.", 

30 )(fn) 

31 

32 fn = cli_utils.extraflag(fn) 

33 

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) 

42 

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) 

51 

52 fn = cli_utils.pruneflag(fn) 

53 

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) 

61 

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) 

69 

70 return fn 

71 

72 

73# TypeError: main() missing 7 required positional arguments: 'output_path', 'watch', 'prune', 'verbosity', 'source_info_only', 'buildstate_path', and 'extra_flags' 

74@click.command() 

75@add_options 

76def main( 

77 output_path, 

78 watch, 

79 prune, 

80 verbosity, 

81 source_info_only, 

82 buildstate_path, 

83 extra_flags, 

84 project_path, 

85): 

86 """Builds the entire project into the final artifacts. 

87 

88 The default behavior is to build the project into the default build 

89 output path which can be discovered with the `project-info` command 

90 but an alternative output folder can be provided with the `--output-path` 

91 option. 

92 

93 The default behavior is to perform a build followed by a pruning step 

94 which removes no longer referenced artifacts from the output folder. 

95 Lektor will only build the files that require rebuilding if the output 

96 folder is reused. 

97 

98 To enforce a clean build you have to issue a `clean` command first. 

99 

100 If the build fails the exit code will be `1` otherwise `0`. This can be 

101 used by external scripts to only deploy on successful build for instance. 

102 """ 

103 from lektor_ng.builder import Builder 

104 from lektor_ng.reporter import CliReporter 

105 

106 project = Project.from_path2(project_path) 

107 

108 output_path = output_path or os.getenv("LEKTOR_BUILD_OUTPUT_PATH") or project.get_output_path() 

109 

110 from lektor_ng.environment import Environment 

111 

112 env = Environment(project, load_plugins=False) 

113 

114 # TODO re-instate load_plugins 

115 from ..pluginsystem import initialize_plugins 

116 

117 initialize_plugins(env) 

118 

119 with CliReporter(env, verbosity=verbosity): 

120 builds = ["first"] 

121 if watch: 

122 from lektor_ng.watcher import watch_project 

123 

124 click.secho("Watching for file system changes", fg="cyan") 

125 builds = chain(builds, watch_project(env, output_path, raise_interrupt=False)) 

126 

127 success = False 

128 for _ in builds: 

129 builder = Builder( 

130 env.new_pad(), 

131 output_path, 

132 buildstate_path=buildstate_path, 

133 extra_flags=extra_flags, 

134 ) 

135 if source_info_only: 

136 builder.update_all_source_infos() 

137 success = True 

138 else: 

139 failures = builder.build_all() 

140 if prune: 

141 builder.prune() 

142 success = failures == 0 

143 

144 return sys.exit(0 if success else 1) 

145 

146 

147if __name__ == "__main__": 

148 main()