Coverage for src/somesy/cli/sync.py: 100%
27 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-03 13:13 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-03 13:13 +0000
1"""Sync command for somesy."""
3import logging
4from pathlib import Path
6import typer
8from somesy.commands import sync as sync_command
9from somesy.commands.sync import SYNC_TARGETS
10from somesy.core.models import SomesyInput
12from .util import (
13 existing_dir_arg_config,
14 existing_file_arg_config,
15 file_arg_config,
16 resolved_somesy_input,
17 wrap_exceptions,
18)
20logger = logging.getLogger("somesy")
22app = typer.Typer()
25@app.callback(invoke_without_command=True)
26@wrap_exceptions
27def sync(
28 input_file: Path | None = typer.Option(
29 None,
30 "--input-file",
31 "-i",
32 help="Somesy input file path (default: discovered)",
33 **file_arg_config,
34 ),
35 no_sync_pyproject: bool | None = typer.Option(
36 None,
37 "--no-sync-pyproject",
38 "-P",
39 help="Do not sync pyproject.toml file (default: False)",
40 ),
41 pyproject_file: list[Path] | None = typer.Option(
42 None,
43 "--pyproject-file",
44 "-p",
45 help="Existing pyproject.toml file path(s) (default: pyproject.toml)",
46 **existing_file_arg_config,
47 ),
48 no_sync_package_json: bool | None = typer.Option(
49 None,
50 "--no-sync-package-json",
51 "-J",
52 help="Do not sync package.json file (default: False)",
53 ),
54 package_json_file: list[Path] | None = typer.Option(
55 None,
56 "--package-json-file",
57 "-j",
58 help="Existing package.json file path(s) (default: package.json)",
59 **existing_file_arg_config,
60 ),
61 no_sync_julia: bool | None = typer.Option(
62 None,
63 "--no-sync-julia",
64 "-L",
65 help="Do not sync Project.toml (Julia) file (default: False)",
66 ),
67 julia_file: list[Path] | None = typer.Option(
68 None,
69 "--julia-file",
70 "-l",
71 help="Custom Project.toml (Julia) file path(s) (default: Project.toml)",
72 **existing_file_arg_config,
73 ),
74 no_sync_fortran: bool | None = typer.Option(
75 None,
76 "--no-sync-fortran",
77 "-F",
78 help="Do not sync fpm.toml (Fortran) file (default: False)",
79 ),
80 fortran_file: list[Path] | None = typer.Option(
81 None,
82 "--fortran-file",
83 "-f",
84 help="Custom fpm.toml (Fortran) file path(s) (default: fpm.toml)",
85 **existing_file_arg_config,
86 ),
87 no_sync_pom_xml: bool | None = typer.Option(
88 None,
89 "--no-sync-pomxml",
90 "-X",
91 help="Do not sync pom.xml (Java Maven) file (default: False)",
92 ),
93 pom_xml_file: list[Path] | None = typer.Option(
94 None,
95 "--pomxml-file",
96 "-x",
97 help="Custom pom.xml (Java Maven) file path(s) (default: pom.xml)",
98 **existing_file_arg_config,
99 ),
100 no_sync_mkdocs: bool | None = typer.Option(
101 None,
102 "--no-sync-mkdocs",
103 "-D",
104 help="Do not sync mkdocs.yml file (default: False)",
105 ),
106 mkdocs_file: list[Path] | None = typer.Option(
107 None,
108 "--mkdocs-file",
109 "-d",
110 help="Custom mkdocs.yml file path(s) (default: mkdocs.yml)",
111 **existing_file_arg_config,
112 ),
113 no_sync_rust: bool | None = typer.Option(
114 None,
115 "--no-sync-rust",
116 "-R",
117 help="Do not sync Cargo.toml file (default: False)",
118 ),
119 rust_file: list[Path] | None = typer.Option(
120 None,
121 "--rust-file",
122 "-r",
123 help="Custom Cargo.toml file path(s) (default: Cargo.toml)",
124 **existing_file_arg_config,
125 ),
126 no_sync_cff: bool | None = typer.Option(
127 None,
128 "--no-sync-cff",
129 "-C",
130 help="Do not sync CITATION.cff file (default: False)",
131 ),
132 cff_file: list[Path] | None = typer.Option(
133 None,
134 "--cff-file",
135 "-c",
136 help="CITATION.cff file path(s) (default: CITATION.cff)",
137 **file_arg_config,
138 ),
139 no_sync_codemeta: bool | None = typer.Option(
140 None,
141 "--no-sync-codemeta",
142 "-M",
143 help="Do not sync codemeta.json file (default: False)",
144 ),
145 codemeta_file: list[Path] | None = typer.Option(
146 None,
147 "--codemeta-file",
148 "-m",
149 help="Custom codemeta.json file path(s) (default: codemeta.json)",
150 **file_arg_config,
151 ),
152 merge_codemeta: bool | None = typer.Option(
153 False,
154 "--merge/--overwrite",
155 help="Merge codemeta.json with with an existing codemeta.json file (default: False)",
156 ),
157 pass_validation: bool | None = typer.Option(
158 False,
159 "--pass-validation",
160 "-V",
161 help="Allow incomplete input and pass output validation (default: False)",
162 ),
163 packages: list[Path] | None = typer.Option(
164 None,
165 "--packages",
166 "-k",
167 help="Packages (subfolders) for monorepos with their own somesy config.",
168 **existing_dir_arg_config,
169 ),
170):
171 """Sync project metadata input with metadata files."""
172 somesy_input = resolved_somesy_input(
173 input_file=input_file,
174 no_sync_cff=no_sync_cff,
175 cff_file=cff_file,
176 no_sync_pyproject=no_sync_pyproject,
177 pyproject_file=pyproject_file,
178 no_sync_package_json=no_sync_package_json,
179 package_json_file=package_json_file,
180 no_sync_codemeta=no_sync_codemeta,
181 codemeta_file=codemeta_file,
182 no_sync_julia=no_sync_julia,
183 julia_file=julia_file,
184 no_sync_fortran=no_sync_fortran,
185 fortran_file=fortran_file,
186 no_sync_pom_xml=no_sync_pom_xml,
187 pom_xml_file=pom_xml_file,
188 no_sync_mkdocs=no_sync_mkdocs,
189 mkdocs_file=mkdocs_file,
190 no_sync_rust=no_sync_rust,
191 rust_file=rust_file,
192 merge_codemeta=merge_codemeta,
193 pass_validation=pass_validation,
194 packages=packages,
195 )
197 run_sync(somesy_input)
200def run_sync(somesy_input: SomesyInput):
201 """Write log messages and run synchronization based on passed config."""
202 conf = somesy_input.config
203 logger.info("[bold green]Synchronizing project metadata...[/bold green]")
204 logger.info("Files to sync:")
205 for target in SYNC_TARGETS:
206 if not getattr(conf, f"no_sync_{target.key}"):
207 files = getattr(conf, f"{target.key}_file")
208 gap = "\n" if target.log_gap else ""
209 logger.info(
210 f" - [italic]{target.label}[/italic]:\t[grey]{files}[/grey]{gap}"
211 )
212 # ----
213 if conf.pass_validation:
214 logger.info("[bold yellow]Passing validation of metadata files.[/bold yellow]")
215 sync_command(somesy_input)
216 # ----
217 logger.info("[bold green]Metadata synchronization completed.[/bold green]")