Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion README.cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ ecc status --project gcd
ecc log --project gcd
```

默认情况下,具名 workspace 创建在 `<project>/<workspace-id>`。如需在项目外部的
精确目录创建 workspace,请同时提供 workspace ID 和绝对 `--path`:

```bash
ecc run --project gcd --workspace experiment --path /data/ecc/gcd/experiment
ecc workspace import recovered --project gcd --path /archive/ecc/gcd/recovered
ecc run --project gcd --workspace recovered --resume
```

规范路径会登记到 `project.json`;后续命令只需使用 workspace ID,无需重复传入
`--path`。

## CLI 命令

运行 `ecc --help`(或 `ecc <command> --help`)查看完整用法。常用命令:
Expand All @@ -154,7 +166,7 @@ ecc log --project gcd
| `ecc param` | 管理参数覆盖(`list`、`show`、`set`、`unset`、`diff`) |
| `ecc pdk` | 管理 PDK 路径(`set-root`、`show`、`unset`) |
| `ecc project` | 编辑 `ecc.toml` 中的项目声明(`set`、`unset`、`add`、`remove`、`show`) |
| `ecc workspace` | 从项目配置刷新受管 workspace |
| `ecc workspace` | 导入已有 workspace,或从项目配置刷新受管 workspace |
| `ecc signoff` | 检查签核就绪度并导出签核包 |
| `ecc report` | 生成设计总结、QoR、签核清单和步骤报告 |
| `ecc version` | 显示 ECC 运行时和组件版本 |
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,19 @@ ecc status --project gcd
ecc log --project gcd
```

By default, named workspaces are created at `<project>/<workspace-id>`. To
create one at an exact external directory, provide an absolute `--path` with
the workspace ID:

```bash
ecc run --project gcd --workspace experiment --path /data/ecc/gcd/experiment
ecc workspace import recovered --project gcd --path /archive/ecc/gcd/recovered
ecc run --project gcd --workspace recovered --resume
```

`project.json` records the canonical path, so later commands select the
workspace by ID without repeating `--path`.

## CLI Commands

Run `ecc --help` (or `ecc <command> --help`) for full usage. Common commands:
Expand All @@ -159,7 +172,7 @@ Run `ecc --help` (or `ecc <command> --help`) for full usage. Common commands:
| `ecc param` | Manage parameter overrides (`list`, `show`, `set`, `unset`, `diff`) |
| `ecc pdk` | Manage the PDK path (`set-root`, `show`, `unset`) |
| `ecc project` | Edit project declarations in `ecc.toml` (`set`, `unset`, `add`, `remove`, `show`) |
| `ecc workspace` | Refresh managed workspaces from project configuration |
| `ecc workspace` | Import existing workspaces or refresh them from project configuration |
| `ecc signoff` | Inspect readiness and export the signoff package |
| `ecc report` | Write design-summary, QoR, checklist, and step reports |
| `ecc version` | Show ECC runtime and component versions |
Expand Down
124 changes: 117 additions & 7 deletions chipcompiler/cli/command_handlers/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@

from typing_extensions import deprecated

from chipcompiler.cli.core.inputs import CheckInput, InitInput, MigrateInput, RunInput
from chipcompiler.cli.core.inputs import (
CheckInput,
InitInput,
MigrateInput,
RunInput,
WorkspaceImportInput,
)
from chipcompiler.cli.core.output import disclosure_cmd
from chipcompiler.cli.core.records import error_record
from chipcompiler.cli.core.types import CommandContext, CommandResult
Expand Down Expand Up @@ -204,6 +210,8 @@ def _preflight_environment(
from chipcompiler.cli.inspection import env_probe
from chipcompiler.rtl2gds import resolve_skip_steps

if preset is None:
return None
skip = resolve_skip_steps(flow_config)
probes = env_probe.probe_environment(env_probe.probe_components_for_preset(preset, skip=skip))
return _preflight_failures(probes, project, preset)
Expand Down Expand Up @@ -306,6 +314,102 @@ def refresh_workspace(command_input, ctx: CommandContext) -> CommandResult:
return _run_project(refresh_input, ctx, execute_flow=False)


def import_workspace(command_input: WorkspaceImportInput, ctx: CommandContext) -> CommandResult:
"""Register an existing workspace without opening or changing it."""
if ctx.project_state == "legacy":
return CommandResult.err([error_record("legacy_workspace_migration_required")])
if ctx.manifest_error:
return CommandResult.err(
[
error_record(
ctx.manifest_error.split(":", 1)[0],
reason=ctx.manifest_error,
)
]
)
cfg = ctx.config
if cfg is None and ctx.project_state != "manifest":
return CommandResult.err(
[
error_record(
"missing_config",
path=os.path.join(ctx.project_dir, "ecc.toml"),
)
]
)

if ctx.project_state == "manifest":
from chipcompiler.cli.project import effective_config

resolved = effective_config.resolve_effective_config(ctx, command_input.workspace, cfg)
if isinstance(resolved, CommandResult):
return resolved
cfg, _flow_config, warnings = resolved
else:
warnings = []
assert cfg is not None

from chipcompiler.cli.project.config import resolve_pdk_root
from chipcompiler.cli.project.workspace_registration import (
WorkspaceRegistrationError,
register_existing_workspace,
)

try:
outcome, metadata = register_existing_workspace(
ctx.project_dir,
cfg=cfg,
pdk_root=resolve_pdk_root(cfg),
workspace_id=command_input.workspace,
workspace_path=ctx.run_dir,
)
except WorkspaceRegistrationError as exc:
return CommandResult.err(
[
error_record(
exc.code,
workspace_id=command_input.workspace,
workspace=ctx.run_dir,
reason=str(exc),
)
]
)

if outcome == "conflict":
return CommandResult.err(
[
error_record(
"workspace_conflict",
workspace_id=command_input.workspace,
workspace=ctx.run_dir,
)
]
)
if outcome not in ("registered", "existing"):
return CommandResult.err(
[
error_record(
"workspace_registration_failed",
workspace_id=command_input.workspace,
workspace=ctx.run_dir,
)
]
)

return CommandResult.ok(
warnings
+ [
{
"workspace_id": command_input.workspace,
"registration": "imported" if outcome == "registered" else "already_registered",
"status": metadata.status,
"workspace": ctx.run_dir,
"run_cmd": disclosure_cmd("ecc run", ctx.project, command_input.workspace),
}
]
)


def _run_project(
command_input: RunInput, ctx: CommandContext, *, execute_flow: bool
) -> CommandResult:
Expand Down Expand Up @@ -390,6 +494,8 @@ def error(kind: str, **fields) -> CommandResult:
)
flow_config = _attach_skip_steps(flow_config, skip_steps)

assert cfg is not None

flow_builders = rtl2gds_api.get_flow_builders()
effective_preset = command_input.preset or cfg.flow_preset
if command_input.preset is not None and effective_preset not in flow_builders:
Expand Down Expand Up @@ -430,12 +536,12 @@ def error(kind: str, **fields) -> CommandResult:
if skip_policy is not None:
flow_config["skip_steps"] = skip_policy

cli_overrides = {}
cli_overrides: dict[str, object] = {}
raw_sets = command_input.param_set
if raw_sets:
from chipcompiler.cli.project.params import parse_cli_overrides

cli_overrides, set_errors = parse_cli_overrides(raw_sets)
cli_overrides, set_errors = parse_cli_overrides(list(raw_sets))
if set_errors:
return CommandResult.err(
[
Expand Down Expand Up @@ -567,10 +673,14 @@ def error(kind: str, **fields) -> CommandResult:
if preflight is not None:
return preflight

if not fresh_target and (
command_input.resume
or command_input.from_step is not None
or command_input.only is not None
if (
not fresh_target
and command_input.path is None
and (
command_input.resume
or command_input.from_step is not None
or command_input.only is not None
)
):
return _run_workspace(command_input, ctx)

Expand Down
5 changes: 5 additions & 0 deletions chipcompiler/cli/commands/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ def run_cmd(
str | None,
typer.Option("--workspace", help="Create, select, or resume a managed workspace"),
] = None,
path: Annotated[
str | None,
typer.Option("--path", help="Exact absolute directory for the managed workspace"),
] = None,
resume: Annotated[
bool,
typer.Option("--resume", help="Continue from the first non-successful step"),
Expand Down Expand Up @@ -126,6 +130,7 @@ def run_cmd(
overwrite=overwrite,
param_set=tuple(param_set or ()),
workspace=workspace,
path=path,
resume=resume,
from_step=from_step,
to_step=to_step,
Expand Down
34 changes: 32 additions & 2 deletions chipcompiler/cli/commands/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,41 @@

from chipcompiler.cli.command_handlers import project as project_handlers
from chipcompiler.cli.core.apps import create_app
from chipcompiler.cli.core.inputs import WorkspaceRefreshInput, output_options, project_options
from chipcompiler.cli.core.inputs import (
WorkspaceImportInput,
WorkspaceRefreshInput,
output_options,
project_options,
)
from chipcompiler.cli.core.invocation import execute_command
from chipcompiler.cli.core.options import PlainOption, ProjectOption

workspace_app = create_app(help="Refresh managed workspaces from project configuration")
workspace_app = create_app(help="Import or refresh managed workspaces")


@workspace_app.command("import")
def import_cmd(
*,
workspace: Annotated[str, typer.Argument(help="Workspace ID to register")],
path: Annotated[
str,
typer.Option("--path", help="Exact absolute directory of an existing workspace"),
],
project: ProjectOption = None,
plain: PlainOption = False,
) -> None:
"""Register an existing workspace without changing or running it.

The workspace remains at its current directory. Future commands select it
by WORKSPACE through the owning project's `project.json`.
"""
command_input = WorkspaceImportInput(
output=output_options(plain=plain),
project=project_options(project),
workspace=workspace,
path=path,
)
execute_command("workspace", command_input, project_handlers.import_workspace)


@workspace_app.command("refresh")
Expand Down
9 changes: 9 additions & 0 deletions chipcompiler/cli/core/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class RunInput:
overwrite: bool = False
param_set: tuple[str, ...] = ()
workspace: str | None = None
path: str | None = None
resume: bool = False
from_step: str | None = None
to_step: str | None = None
Expand Down Expand Up @@ -222,6 +223,14 @@ class WorkspaceRefreshInput:
workspace: str


@dataclass(frozen=True)
class WorkspaceImportInput:
output: OutputOptions
project: ProjectOptions
workspace: str
path: str


@dataclass(frozen=True)
class MacroSetInput:
output: OutputOptions
Expand Down
Loading
Loading