chipfoundry-cli 2.4.10__tar.gz → 2.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {chipfoundry_cli-2.4.10 → chipfoundry_cli-2.5.0}/PKG-INFO +24 -5
- {chipfoundry_cli-2.4.10 → chipfoundry_cli-2.5.0}/README.md +23 -4
- {chipfoundry_cli-2.4.10 → chipfoundry_cli-2.5.0}/chipfoundry_cli/main.py +216 -30
- {chipfoundry_cli-2.4.10 → chipfoundry_cli-2.5.0}/pyproject.toml +1 -1
- {chipfoundry_cli-2.4.10 → chipfoundry_cli-2.5.0}/LICENSE +0 -0
- {chipfoundry_cli-2.4.10 → chipfoundry_cli-2.5.0}/chipfoundry_cli/__init__.py +0 -0
- {chipfoundry_cli-2.4.10 → chipfoundry_cli-2.5.0}/chipfoundry_cli/check_refs.py +0 -0
- {chipfoundry_cli-2.4.10 → chipfoundry_cli-2.5.0}/chipfoundry_cli/remote_precheck_git.py +0 -0
- {chipfoundry_cli-2.4.10 → chipfoundry_cli-2.5.0}/chipfoundry_cli/utils.py +0 -0
- {chipfoundry_cli-2.4.10 → chipfoundry_cli-2.5.0}/chipfoundry_cli/version_check.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: chipfoundry-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
4
4
|
Summary: CLI tool to automate ChipFoundry project submission to SFTP server
|
|
5
5
|
Home-page: https://chipfoundry.io
|
|
6
6
|
License: Apache-2.0
|
|
@@ -427,13 +427,18 @@ cf harden [MACRO] [OPTIONS]
|
|
|
427
427
|
|
|
428
428
|
**Key Options:**
|
|
429
429
|
- `--list` or no argument: List all available macros
|
|
430
|
+
- `--list-from-steps`: List valid LibreLane step names for `--from` for a specific macro
|
|
430
431
|
- `MACRO`: Name of macro to harden (e.g., `user_proj_example`, `user_project_wrapper`)
|
|
431
432
|
- `--project-root`: Specify project directory
|
|
432
|
-
- `--tag`:
|
|
433
|
+
- `--tag`: Run tag. Without `--from`, existing tag is overwritten; with `--from`, resumes that tag
|
|
434
|
+
- `--from`: Start hardening from a specific LibreLane step (e.g., `OpenROAD.DetailedRouting`)
|
|
435
|
+
- `--tag` + `--from`: Resume from that step using the existing run state under the specified tag
|
|
436
|
+
- `--from` without `--tag`: Resume from that step using the latest existing run tag for the macro
|
|
437
|
+
- `--open-in-openroad`: Open an existing run in OpenROAD GUI (uses latest run if `--tag` omitted)
|
|
438
|
+
- `--open-in-klayout`: Open an existing run in KLayout GUI (uses latest run if `--tag` omitted)
|
|
433
439
|
- `--pdk`: PDK to use (default: sky130A)
|
|
434
440
|
- `--use-nix`: Force use of Nix (fails if Nix not available)
|
|
435
441
|
- `--use-docker`: Force use of Docker (fails if Docker not available)
|
|
436
|
-
- `--dry-run`: Show configuration without running
|
|
437
442
|
|
|
438
443
|
**Examples:**
|
|
439
444
|
```bash
|
|
@@ -446,8 +451,22 @@ cf harden user_proj_example
|
|
|
446
451
|
# Harden with custom tag and PDK
|
|
447
452
|
cf harden user_proj_example --tag my_run --pdk sky130B
|
|
448
453
|
|
|
449
|
-
#
|
|
450
|
-
cf harden user_proj_example --
|
|
454
|
+
# Resume flow from a specific LibreLane step
|
|
455
|
+
cf harden user_proj_example --tag test2 --from OpenROAD.DetailedRouting
|
|
456
|
+
|
|
457
|
+
# Resume from latest existing run tag automatically
|
|
458
|
+
cf harden user_proj_example --from OpenROAD.DetailedRouting
|
|
459
|
+
|
|
460
|
+
# Show exact valid --from step names for a macro
|
|
461
|
+
cf harden user_proj_example --list-from-steps
|
|
462
|
+
|
|
463
|
+
# Open GUI for a specific run tag
|
|
464
|
+
cf harden user_proj_example --tag test2 --open-in-openroad
|
|
465
|
+
cf harden user_proj_example --tag test2 --open-in-klayout
|
|
466
|
+
|
|
467
|
+
# Open GUI for latest existing run tag automatically
|
|
468
|
+
cf harden user_proj_example --open-in-openroad
|
|
469
|
+
|
|
451
470
|
```
|
|
452
471
|
|
|
453
472
|
**Workflow:**
|
|
@@ -401,13 +401,18 @@ cf harden [MACRO] [OPTIONS]
|
|
|
401
401
|
|
|
402
402
|
**Key Options:**
|
|
403
403
|
- `--list` or no argument: List all available macros
|
|
404
|
+
- `--list-from-steps`: List valid LibreLane step names for `--from` for a specific macro
|
|
404
405
|
- `MACRO`: Name of macro to harden (e.g., `user_proj_example`, `user_project_wrapper`)
|
|
405
406
|
- `--project-root`: Specify project directory
|
|
406
|
-
- `--tag`:
|
|
407
|
+
- `--tag`: Run tag. Without `--from`, existing tag is overwritten; with `--from`, resumes that tag
|
|
408
|
+
- `--from`: Start hardening from a specific LibreLane step (e.g., `OpenROAD.DetailedRouting`)
|
|
409
|
+
- `--tag` + `--from`: Resume from that step using the existing run state under the specified tag
|
|
410
|
+
- `--from` without `--tag`: Resume from that step using the latest existing run tag for the macro
|
|
411
|
+
- `--open-in-openroad`: Open an existing run in OpenROAD GUI (uses latest run if `--tag` omitted)
|
|
412
|
+
- `--open-in-klayout`: Open an existing run in KLayout GUI (uses latest run if `--tag` omitted)
|
|
407
413
|
- `--pdk`: PDK to use (default: sky130A)
|
|
408
414
|
- `--use-nix`: Force use of Nix (fails if Nix not available)
|
|
409
415
|
- `--use-docker`: Force use of Docker (fails if Docker not available)
|
|
410
|
-
- `--dry-run`: Show configuration without running
|
|
411
416
|
|
|
412
417
|
**Examples:**
|
|
413
418
|
```bash
|
|
@@ -420,8 +425,22 @@ cf harden user_proj_example
|
|
|
420
425
|
# Harden with custom tag and PDK
|
|
421
426
|
cf harden user_proj_example --tag my_run --pdk sky130B
|
|
422
427
|
|
|
423
|
-
#
|
|
424
|
-
cf harden user_proj_example --
|
|
428
|
+
# Resume flow from a specific LibreLane step
|
|
429
|
+
cf harden user_proj_example --tag test2 --from OpenROAD.DetailedRouting
|
|
430
|
+
|
|
431
|
+
# Resume from latest existing run tag automatically
|
|
432
|
+
cf harden user_proj_example --from OpenROAD.DetailedRouting
|
|
433
|
+
|
|
434
|
+
# Show exact valid --from step names for a macro
|
|
435
|
+
cf harden user_proj_example --list-from-steps
|
|
436
|
+
|
|
437
|
+
# Open GUI for a specific run tag
|
|
438
|
+
cf harden user_proj_example --tag test2 --open-in-openroad
|
|
439
|
+
cf harden user_proj_example --tag test2 --open-in-klayout
|
|
440
|
+
|
|
441
|
+
# Open GUI for latest existing run tag automatically
|
|
442
|
+
cf harden user_proj_example --open-in-openroad
|
|
443
|
+
|
|
425
444
|
```
|
|
426
445
|
|
|
427
446
|
**Workflow:**
|
|
@@ -28,6 +28,7 @@ import subprocess
|
|
|
28
28
|
import sys
|
|
29
29
|
import shutil
|
|
30
30
|
import signal
|
|
31
|
+
import difflib
|
|
31
32
|
|
|
32
33
|
# Textual imports for GPIO grid UI
|
|
33
34
|
from textual.app import App, ComposeResult
|
|
@@ -41,6 +42,42 @@ DEFAULT_SFTP_HOST = 'sftp.chipfoundry.io'
|
|
|
41
42
|
|
|
42
43
|
console = Console()
|
|
43
44
|
|
|
45
|
+
class CategorizedCommand(click.Command):
|
|
46
|
+
"""Click command with categorized help sections for options."""
|
|
47
|
+
|
|
48
|
+
def __init__(self, *args, option_categories=None, **kwargs):
|
|
49
|
+
self.option_categories = option_categories or []
|
|
50
|
+
super().__init__(*args, **kwargs)
|
|
51
|
+
|
|
52
|
+
def format_options(self, ctx, formatter):
|
|
53
|
+
options = {}
|
|
54
|
+
for param in self.get_params(ctx):
|
|
55
|
+
if not isinstance(param, click.Option):
|
|
56
|
+
continue
|
|
57
|
+
# Keep built-in --help available but omit it from custom sections.
|
|
58
|
+
if param.name == "help":
|
|
59
|
+
continue
|
|
60
|
+
record = param.get_help_record(ctx)
|
|
61
|
+
if record:
|
|
62
|
+
# Make option names easier to scan in help output.
|
|
63
|
+
options[param.name] = (click.style(record[0], fg="cyan"), record[1])
|
|
64
|
+
|
|
65
|
+
rendered = set()
|
|
66
|
+
for title, option_names in self.option_categories:
|
|
67
|
+
rows = []
|
|
68
|
+
for opt_name in option_names:
|
|
69
|
+
if opt_name in options:
|
|
70
|
+
rows.append(options[opt_name])
|
|
71
|
+
rendered.add(opt_name)
|
|
72
|
+
if rows:
|
|
73
|
+
with formatter.section(click.style(title, fg="green", bold=True)):
|
|
74
|
+
formatter.write_dl(rows)
|
|
75
|
+
|
|
76
|
+
remaining_rows = [row for name, row in options.items() if name not in rendered]
|
|
77
|
+
if remaining_rows:
|
|
78
|
+
with formatter.section(click.style("Other Options", fg="green", bold=True)):
|
|
79
|
+
formatter.write_dl(remaining_rows)
|
|
80
|
+
|
|
44
81
|
def get_git_tag(repo_path):
|
|
45
82
|
"""Get the current git tag/branch of a repository."""
|
|
46
83
|
try:
|
|
@@ -3659,23 +3696,29 @@ def setup(project_root, repo_owner, repo_name, branch, pdk, caravel_lite,
|
|
|
3659
3696
|
else:
|
|
3660
3697
|
console.print("[bold green]Setup complete![/bold green]")
|
|
3661
3698
|
|
|
3662
|
-
@main.command(
|
|
3699
|
+
@main.command(
|
|
3700
|
+
'harden',
|
|
3701
|
+
cls=CategorizedCommand,
|
|
3702
|
+
option_categories=[
|
|
3703
|
+
("Design Selection", ["project_root", "list_designs", "list_from_steps"]),
|
|
3704
|
+
("Run Controls", ["tag", "from_step"]),
|
|
3705
|
+
("GUI Modes", ["open_in_openroad", "open_in_klayout"]),
|
|
3706
|
+
("Execution Backend", ["pdk", "use_nix", "use_docker"]),
|
|
3707
|
+
],
|
|
3708
|
+
)
|
|
3663
3709
|
@click.argument('macro', required=False)
|
|
3664
3710
|
@click.option('--project-root', type=click.Path(exists=True, file_okay=False), help='Path to the project directory (defaults to current directory)')
|
|
3665
3711
|
@click.option('--list', 'list_designs', is_flag=True, help='List all available macros')
|
|
3666
|
-
@click.option('--
|
|
3712
|
+
@click.option('--list-from-steps', is_flag=True, help='List valid LibreLane step names for --from (requires MACRO)')
|
|
3713
|
+
@click.option('--tag', help='Run tag. Without --from, existing tag is overwritten; with --from, resumes that tag')
|
|
3714
|
+
@click.option('--from', 'from_step', help='Start hardening from a specific LibreLane step (uses latest run tag if --tag is omitted)')
|
|
3715
|
+
@click.option('--open-in-openroad', is_flag=True, help='Open an existing run in the OpenROAD GUI')
|
|
3716
|
+
@click.option('--open-in-klayout', is_flag=True, help='Open an existing run in the KLayout GUI')
|
|
3667
3717
|
@click.option('--pdk', help='PDK to use (defaults to sky130A)')
|
|
3668
3718
|
@click.option('--use-nix', is_flag=True, help='Force use of Nix (fails if Nix not available)')
|
|
3669
3719
|
@click.option('--use-docker', is_flag=True, help='Force use of Docker (fails if Docker not available)')
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
"""Harden a macro using LibreLane (OpenLane 2).
|
|
3673
|
-
|
|
3674
|
-
Examples:
|
|
3675
|
-
cf harden user_proj_example # Harden a specific macro
|
|
3676
|
-
cf harden user_project_wrapper
|
|
3677
|
-
cf harden --list # List available macros
|
|
3678
|
-
"""
|
|
3720
|
+
def harden(macro, project_root, list_designs, list_from_steps, tag, from_step, open_in_openroad, open_in_klayout, pdk, use_nix, use_docker):
|
|
3721
|
+
"""Harden a macro using LibreLane (OpenLane 2)."""
|
|
3679
3722
|
from datetime import datetime
|
|
3680
3723
|
|
|
3681
3724
|
# If .cf/project.json exists in cwd, use it as default project_root
|
|
@@ -3689,7 +3732,7 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
3689
3732
|
|
|
3690
3733
|
# Check if project is initialized (skip check for --list or when no macro specified, allow graceful return)
|
|
3691
3734
|
if not list_designs and macro:
|
|
3692
|
-
if not check_project_initialized(project_root_path, 'harden',
|
|
3735
|
+
if not check_project_initialized(project_root_path, 'harden', allow_graceful=True):
|
|
3693
3736
|
console.print(f"[red]✗[/red] Project not initialized. Please run 'cf init' first.")
|
|
3694
3737
|
console.print("[yellow]Run 'cf setup' first to install OpenLane[/yellow]")
|
|
3695
3738
|
return
|
|
@@ -3702,9 +3745,26 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
3702
3745
|
console.print("[yellow]Run 'cf setup' first to install OpenLane[/yellow]")
|
|
3703
3746
|
return
|
|
3704
3747
|
|
|
3748
|
+
if list_from_steps and not macro:
|
|
3749
|
+
console.print("[red]✗[/red] --list-from-steps requires a macro name")
|
|
3750
|
+
console.print("[yellow]Example:[/yellow] cf harden user_proj_example --list-from-steps")
|
|
3751
|
+
return
|
|
3752
|
+
|
|
3753
|
+
gui_mode_count = int(open_in_openroad) + int(open_in_klayout)
|
|
3754
|
+
if gui_mode_count > 1:
|
|
3755
|
+
console.print("[red]✗[/red] Use only one GUI flag: --open-in-openroad or --open-in-klayout")
|
|
3756
|
+
return
|
|
3757
|
+
if gui_mode_count and from_step:
|
|
3758
|
+
console.print("[red]✗[/red] --from cannot be combined with GUI modes")
|
|
3759
|
+
console.print("[yellow]Use --tag to select which run to open, or omit --tag to use latest run[/yellow]")
|
|
3760
|
+
return
|
|
3761
|
+
if gui_mode_count and list_from_steps:
|
|
3762
|
+
console.print("[red]✗[/red] --list-from-steps cannot be combined with GUI modes")
|
|
3763
|
+
return
|
|
3764
|
+
|
|
3705
3765
|
# If no macro specified, show prompt with available macros
|
|
3706
|
-
no_macro_specified = not macro and not list_designs
|
|
3707
|
-
if not macro:
|
|
3766
|
+
no_macro_specified = not macro and not list_designs and not list_from_steps
|
|
3767
|
+
if not macro and not list_from_steps:
|
|
3708
3768
|
list_designs = True
|
|
3709
3769
|
|
|
3710
3770
|
# List designs if requested (or if no macro specified)
|
|
@@ -3753,6 +3813,89 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
3753
3813
|
console.print("[red]✗[/red] LibreLane not installed")
|
|
3754
3814
|
console.print("[yellow]Run 'cf setup --only-openlane' to install LibreLane[/yellow]")
|
|
3755
3815
|
raise click.Abort()
|
|
3816
|
+
|
|
3817
|
+
# Resolve valid step names for this macro's selected flow using LibreLane itself.
|
|
3818
|
+
def get_valid_from_steps(librelane_python, macro_config, working_dir):
|
|
3819
|
+
script = (
|
|
3820
|
+
"import json, sys\n"
|
|
3821
|
+
"from librelane.config import Config\n"
|
|
3822
|
+
"from librelane.flows import Flow, SequentialFlow\n"
|
|
3823
|
+
"cfg = sys.argv[1]\n"
|
|
3824
|
+
"target = Flow.factory.get('Classic')\n"
|
|
3825
|
+
"meta = Config.get_meta(cfg)\n"
|
|
3826
|
+
"if meta:\n"
|
|
3827
|
+
" if isinstance(meta.flow, str):\n"
|
|
3828
|
+
" found = Flow.factory.get(meta.flow)\n"
|
|
3829
|
+
" if found is None:\n"
|
|
3830
|
+
" raise RuntimeError(f\"Unknown flow '{meta.flow}' in config metadata\")\n"
|
|
3831
|
+
" target = found\n"
|
|
3832
|
+
" elif isinstance(meta.flow, list):\n"
|
|
3833
|
+
" target = SequentialFlow.make(meta.flow)\n"
|
|
3834
|
+
" if meta.substituting_steps is not None:\n"
|
|
3835
|
+
" if meta.flow is None:\n"
|
|
3836
|
+
" raise RuntimeError('substituting_steps is set but flow is not defined')\n"
|
|
3837
|
+
" if not issubclass(target, SequentialFlow):\n"
|
|
3838
|
+
" raise RuntimeError('substituting_steps requires a sequential flow')\n"
|
|
3839
|
+
" target = target.Substitute(meta.substituting_steps)\n"
|
|
3840
|
+
"steps = []\n"
|
|
3841
|
+
"seen = set()\n"
|
|
3842
|
+
"for step in getattr(target, 'Steps', []) or []:\n"
|
|
3843
|
+
" step_id = getattr(step, 'id', None)\n"
|
|
3844
|
+
" if not step_id:\n"
|
|
3845
|
+
" continue\n"
|
|
3846
|
+
" if step_id in seen:\n"
|
|
3847
|
+
" continue\n"
|
|
3848
|
+
" seen.add(step_id)\n"
|
|
3849
|
+
" steps.append(step_id)\n"
|
|
3850
|
+
"print(json.dumps({'steps': steps}))\n"
|
|
3851
|
+
)
|
|
3852
|
+
result = subprocess.run(
|
|
3853
|
+
[str(librelane_python), '-c', script, macro_config],
|
|
3854
|
+
cwd=str(working_dir),
|
|
3855
|
+
capture_output=True,
|
|
3856
|
+
text=True,
|
|
3857
|
+
)
|
|
3858
|
+
if result.returncode != 0:
|
|
3859
|
+
err = (result.stderr or result.stdout or 'unknown error').strip()
|
|
3860
|
+
return None, err
|
|
3861
|
+
try:
|
|
3862
|
+
payload = json.loads(result.stdout.strip())
|
|
3863
|
+
return payload.get('steps', []), None
|
|
3864
|
+
except Exception as exc:
|
|
3865
|
+
return None, str(exc)
|
|
3866
|
+
|
|
3867
|
+
venv_bin = librelane_venv / 'bin'
|
|
3868
|
+
librelane_python = venv_bin / 'python3'
|
|
3869
|
+
valid_from_steps, valid_from_steps_error = get_valid_from_steps(
|
|
3870
|
+
librelane_python=librelane_python,
|
|
3871
|
+
macro_config=config_file,
|
|
3872
|
+
working_dir=openlane_dir,
|
|
3873
|
+
)
|
|
3874
|
+
if valid_from_steps_error:
|
|
3875
|
+
console.print("[red]✗[/red] Failed to load LibreLane step list for this macro")
|
|
3876
|
+
console.print(f"[yellow]Error:[/yellow] {valid_from_steps_error}")
|
|
3877
|
+
console.print("[yellow]Run 'cf setup --only-openlane' to ensure LibreLane is installed correctly[/yellow]")
|
|
3878
|
+
return
|
|
3879
|
+
|
|
3880
|
+
if list_from_steps:
|
|
3881
|
+
console.print(f"[bold cyan]Valid --from steps for {macro}:[/bold cyan]")
|
|
3882
|
+
if valid_from_steps:
|
|
3883
|
+
for step_name in valid_from_steps:
|
|
3884
|
+
console.print(f" • {step_name}")
|
|
3885
|
+
else:
|
|
3886
|
+
console.print("[yellow]No steps found for this flow[/yellow]")
|
|
3887
|
+
return
|
|
3888
|
+
|
|
3889
|
+
if from_step and from_step not in valid_from_steps:
|
|
3890
|
+
console.print(f"[red]✗[/red] Invalid --from step: {from_step}")
|
|
3891
|
+
matches = difflib.get_close_matches(from_step, valid_from_steps, n=5, cutoff=0.4)
|
|
3892
|
+
if matches:
|
|
3893
|
+
console.print("[yellow]Did you mean:[/yellow]")
|
|
3894
|
+
for m in matches:
|
|
3895
|
+
console.print(f" • {m}")
|
|
3896
|
+
else:
|
|
3897
|
+
console.print(f"[yellow]Use 'cf harden {macro} --list-from-steps' to see valid step names[/yellow]")
|
|
3898
|
+
return
|
|
3756
3899
|
|
|
3757
3900
|
# Fetch versions from upstream
|
|
3758
3901
|
console.print("[dim]Fetching version information from cf-cli repository...[/dim]")
|
|
@@ -3849,7 +3992,28 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
3849
3992
|
console.print("[yellow]Run 'cf setup --only-pdk' to install the PDK[/yellow]")
|
|
3850
3993
|
return
|
|
3851
3994
|
|
|
3852
|
-
|
|
3995
|
+
auto_selected_latest_tag = False
|
|
3996
|
+
if (from_step or gui_mode_count) and not tag:
|
|
3997
|
+
runs_dir = macro_dir / 'runs'
|
|
3998
|
+
if not runs_dir.exists():
|
|
3999
|
+
console.print("[red]✗[/red] No existing runs found for this macro")
|
|
4000
|
+
if gui_mode_count:
|
|
4001
|
+
console.print("[yellow]Create a hardening run first, or specify --tag <existing_tag>[/yellow]")
|
|
4002
|
+
else:
|
|
4003
|
+
console.print("[yellow]Run without --from first, or specify --tag <existing_tag>[/yellow]")
|
|
4004
|
+
return
|
|
4005
|
+
candidate_runs = [p for p in runs_dir.iterdir() if p.is_dir()]
|
|
4006
|
+
if not candidate_runs:
|
|
4007
|
+
console.print("[red]✗[/red] No existing runs found for this macro")
|
|
4008
|
+
if gui_mode_count:
|
|
4009
|
+
console.print("[yellow]Create a hardening run first, or specify --tag <existing_tag>[/yellow]")
|
|
4010
|
+
else:
|
|
4011
|
+
console.print("[yellow]Run without --from first, or specify --tag <existing_tag>[/yellow]")
|
|
4012
|
+
return
|
|
4013
|
+
latest_run = max(candidate_runs, key=lambda p: p.stat().st_mtime)
|
|
4014
|
+
tag = latest_run.name
|
|
4015
|
+
auto_selected_latest_tag = True
|
|
4016
|
+
elif not tag:
|
|
3853
4017
|
tag = datetime.now().strftime('%y_%m_%d_%H_%M')
|
|
3854
4018
|
|
|
3855
4019
|
# Display configuration
|
|
@@ -3857,16 +4021,23 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
3857
4021
|
console.print(f"[bold cyan]Hardening: {macro}[/bold cyan]")
|
|
3858
4022
|
console.print(f"Config: [yellow]{Path(config_file).name}[/yellow]")
|
|
3859
4023
|
console.print(f"Run tag: [yellow]{tag}[/yellow]")
|
|
4024
|
+
if auto_selected_latest_tag:
|
|
4025
|
+
if gui_mode_count:
|
|
4026
|
+
console.print("[yellow]Using latest existing run tag (auto-selected because GUI mode was requested without --tag)[/yellow]")
|
|
4027
|
+
else:
|
|
4028
|
+
console.print("[yellow]Using latest existing run tag (auto-selected because --from was provided without --tag)[/yellow]")
|
|
4029
|
+
if from_step:
|
|
4030
|
+
console.print(f"Start from: [yellow]{from_step}[/yellow]")
|
|
4031
|
+
console.print("[yellow]Mode:[/yellow] resume from existing state under this tag (no overwrite)")
|
|
4032
|
+
if open_in_openroad:
|
|
4033
|
+
console.print("[yellow]Mode:[/yellow] open existing run in OpenROAD GUI")
|
|
4034
|
+
elif open_in_klayout:
|
|
4035
|
+
console.print("[yellow]Mode:[/yellow] open existing run in KLayout GUI")
|
|
3860
4036
|
console.print(f"PDK: [yellow]{pdk}[/yellow]")
|
|
3861
4037
|
console.print(f"PDK Root: [yellow]{pdk_root}[/yellow]")
|
|
3862
4038
|
console.print(f"Execution: [yellow]{execution_method}[/yellow]")
|
|
3863
4039
|
console.print("="*60 + "\n")
|
|
3864
|
-
|
|
3865
|
-
if dry_run:
|
|
3866
|
-
console.print("[bold yellow]Dry run - configuration ready[/bold yellow]")
|
|
3867
|
-
console.print(f"Would use: {execution_method}")
|
|
3868
|
-
return
|
|
3869
|
-
|
|
4040
|
+
|
|
3870
4041
|
# Build command based on execution method
|
|
3871
4042
|
if use_nix:
|
|
3872
4043
|
# Use Nix to run LibreLane
|
|
@@ -3874,22 +4045,30 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
3874
4045
|
|
|
3875
4046
|
cmd = [
|
|
3876
4047
|
'nix', 'run', f'github:chipfoundry/openlane-2/{openlane_version}', '--',
|
|
3877
|
-
'--run-tag', tag,
|
|
3878
4048
|
'--manual-pdk',
|
|
3879
4049
|
'--pdk-root', str(pdk_root),
|
|
3880
4050
|
'--pdk', pdk,
|
|
3881
4051
|
'--ef-save-views-to', str(project_root_path),
|
|
3882
|
-
'--
|
|
3883
|
-
config_file
|
|
4052
|
+
'--run-tag', tag,
|
|
3884
4053
|
]
|
|
4054
|
+
if open_in_openroad:
|
|
4055
|
+
cmd.extend(['--flow', 'OpenInOpenROAD'])
|
|
4056
|
+
elif open_in_klayout:
|
|
4057
|
+
cmd.extend(['--flow', 'OpenInKLayout'])
|
|
4058
|
+
elif not from_step:
|
|
4059
|
+
cmd.append('--overwrite')
|
|
4060
|
+
if from_step:
|
|
4061
|
+
cmd.extend(['--from', from_step])
|
|
4062
|
+
cmd.append(config_file)
|
|
3885
4063
|
|
|
3886
4064
|
env = os.environ.copy()
|
|
3887
4065
|
env.update({
|
|
3888
4066
|
'PROJECT_ROOT': str(project_root_path),
|
|
3889
4067
|
'PDK_ROOT': str(pdk_root),
|
|
3890
4068
|
'PDK': pdk,
|
|
3891
|
-
'LIBRELANE_RUN_TAG': tag,
|
|
3892
4069
|
})
|
|
4070
|
+
if tag:
|
|
4071
|
+
env['LIBRELANE_RUN_TAG'] = tag
|
|
3893
4072
|
|
|
3894
4073
|
else:
|
|
3895
4074
|
# Use Docker via venv
|
|
@@ -3901,12 +4080,12 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
3901
4080
|
'PROJECT_ROOT': str(project_root_path),
|
|
3902
4081
|
'PDK_ROOT': str(pdk_root),
|
|
3903
4082
|
'PDK': pdk,
|
|
3904
|
-
'LIBRELANE_RUN_TAG': tag,
|
|
3905
4083
|
'PYTHONPATH': str(librelane_venv / 'lib' / f'python{sys.version_info.major}.{sys.version_info.minor}' / 'site-packages')
|
|
3906
4084
|
})
|
|
4085
|
+
if tag:
|
|
4086
|
+
env['LIBRELANE_RUN_TAG'] = tag
|
|
3907
4087
|
|
|
3908
4088
|
# Add venv to PATH so librelane can find its dependencies
|
|
3909
|
-
venv_bin = librelane_venv / 'bin'
|
|
3910
4089
|
env['PATH'] = f"{venv_bin}:{env.get('PATH', '')}"
|
|
3911
4090
|
|
|
3912
4091
|
# Build LibreLane command
|
|
@@ -3927,14 +4106,21 @@ def harden(macro, project_root, list_designs, tag, pdk, use_nix, use_docker, dry
|
|
|
3927
4106
|
cmd.append('--docker-no-tty')
|
|
3928
4107
|
|
|
3929
4108
|
cmd.extend([
|
|
3930
|
-
'--run-tag', tag,
|
|
3931
4109
|
'--manual-pdk',
|
|
3932
4110
|
'--pdk-root', str(pdk_root),
|
|
3933
4111
|
'--pdk', pdk,
|
|
3934
4112
|
'--ef-save-views-to', str(project_root_path),
|
|
3935
|
-
'--
|
|
3936
|
-
config_file
|
|
4113
|
+
'--run-tag', tag,
|
|
3937
4114
|
])
|
|
4115
|
+
if open_in_openroad:
|
|
4116
|
+
cmd.extend(['--flow', 'OpenInOpenROAD'])
|
|
4117
|
+
elif open_in_klayout:
|
|
4118
|
+
cmd.extend(['--flow', 'OpenInKLayout'])
|
|
4119
|
+
elif not from_step:
|
|
4120
|
+
cmd.append('--overwrite')
|
|
4121
|
+
if from_step:
|
|
4122
|
+
cmd.extend(['--from', from_step])
|
|
4123
|
+
cmd.append(config_file)
|
|
3938
4124
|
|
|
3939
4125
|
# Run LibreLane
|
|
3940
4126
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|