Skip to content

Commit 9857704

Browse files
committed
add pacakges to command and cli
1 parent d0854e5 commit 9857704

3 files changed

Lines changed: 350 additions & 6 deletions

File tree

src/somesy/cli/sync.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ def sync(
159159
"-P",
160160
help="Pass validation of metadata files (default: False)",
161161
),
162+
packages: Optional[List[Path]] = typer.Option(
163+
None,
164+
"--packages",
165+
"-k",
166+
help="Packages (subfolders) for monorepos with their own somesy config.",
167+
**existing_file_arg_config,
168+
),
162169
):
163170
"""Sync project metadata input with metadata files."""
164171
somesy_input = resolved_somesy_input(
@@ -183,7 +190,9 @@ def sync(
183190
rust_file=rust_file,
184191
merge_codemeta=merge_codemeta,
185192
pass_validation=pass_validation,
193+
packages=packages,
186194
)
195+
187196
run_sync(somesy_input)
188197

189198

src/somesy/commands/sync.py

Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
from somesy.cff.writer import CFF
1010
from somesy.codemeta import CodeMeta
11-
from somesy.core.models import ProjectMetadata, SomesyInput
11+
from somesy.core.core import INPUT_FILES_ORDERED
12+
from somesy.core.models import ProjectMetadata, SomesyConfig, SomesyInput
1213
from somesy.core.writer import ProjectMetadataWriter
1314
from somesy.fortran.writer import Fortran
1415
from somesy.julia.writer import Julia
@@ -40,23 +41,114 @@ def _sync_file(
4041
logger.verbose(f"Saved synced '{file.name}'.\n")
4142

4243

43-
def _sync_files(metadata, files, writer_class, **kwargs):
44+
def _sync_files(
45+
metadata, files, writer_class, create_if_missing: bool = False, **kwargs
46+
):
47+
"""Sync metadata to files using the provided writer.
48+
49+
Args:
50+
metadata: Project metadata to sync
51+
files: Path or list of paths to sync
52+
writer_class: Writer class to use
53+
create_if_missing: Whether to create the file if it doesn't exist
54+
**kwargs: Additional arguments passed to the writer
55+
56+
"""
4457
if isinstance(files, Path):
4558
files = [files]
4659
for file in files:
47-
if file.is_file():
60+
if file.is_file() or create_if_missing:
4861
_sync_file(metadata, file, writer_class, **kwargs)
4962

5063

51-
def sync(somesy_input: SomesyInput):
52-
"""Sync selected metadata files with given input file."""
64+
def sync(somesy_input: SomesyInput, is_package: bool = False):
65+
"""Sync selected metadata files with given input file.
66+
67+
Args:
68+
somesy_input: The input configuration and metadata to sync
69+
is_package: Whether this is a package (subfolder) being synced
70+
71+
"""
5372
conf, metadata = somesy_input.config, somesy_input.project
5473

74+
# Get the base directory from the input file's location
75+
try:
76+
base_dir = somesy_input._origin.parent
77+
except AttributeError:
78+
logger.warning(
79+
"No origin found for somesy input, using current working directory."
80+
)
81+
base_dir = Path.cwd()
82+
83+
# Resolve all paths in the config relative to the base directory
84+
conf.resolve_paths(base_dir)
85+
86+
if is_package:
87+
logger.info("\n[bold green]Synchronizing package metadata...[/bold green]")
88+
else:
89+
logger.info("\n[bold green]Synchronizing root project metadata...[/bold green]")
90+
5591
pp_metadata = pretty_repr(metadata.model_dump(exclude_defaults=True))
5692
logger.debug(f"Project metadata: {pp_metadata}")
5793

94+
# First sync the current project
95+
_sync_root_project(conf, metadata)
96+
97+
# Then sync each package if defined
98+
if conf.packages:
99+
packages = [conf.packages] if isinstance(conf.packages, Path) else conf.packages
100+
for package in packages:
101+
logger.info(f"\n[bold blue]Processing package {package}...[/bold blue]")
102+
103+
# Try all possible input files in order of priority
104+
config_files = [package / file for file in INPUT_FILES_ORDERED]
105+
package_input = None
106+
107+
for config_file in config_files:
108+
try:
109+
package_input = SomesyInput.from_input_file(config_file)
110+
logger.debug(f"Found config file: {config_file}")
111+
break
112+
except (FileNotFoundError, RuntimeError):
113+
continue
114+
115+
if package_input is None:
116+
logger.warning(
117+
f"No valid somesy config found in package {package} "
118+
f"(tried: {', '.join(str(f) for f in config_files)})"
119+
)
120+
continue
121+
122+
# Create new config with CLI options and package's input file
123+
cli_options = {
124+
"no_sync_pyproject": conf.no_sync_pyproject,
125+
"no_sync_package_json": conf.no_sync_package_json,
126+
"no_sync_julia": conf.no_sync_julia,
127+
"no_sync_fortran": conf.no_sync_fortran,
128+
"no_sync_pom_xml": conf.no_sync_pom_xml,
129+
"no_sync_mkdocs": conf.no_sync_mkdocs,
130+
"no_sync_rust": conf.no_sync_rust,
131+
"no_sync_cff": conf.no_sync_cff,
132+
"no_sync_codemeta": conf.no_sync_codemeta,
133+
"merge_codemeta": conf.merge_codemeta,
134+
"pass_validation": conf.pass_validation,
135+
"packages": None, # Don't pass packages to avoid recursive package handling
136+
}
137+
package_input.config = SomesyConfig(input_file=config_file, **cli_options)
138+
139+
# Set default CFF and CodeMeta paths in package directory if not specified
140+
if not package_input.config.no_sync_cff:
141+
package_input.config.cff_file = Path("CITATION.cff")
142+
if not package_input.config.no_sync_codemeta:
143+
package_input.config.codemeta_file = Path("codemeta.json")
144+
145+
# Recursively call sync on the package
146+
sync(package_input, is_package=True)
147+
148+
149+
def _sync_root_project(conf: SomesyConfig, metadata: ProjectMetadata):
150+
"""Sync metadata files for the root project."""
58151
# update these only if they exist:
59-
60152
if conf.pyproject_file and not conf.no_sync_pyproject:
61153
_sync_files(
62154
metadata,
@@ -119,6 +211,7 @@ def sync(somesy_input: SomesyInput):
119211
metadata,
120212
conf.cff_file,
121213
CFF,
214+
create_if_missing=True,
122215
pass_validation=conf.pass_validation,
123216
)
124217

@@ -127,6 +220,7 @@ def sync(somesy_input: SomesyInput):
127220
metadata,
128221
conf.codemeta_file,
129222
CodeMeta,
223+
create_if_missing=True,
130224
merge_codemeta=conf.merge_codemeta,
131225
pass_validation=conf.pass_validation,
132226
)

0 commit comments

Comments
 (0)