Skip to content

Commit 41215d3

Browse files
committed
Add 'dump-config' CLI command
1 parent aaa2884 commit 41215d3

5 files changed

Lines changed: 110 additions & 1 deletion

File tree

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ presets = [
4545

4646
## CLI
4747

48-
In virtualenv of your project you can use the following command:
48+
1. In virtualenv of your project you can use the following command:
4949

5050
`python -m finecode run [run_options] <list_of_actions> [actions_payload]`
5151

@@ -68,6 +68,17 @@ Examples:
6868
- `python -m finecode --workdir="./finecode_extension_api" run lint check_formatting` ... run `lint` and `check_formatting` sequentially in `finecode_extension_api` directory (project is there)
6969
- `python -m finecode --project="fine_python_mypy" --project="fine_python_ruff" run lint` ... run `lint` action in projects `fine_python_mypy` and `fine_python_ruff`. They should be discoverable from the working directory.
7070

71+
2. You can dump project config with fully resolved configuration using following command:
72+
73+
`python -m finecode dump-config [--trace] [--project="<project_name>"]`
74+
75+
The result will be saved in `<cwd>/finecode_config_dump/` directory.
76+
77+
Options:
78+
79+
- `--trace` ... activate trace(more detailed) logging
80+
- `--project` ... by default config of project in current working directory is dumped. If current working directory contains multiple projects and you want to dump config of particular one, provide its name using this option
81+
7182
## Extensions from FineCode authors
7283

7384
### Presets

src/finecode/workspace_manager/cli.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from finecode import communication_utils
1111
from finecode.workspace_manager import logger_utils, user_messages
1212
from finecode.workspace_manager.cli_app import run as run_cmd
13+
from finecode.workspace_manager.cli_app import dump_config as dump_config_cmd
1314

1415

1516
@click.group()
@@ -168,5 +169,36 @@ def run(ctx) -> None:
168169
sys.exit(1)
169170

170171

172+
@cli.command()
173+
@click.option("--trace", "trace", is_flag=True, default=False)
174+
@click.option("--debug", "debug", is_flag=True, default=False)
175+
@click.option("--project", "project", type=str)
176+
def dump_config(
177+
trace: bool,
178+
debug: bool,
179+
project: str | None
180+
):
181+
if debug is True:
182+
import debugpy
183+
184+
try:
185+
debugpy.listen(5680)
186+
debugpy.wait_for_client()
187+
except Exception as e:
188+
logger.info(e)
189+
190+
if project is None:
191+
click.echo("--project parameter is required", err=True)
192+
return
193+
194+
logger_utils.init_logger(trace=trace, stdout=True)
195+
196+
try:
197+
asyncio.run(dump_config_cmd.dump_config(workdir_path=pathlib.Path(os.getcwd()), project_name=project))
198+
except dump_config_cmd.DumpFailed as exception:
199+
click.echo(exception.message, err=True)
200+
sys.exit(1)
201+
202+
171203
if __name__ == "__main__":
172204
cli()
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import os
2+
import pathlib
3+
4+
from loguru import logger
5+
6+
from finecode.workspace_manager import context, services
7+
from finecode.workspace_manager.config import read_configs, dump_configs
8+
from finecode.workspace_manager.runner import manager as runner_manager
9+
10+
11+
class DumpFailed(Exception):
12+
def __init__(self, message: str) -> None:
13+
self.message = message
14+
15+
16+
async def dump_config(workdir_path: pathlib.Path, project_name: str):
17+
ws_context = context.WorkspaceContext([workdir_path])
18+
# it could be optimized by looking for concrete project instead of all
19+
await read_configs.read_projects_in_dir(
20+
dir_path=workdir_path, ws_context=ws_context
21+
)
22+
23+
# project is provided. Filter out other projects if there are more, they would
24+
# not be used (run can be started in a workspace with also other projects)
25+
ws_context.ws_projects = {
26+
project_dir_path: project
27+
for project_dir_path, project in ws_context.ws_projects.items()
28+
if project.name == project_name
29+
}
30+
31+
# start runner to init project config
32+
try:
33+
try:
34+
await runner_manager.update_runners(ws_context)
35+
except runner_manager.RunnerFailedToStart as exception:
36+
raise DumpFailed(
37+
f"One or more projects are misconfigured, runners for them didn't"
38+
f" start: {exception.message}. Check logs for details."
39+
)
40+
41+
# Some tools like IDE extensions for syntax highlighting rely on
42+
# file name. Keep file name of config the same and save in subdirectory
43+
project_dir_path = list(ws_context.ws_projects.keys())[0]
44+
dump_dir_path = project_dir_path / 'finecode_config_dump'
45+
dump_file_path = dump_dir_path / 'pyproject.toml'
46+
47+
project_raw_config = ws_context.ws_projects_raw_configs[project_dir_path]
48+
raw_config_str = dump_configs.dump_config(project_raw_config)
49+
50+
os.makedirs(dump_dir_path, exist_ok=True)
51+
with open(dump_file_path, 'w') as dump_file:
52+
dump_file.write(raw_config_str)
53+
54+
logger.info(f"Dumped config into {dump_file_path}")
55+
finally:
56+
services.on_shutdown(ws_context)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import typing
2+
import tomlkit
3+
4+
5+
def dump_config(config: dict[str, typing.Any]) -> str:
6+
return tomlkit.dumps(config)

src/finecode/workspace_manager/config/read_configs.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ async def read_projects_in_dir(
2727
if '__testdata__' in def_file_rel_dir_path.parts:
2828
logger.debug(f"Skip '{def_file}' because it is in test data and it is not a test session")
2929
continue
30+
if def_file.parent.name == 'finecode_config_dump':
31+
logger.debug(f"Skip '{def_file}' because it is config dump, not real project config")
32+
continue
3033

3134
status = domain.ProjectStatus.READY
3235
actions: list[domain.Action] | None = None
@@ -63,6 +66,7 @@ async def read_project_config(
6366
# from it
6467
if project.def_path.name == "pyproject.toml":
6568
with open(project.def_path, "rb") as pyproject_file:
69+
# TODO: handle error if toml is invalid
6670
project_def = toml_loads(pyproject_file.read()).value
6771
# TODO: validate that finecode is installed?
6872

0 commit comments

Comments
 (0)