Skip to content

get_project_config() only checks for .gds (uncompressed), misleading error message implies .gds.gz is also accepted #111

Description

@shivarammysore

Summary

cf_precheck/config.py:get_project_config() only checks for the uncompressed .gds form of the wrapper GDS — but the error message it raises tells the user that .gds.gz is also a valid input. The detection and the error are inconsistent.

Code reference

src/cf_precheck/config.py lines 50-72 (current main):

analog_gds = project_path / "gds/user_analog_project_wrapper.gds"
digital_gds = project_path / "gds/user_project_wrapper.gds"
openframe_gds = project_path / "gds/openframe_project_wrapper.gds"
mini_gds = project_path / "gds/user_project_wrapper_mini4.gds"

gds_files = {
    "analog": analog_gds,
    "digital": digital_gds,
    "openframe": openframe_gds,
    "mini": mini_gds,
}
present = {k: v for k, v in gds_files.items() if v.exists()}

if len(present) != 1:
    logging.critical(
        "A single valid GDS was not found. "
        "Digital projects need 'gds/user_project_wrapper(.gds/.gds.gz)'. "
        "Analog projects need 'gds/user_analog_project_wrapper(.gds/.gds.gz)'."
    )

Detection only looks at the .gds form (uncompressed). The error message lists .gds/.gds.gz as accepted forms.

Why this matters in practice

The intended flow is: uncompress_gds() runs Caravel's make uncompress (gunzips .gds.gz.gds), then get_project_config() finds the resulting .gds. That works as long as make uncompress actually produces a .gds.

But several real failure modes leave .gds.gz un-extracted (e.g., the file is a Git LFS pointer not pulled by the remote runner — see chipfoundry/cf-cli#20). In those cases, get_project_config() reports "A single valid GDS was not found" — leaving the user thinking they need to commit a .gds, when in fact the issue is upstream of detection.

Suggested fix

Either:

  1. Make get_project_config() also accept .gds.gz directly (and let downstream stages call uncompress on demand), so the error message becomes accurate; OR
  2. Tighten the error message to reflect what is actually checked, e.g. "Digital projects need an uncompressed gds/user_project_wrapper.gds (commit it directly, or make uncompress your .gds.gz first)."

(1) is friendlier to users. (2) is at least truthful.

Suggested patch for option (1):

gds_suffixes = (\".gds\", \".gds.gz\")

def first_existing(base: str) -> Path | None:
    for suf in gds_suffixes:
        p = project_path / (\"gds/\" + base + suf)
        if p.exists():
            return p
    return None

bases = {
    \"analog\": \"user_analog_project_wrapper\",
    \"digital\": \"user_project_wrapper\",
    \"openframe\": \"openframe_project_wrapper\",
    \"mini\": \"user_project_wrapper_mini4\",
}
present = {k: p for k, b in bases.items() if (p := first_existing(b))}

Then call uncompress_gds() only on the matched file if its suffix is .gds.gz, instead of unconditionally running it.

Evidence

Environment

  • cf-precheck: current main
  • Reproduces with any project that ships .gds.gz instead of .gds and has make uncompress fail silently for any reason (LFS pointer, permission issue, missing make target, etc.)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions