Add precision support audit tooling (#728)
* Add precision support audit tooling Introduces two slash commands for auditing data-type support across ROCm libraries between releases: - /precision-check: scopes to libraries changed in the manifest diff - /precision-check-delta: scopes to libraries whose source file SHA changed between releases (faster for routine release-over-release use) precision_fetch.py fetches raw source files (RST, C headers) and YAML snapshots from GitHub to /tmp/. The slash commands read them directly and do semantic comparison — no regex parsers. Auto-updates the YAML for unambiguous missing entries; flags ambiguous findings (macro expansion, combination tables, support level mismatches, typedef-only sources) for human review. manifest_diff.py fetches and diffs ROCm manifests between two versions, with branch-first and tag fallback for pre-GA use. Also includes: - .claude/settings.json: pre-approved permissions so the commands run without repeated prompts - tools/autotag/precision-update-log/: gitignored directory for local audit logs - README updates documenting the commands, prerequisites, and how to extend coverage to new libraries * Fix markdown issues * Move precision support scripts to tools/precision-support/ * Fix precision-check command path after script move to tools/precision-support --------- Co-authored-by: Istvan Kiss <istvan.kiss@amd.com>
This commit is contained in:
co-authored by
Istvan Kiss
parent
2e7ccf4637
commit
f5c3167c0a
@@ -0,0 +1,112 @@
|
||||
Precision support delta check — SHA-filtered. Arguments: $ARGUMENTS = "previous_version current_version" (e.g. 7.1.1 7.2.0).
|
||||
|
||||
Only checks libraries where the source file itself changed between the two releases (SHA comparison). Libraries with an unchanged source file are skipped automatically — no manifest diff is performed.
|
||||
|
||||
**Output rule:** Do not write any text until all tool calls are complete. When you are ready to respond, write exactly: "X of N libraries need verification." then the summary table, then detail blocks, then the "Changes written:" block. Nothing else. No narration, no transitions, no status updates, no reasoning.
|
||||
|
||||
## Step 1 — Fetch source files
|
||||
|
||||
```bash
|
||||
cd ~/projects/ROCm-internal/tools/autotag && python3 precision_fetch.py -t "$GITHUB_TOKEN" --previous PREVIOUS --current CURRENT --sha-filter
|
||||
```
|
||||
|
||||
Replace PREVIOUS and CURRENT from $ARGUMENTS.
|
||||
|
||||
## Step 2 — Read library list
|
||||
|
||||
Read `/tmp/precision_libs.txt`.
|
||||
|
||||
## Step 3 — Parse each library
|
||||
|
||||
For each library in the list:
|
||||
|
||||
- Source file exists (`/tmp/precision_{lib}_source.txt`): read it and `/tmp/precision_{lib}_yaml.txt`, then compare.
|
||||
- URL file exists (`/tmp/precision_{lib}_url.txt`): read it — this is the GitHub link to the source file, used in the detail block Source field.
|
||||
- Skip file exists (`/tmp/precision_{lib}_skip.txt`): note the reason.
|
||||
|
||||
**Do not use GitHub MCP tools, WebFetch, or any network call.** All content is already in `/tmp/`. Use only the Read tool on those files.
|
||||
|
||||
You are the parser. Read the source file directly — do not infer from filenames or prior knowledge.
|
||||
|
||||
- RST files: look for list-tables, type listings, and support level indicators.
|
||||
- C headers: look for enums and macros that define supported types.
|
||||
- AMD/NVIDIA split tables: use the AMD column only.
|
||||
|
||||
## Step 4 — Known mismatches (do not flag)
|
||||
|
||||
These entries are **specific** — they exempt only the named type for the named library. They do not mark the entire library as clean. Continue checking all other types in every library.
|
||||
|
||||
- **hipBLAS float16**: YAML=⚠️ correct — only AXPY and Dot support it.
|
||||
- **hipBLAS bfloat16**: YAML=⚠️ correct — only Dot supports it.
|
||||
- **rocBLAS float16**: same partial-support pattern as hipBLAS — do not flag.
|
||||
- **rocBLAS bfloat16**: same partial-support pattern as hipBLAS — do not flag.
|
||||
- **MIGraphX int8**: YAML=⚠️ correct — quantization-only via `quantize_int8()`.
|
||||
- **rocFFT float16**: YAML already includes float16 ✅ — do not flag as missing.
|
||||
|
||||
**Do not dismiss any other gaps on your own judgment.** If a type appears in the source but not in the YAML, flag it — even if you think it might be intentional or covered by convention. That call belongs to the human reviewer, not you.
|
||||
|
||||
## Step 5 — Classify and update (silent)
|
||||
|
||||
For each finding, decide **auto-update** or **flag**:
|
||||
|
||||
**Default: auto-update.** If a type is absent from YAML and appears in the source, add it — unless one of the following exceptions applies.
|
||||
|
||||
**Flag for human review if ANY are true:**
|
||||
|
||||
- Found only via macro expansion (e.g., `MIGRAPHX_SHAPE_VISIT_TYPES`).
|
||||
- Found only in a combination table (Ti/To/Tc triplets) — not a canonical per-type list.
|
||||
- Finding is a support level mismatch (✅ vs ⚠️) — the type is already in YAML but at the wrong level.
|
||||
- Source contains only typedef declarations with no support table or ✅ indicators of any kind.
|
||||
- Type is explicitly marked AMD ❌ in an AMD/NVIDIA split table.
|
||||
|
||||
For auto-update findings, add the missing types to `~/projects/ROCm-internal/docs/data/reference/precision-support/precision-support.yaml`. Match the existing format exactly (type + support fields).
|
||||
|
||||
Then write a log to `~/projects/ROCm-internal/tools/autotag/precision-update-log/PREVIOUS-CURRENT-YYYYMMDD-HHMMSS.md` (replace PREVIOUS/CURRENT from $ARGUMENTS, timestamp from `date +%Y%m%d-%H%M%S`). Always create a new file — never read or overwrite an existing log. Log format:
|
||||
|
||||
```markdown
|
||||
# Precision support audit: ROCm PREVIOUS → CURRENT
|
||||
|
||||
**Date:** YYYY-MM-DD
|
||||
|
||||
## Auto-updated
|
||||
(table of types added, or "None")
|
||||
|
||||
## Flagged for human review
|
||||
(table of flags)
|
||||
|
||||
## Clean / skipped
|
||||
(table)
|
||||
```
|
||||
|
||||
## Step 6 — Output
|
||||
|
||||
Write your response now. Start with: "X of N libraries need verification."
|
||||
|
||||
Then the summary table. **This MUST be a markdown table — no lists, no separators, no other format.** One row per library, all libraries included:
|
||||
|
||||
| Library | Finding | Action | Source |
|
||||
|---------|---------|--------|--------|
|
||||
| ... | ... | ... | filename.ext |
|
||||
|
||||
Use the URL from `/tmp/precision_{lib}_url.txt`. In the Source column, write only the filename (last path segment, plain text — no markdown link). For skipped libraries, leave Source blank.
|
||||
|
||||
Then, **for flagged libraries only**, a detail block:
|
||||
|
||||
<!-- markdownlint-disable MD036 -->
|
||||
**{Library}**
|
||||
<!-- markdownlint-enable MD036 -->
|
||||
|
||||
- Finding: ...
|
||||
- Details: ...
|
||||
- Source: [filename](url) — full clickable link using the URL from `/tmp/precision_{lib}_url.txt`.
|
||||
- Recommended action: ...
|
||||
|
||||
Clean and skipped libraries appear only in the table — no detail block.
|
||||
|
||||
End with:
|
||||
|
||||
```text
|
||||
Changes written:
|
||||
- {library}: {types added}
|
||||
(or "None" if no auto-updates)
|
||||
```
|
||||
@@ -0,0 +1,110 @@
|
||||
Precision support delta check. Arguments: $ARGUMENTS = "previous_version current_version" (e.g. 7.1.1 7.2.0).
|
||||
|
||||
**Output rule:** Do not write any text until all tool calls are complete. When you are ready to respond, write exactly: "X of N libraries need verification." then the summary table, then detail blocks, then the "Changes written:" block. Nothing else. No narration, no transitions, no status updates, no reasoning.
|
||||
|
||||
## Step 1 — Fetch source files
|
||||
|
||||
```bash
|
||||
cd ~/projects/ROCm-internal/tools/precision-support && python3 precision_fetch.py -t "$GITHUB_TOKEN" --previous PREVIOUS --current CURRENT
|
||||
```
|
||||
|
||||
Replace PREVIOUS and CURRENT from $ARGUMENTS.
|
||||
|
||||
## Step 2 — Read library list
|
||||
|
||||
Read `/tmp/precision_libs.txt`.
|
||||
|
||||
## Step 3 — Parse each library
|
||||
|
||||
For each library in the list:
|
||||
|
||||
- Source file exists (`/tmp/precision_{lib}_source.txt`): read it and `/tmp/precision_{lib}_yaml.txt`, then compare.
|
||||
- URL file exists (`/tmp/precision_{lib}_url.txt`): read it — this is the GitHub link to the source file, used in the detail block Source field.
|
||||
- Skip file exists (`/tmp/precision_{lib}_skip.txt`): note the reason.
|
||||
|
||||
**Do not use GitHub MCP tools, WebFetch, or any network call.** All content is already in `/tmp/`. Use only the Read tool on those files.
|
||||
|
||||
You are the parser. Read the source file directly — do not infer from filenames or prior knowledge.
|
||||
|
||||
- RST files: look for list-tables, type listings, and support level indicators.
|
||||
- C headers: look for enums and macros that define supported types.
|
||||
- AMD/NVIDIA split tables: use the AMD column only.
|
||||
|
||||
## Step 4 — Known mismatches (do not flag)
|
||||
|
||||
These entries are **specific** — they exempt only the named type for the named library. They do not mark the entire library as clean. Continue checking all other types in every library.
|
||||
|
||||
- **hipBLAS float16**: YAML=⚠️ correct — only AXPY and Dot support it.
|
||||
- **hipBLAS bfloat16**: YAML=⚠️ correct — only Dot supports it.
|
||||
- **rocBLAS float16**: same partial-support pattern as hipBLAS — do not flag.
|
||||
- **rocBLAS bfloat16**: same partial-support pattern as hipBLAS — do not flag.
|
||||
- **MIGraphX int8**: YAML=⚠️ correct — quantization-only via `quantize_int8()`.
|
||||
- **rocFFT float16**: YAML already includes float16 ✅ — do not flag as missing.
|
||||
|
||||
**Do not dismiss any other gaps on your own judgment.** If a type appears in the source but not in the YAML, flag it — even if you think it might be intentional or covered by convention. That call belongs to the human reviewer, not you.
|
||||
|
||||
## Step 5 — Classify and update (silent)
|
||||
|
||||
For each finding, decide **auto-update** or **flag**:
|
||||
|
||||
**Default: auto-update.** If a type is absent from YAML and appears in the source, add it — unless one of the following exceptions applies.
|
||||
|
||||
**Flag for human review if ANY are true:**
|
||||
|
||||
- Found only via macro expansion (e.g., `MIGRAPHX_SHAPE_VISIT_TYPES`).
|
||||
- Found only in a combination table (Ti/To/Tc triplets) — not a canonical per-type list.
|
||||
- Finding is a support level mismatch (✅ vs ⚠️) — the type is already in YAML but at the wrong level.
|
||||
- Source contains only typedef declarations with no support table or ✅ indicators of any kind.
|
||||
- Type is explicitly marked AMD ❌ in an AMD/NVIDIA split table.
|
||||
|
||||
For auto-update findings, add the missing types to `~/projects/ROCm-internal/docs/data/reference/precision-support/precision-support.yaml`. Match the existing format exactly (type + support fields).
|
||||
|
||||
Then write a log to `~/projects/ROCm-internal/tools/precision-support/precision-update-log/PREVIOUS-CURRENT-YYYYMMDD-HHMMSS.md` (replace PREVIOUS/CURRENT from $ARGUMENTS, timestamp from `date +%Y%m%d-%H%M%S`). Always create a new file — never read or overwrite an existing log. Log format:
|
||||
|
||||
```markdown
|
||||
# Precision support audit: ROCm PREVIOUS → CURRENT
|
||||
|
||||
**Date:** YYYY-MM-DD
|
||||
|
||||
## Auto-updated
|
||||
(table of types added, or "None")
|
||||
|
||||
## Flagged for human review
|
||||
(table of flags)
|
||||
|
||||
## Clean / skipped
|
||||
(table)
|
||||
```
|
||||
|
||||
## Step 6 — Output
|
||||
|
||||
Write your response now. Start with: "X of N libraries need verification."
|
||||
|
||||
Then the summary table. **This MUST be a markdown table — no lists, no separators, no other format.** One row per library, all libraries included:
|
||||
|
||||
| Library | Finding | Action | Source |
|
||||
|---------|---------|--------|--------|
|
||||
| ... | ... | ... | filename.ext |
|
||||
|
||||
Use the URL from `/tmp/precision_{lib}_url.txt`. In the Source column, write only the filename (last path segment, plain text — no markdown link). For skipped libraries, leave Source blank.
|
||||
|
||||
Then, **for flagged libraries only**, a detail block:
|
||||
|
||||
<!-- markdownlint-disable MD036 -->
|
||||
**{Library}**
|
||||
<!-- markdownlint-enable MD036 -->
|
||||
|
||||
- Finding: ...
|
||||
- Details: ...
|
||||
- Source: [filename](url) — full clickable link using the URL from `/tmp/precision_{lib}_url.txt`.
|
||||
- Recommended action: ...
|
||||
|
||||
Clean and skipped libraries appear only in the table — no detail block.
|
||||
|
||||
End with:
|
||||
|
||||
```text
|
||||
Changes written:
|
||||
- {library}: {types added}
|
||||
(or "None" if no auto-updates)
|
||||
```
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(cd ~/projects/ROCm-internal/tools/autotag && python3 precision_fetch.py*)",
|
||||
"Read(/tmp/precision_*)",
|
||||
"Edit(docs/data/reference/precision-support/precision-support.yaml)",
|
||||
"Write(tools/autotag/precision-update-log/*)",
|
||||
"Write(precision-update-log/*)",
|
||||
"Bash(date +%Y%m%d-%H%M%S)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -19,3 +19,4 @@ __pycache__/
|
||||
docs/contribute/index.md
|
||||
docs/about/release-notes.md
|
||||
docs/release/changelog.md
|
||||
.claude/settings.local.json
|
||||
|
||||
@@ -42,6 +42,58 @@ python3 tag_script.py -t $GITHUB_ACCESS_TOKEN --no-release --no-pulls --compile_
|
||||
|
||||
* Copy over the first part of the changelog and replace the old release notes in RELEASE.md.
|
||||
|
||||
## Precision support audit (`/precision-check`, `/precision-check-delta`)
|
||||
|
||||
Audits data-type support across ROCm libraries between two releases. Uses a hybrid
|
||||
approach: `precision_fetch.py` fetches raw source files and YAML snapshots from
|
||||
GitHub to `/tmp/`, then Claude reads and compares them semantically via a slash
|
||||
command — no regex parsers.
|
||||
|
||||
### Commands
|
||||
|
||||
| Command | When to use |
|
||||
|---------|-------------|
|
||||
| `/precision-check PREV CURR` | Full audit — checks all libraries that changed in the manifest |
|
||||
| `/precision-check-delta PREV CURR` | SHA-filtered — only checks libraries whose source file itself changed |
|
||||
|
||||
Use `/precision-check-delta` for routine release-to-release audits. Use
|
||||
`/precision-check` for a full sweep regardless of source file changes.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* [Claude Code](https://claude.ai/claude-code) installed and running in this repo.
|
||||
* `$GITHUB_TOKEN` set to a GitHub Personal Access Token with read access to the ROCm org. Add it to your shell profile or pass it inline:
|
||||
|
||||
```sh
|
||||
export GITHUB_TOKEN=your_token_here
|
||||
```
|
||||
|
||||
### Running an audit
|
||||
|
||||
Open Claude Code in this repo and run:
|
||||
|
||||
```sh
|
||||
/precision-check 7.1.1 7.2.0
|
||||
# or
|
||||
/precision-check-delta 7.1.1 7.2.0
|
||||
```
|
||||
|
||||
Claude will:
|
||||
|
||||
1. Run `precision_fetch.py` to download source files and YAML snapshots to `/tmp/`.
|
||||
2. Read and compare each library's source against `precision-support.yaml`.
|
||||
3. Auto-update the YAML for clear missing entries.
|
||||
4. Flag ambiguous findings (macro expansion, combination tables, support level mismatches) for human review.
|
||||
5. Write a timestamped log to `tools/autotag/precision-update-log/` (gitignored — local only).
|
||||
|
||||
Commit any YAML changes. The YAML being audited lives at `docs/data/reference/precision-support/precision-support.yaml`.
|
||||
|
||||
### Adding new libraries to precision support
|
||||
|
||||
* Add an entry to `MANIFEST_TO_TAG` in `precision_fetch.py` mapping the manifest component name to the YAML tag.
|
||||
* Add an entry to `SOURCE_CONFIG` in `precision_fetch.py` with the org, repo, and path to the source file. Add a `note` field if the library should be permanently skipped.
|
||||
* Update `MONOREPO_LIBS` in `precision_fetch.py` if the library lives inside a monorepo (e.g. `rocm-libraries`).
|
||||
|
||||
## Adding new libraries/repositories
|
||||
|
||||
* Add the name or group of the repository (retrieved in default.xml in the ROCm project root) to: included_names or included_groups to auto_tag.py.
|
||||
@@ -0,0 +1,261 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compare two ROCm default.xml manifests to detect component additions,
|
||||
removals, and version changes between releases or RCs.
|
||||
|
||||
Usage:
|
||||
python3 manifest_diff.py previous.xml current.xml
|
||||
python3 manifest_diff.py 7.1.1 7.2.0 # fetch from GitHub by tag
|
||||
python3 manifest_diff.py 7.2.0 7.2.1 # e.g. RC comparison
|
||||
|
||||
The script accepts either local file paths or ROCm version strings.
|
||||
When given version strings, it fetches default.xml from the ROCm/ROCm
|
||||
GitHub repo at the corresponding tag (rocm-X.Y.Z).
|
||||
|
||||
Output:
|
||||
A report of added, removed, and version-changed components, plus
|
||||
a summary count.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
from dataclasses import dataclass
|
||||
from urllib.request import urlopen, Request
|
||||
from urllib.error import URLError
|
||||
|
||||
|
||||
_GITHUB_RAW = (
|
||||
"https://raw.githubusercontent.com/ROCm/ROCm/release/rocm-rel-{branch}/default.xml"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Manifest parsing
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@dataclass
|
||||
class Project:
|
||||
name: str
|
||||
revision: str # effective revision (project-level override or default)
|
||||
path: str # repo checkout path (may differ from name)
|
||||
groups: str # groups attribute if present
|
||||
|
||||
|
||||
def _extract_version(revision: str) -> str:
|
||||
"""Extract a human-readable version from a revision string.
|
||||
|
||||
refs/tags/rocm-7.2.0 → 7.2.0
|
||||
refs/tags/v1.2.3 → v1.2.3
|
||||
refs/heads/develop → develop (branch)
|
||||
abc1234 → abc1234 (commit SHA)
|
||||
"""
|
||||
# Named ROCm release tag
|
||||
m = re.search(r"refs/tags/rocm-(.+)", revision)
|
||||
if m:
|
||||
return m.group(1)
|
||||
# Generic tag
|
||||
m = re.search(r"refs/tags/(.+)", revision)
|
||||
if m:
|
||||
return m.group(1)
|
||||
# Branch
|
||||
m = re.search(r"refs/heads/(.+)", revision)
|
||||
if m:
|
||||
return f"[branch: {m.group(1)}]"
|
||||
# Bare SHA or anything else
|
||||
return revision
|
||||
|
||||
|
||||
def parse_manifest(path_or_content: str, from_string: bool = False) -> dict[str, Project]:
|
||||
"""Parse a manifest XML file (or string) and return {name: Project}."""
|
||||
if from_string:
|
||||
root = ET.fromstring(path_or_content)
|
||||
else:
|
||||
root = ET.parse(path_or_content).getroot()
|
||||
|
||||
default_el = root.find("default")
|
||||
default_revision = default_el.get("revision", "") if default_el is not None else ""
|
||||
|
||||
projects: dict[str, Project] = {}
|
||||
for el in root.iterfind("project"):
|
||||
name = el.get("name", "")
|
||||
if not name:
|
||||
continue
|
||||
revision = el.get("revision") or default_revision
|
||||
path = el.get("path", name)
|
||||
groups = el.get("groups", "")
|
||||
projects[name] = Project(name=name, revision=revision, path=path, groups=groups)
|
||||
|
||||
return projects
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fetching from GitHub
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _looks_like_version(s: str) -> bool:
|
||||
return bool(re.match(r"^\d+\.\d+", s))
|
||||
|
||||
|
||||
_GITHUB_RAW_TAG = (
|
||||
"https://raw.githubusercontent.com/ROCm/ROCm/refs/tags/rocm-{version}/default.xml"
|
||||
)
|
||||
|
||||
|
||||
def fetch_manifest(source: str) -> dict[str, Project]:
|
||||
"""Load a manifest from a local file path or a ROCm version string.
|
||||
|
||||
When given a version string, tries the release branch first (release/rocm-rel-X.Y),
|
||||
then falls back to the release tag (rocm-X.Y.Z) for older releases.
|
||||
"""
|
||||
if _looks_like_version(source):
|
||||
branch = ".".join(source.split(".")[:2])
|
||||
branch_url = _GITHUB_RAW.format(branch=branch)
|
||||
tag_url = _GITHUB_RAW_TAG.format(version=source)
|
||||
for url in (branch_url, tag_url):
|
||||
print(f" Fetching {url}", file=sys.stderr)
|
||||
try:
|
||||
req = Request(url, headers={"User-Agent": "rocm-manifest-diff/1.0"})
|
||||
with urlopen(req, timeout=30) as resp:
|
||||
return parse_manifest(resp.read().decode(), from_string=True)
|
||||
except URLError as e:
|
||||
if hasattr(e, "code") and e.code == 404:
|
||||
continue
|
||||
raise SystemExit(f"Cannot fetch manifest for ROCm {source}:\n {e}")
|
||||
raise SystemExit(f"Cannot fetch manifest for ROCm {source}: not found at branch or tag.")
|
||||
else:
|
||||
return parse_manifest(source)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Diff logic
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@dataclass
|
||||
class Change:
|
||||
name: str
|
||||
prev_version: str = ""
|
||||
curr_version: str = ""
|
||||
|
||||
|
||||
def diff_manifests(
|
||||
prev: dict[str, Project],
|
||||
curr: dict[str, Project],
|
||||
) -> tuple[list[str], list[str], list[Change], list[str]]:
|
||||
"""Return (added, removed, version_changed, unchanged) component lists."""
|
||||
prev_names = set(prev)
|
||||
curr_names = set(curr)
|
||||
|
||||
added = sorted(curr_names - prev_names)
|
||||
removed = sorted(prev_names - curr_names)
|
||||
|
||||
version_changed: list[Change] = []
|
||||
unchanged: list[str] = []
|
||||
|
||||
for name in sorted(prev_names & curr_names):
|
||||
pv = _extract_version(prev[name].revision)
|
||||
cv = _extract_version(curr[name].revision)
|
||||
if pv != cv:
|
||||
version_changed.append(Change(name, pv, cv))
|
||||
else:
|
||||
unchanged.append(name)
|
||||
|
||||
return added, removed, version_changed, unchanged
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Report
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def print_report(
|
||||
prev_label: str,
|
||||
curr_label: str,
|
||||
added: list[str],
|
||||
removed: list[str],
|
||||
version_changed: list[Change],
|
||||
unchanged: list[str],
|
||||
show_unchanged: bool = False,
|
||||
) -> None:
|
||||
print(f"\nManifest diff: {prev_label} → {curr_label}\n")
|
||||
|
||||
if added:
|
||||
print(f"ADDED ({len(added)}):")
|
||||
for name in added:
|
||||
print(f" + {name}")
|
||||
print()
|
||||
|
||||
if removed:
|
||||
print(f"REMOVED ({len(removed)}):")
|
||||
for name in removed:
|
||||
print(f" - {name}")
|
||||
print(
|
||||
" Note: removals may reflect migration into rocm-libraries or\n"
|
||||
" rocm-systems rather than a component drop. Verify before\n"
|
||||
" updating release notes."
|
||||
)
|
||||
print()
|
||||
|
||||
if version_changed:
|
||||
col = max(len(c.name) for c in version_changed)
|
||||
print(f"VERSION CHANGED ({len(version_changed)}):")
|
||||
for c in version_changed:
|
||||
print(f" {c.name:<{col}} {c.prev_version} → {c.curr_version}")
|
||||
print()
|
||||
|
||||
if show_unchanged and unchanged:
|
||||
print(f"UNCHANGED ({len(unchanged)}):")
|
||||
for name in unchanged:
|
||||
print(f" {name}")
|
||||
print()
|
||||
|
||||
total = len(added) + len(removed) + len(version_changed) + len(unchanged)
|
||||
print(
|
||||
f"Summary: {len(added)} added, {len(removed)} removed, "
|
||||
f"{len(version_changed)} version changed, {len(unchanged)} unchanged "
|
||||
f"({total} total)"
|
||||
)
|
||||
|
||||
if not added and not removed and not version_changed:
|
||||
print("\nNo component changes detected.")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Entry point
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Diff two ROCm manifest files to detect component changes."
|
||||
)
|
||||
parser.add_argument(
|
||||
"previous",
|
||||
help="Previous manifest — local file path or ROCm version (e.g. 7.1.1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"current",
|
||||
help="Current manifest — local file path or ROCm version (e.g. 7.2.0)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--unchanged", action="store_true",
|
||||
help="Also list components with no version change",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
prev = fetch_manifest(args.previous)
|
||||
curr = fetch_manifest(args.current)
|
||||
|
||||
added, removed, version_changed, unchanged = diff_manifests(prev, curr)
|
||||
|
||||
print_report(
|
||||
prev_label=args.previous,
|
||||
curr_label=args.current,
|
||||
added=added,
|
||||
removed=removed,
|
||||
version_changed=version_changed,
|
||||
unchanged=unchanged,
|
||||
show_unchanged=args.unchanged,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1 @@
|
||||
*.md
|
||||
@@ -0,0 +1,480 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fetch precision support source files and YAML for Claude to compare.
|
||||
|
||||
Writes raw content to /tmp/ for the Claude precision-check command.
|
||||
Claude reads the files and does the comparison — no regex parsers used.
|
||||
|
||||
Usage (manifest-scoped — full audit):
|
||||
python3 precision_fetch.py -t $GITHUB_TOKEN --previous 7.1.1 --current 7.2.0
|
||||
|
||||
Usage (SHA-filtered — only libraries whose source file changed):
|
||||
python3 precision_fetch.py -t $GITHUB_TOKEN --previous 7.1.1 --current 7.2.0 --sha-filter
|
||||
|
||||
Usage (explicit library list):
|
||||
python3 precision_fetch.py -t $GITHUB_TOKEN --version 7.2.0 --libs hipblas,hipsparselt
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from urllib.error import HTTPError, URLError
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
sys.exit("pyyaml is required: pip install pyyaml")
|
||||
|
||||
from manifest_diff import fetch_manifest, diff_manifests
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Monorepo expansion
|
||||
# ---------------------------------------------------------------------------
|
||||
# Some manifest entries are monorepos covering multiple precision-tracked
|
||||
# libraries. When one of these appears in the manifest diff, expand it to
|
||||
# all tracked sub-libraries rather than treating it as a single component.
|
||||
|
||||
MONOREPO_LIBS: dict[str, list[str]] = {
|
||||
"rocm-libraries": [
|
||||
"hipBLAS", "hipBLASLt", "hipFFT", "hipRAND",
|
||||
"hipSOLVER", "hipSPARSE", "hipSPARSELt", "hipTensor", "hipCUB",
|
||||
"rocBLAS", "rocFFT", "rocRAND", "rocSOLVER", "rocSPARSE",
|
||||
"rocWMMA", "rocPRIM", "rocThrust", "Tensile",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Mapping: manifest component name → YAML library tag
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
MANIFEST_TO_TAG: dict[str, str] = {
|
||||
"hipBLAS": "hipblas",
|
||||
"hipBLASLt": "hipblaslt",
|
||||
"hipFFT": "hipfft",
|
||||
"hipRAND": "hiprand",
|
||||
"hipSOLVER": "hipsolver",
|
||||
"hipSPARSE": "hipsparse",
|
||||
"hipSPARSELt": "hipsparselt",
|
||||
"hipTensor": "hiptensor",
|
||||
"hipCUB": "hipcub",
|
||||
"rocBLAS": "rocblas",
|
||||
"rocFFT": "rocfft",
|
||||
"rocRAND": "rocrand",
|
||||
"rocSOLVER": "rocsolver",
|
||||
"rocSPARSE": "rocsparse",
|
||||
"rocWMMA": "rocwmma",
|
||||
"rocPRIM": "rocprim",
|
||||
"rocThrust": "rocthrust",
|
||||
"composable_kernel": "composable-kernel",
|
||||
"MIOpen": "miopen",
|
||||
"AMDMIGraphX": "migraphx",
|
||||
"rccl": "rccl",
|
||||
"Tensile": "tensile",
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Source config: YAML tag → GitHub fetch details
|
||||
# ---------------------------------------------------------------------------
|
||||
# Each entry defines where to fetch the authoritative source file for a library.
|
||||
# org: GitHub org (default "ROCm")
|
||||
# repo: GitHub repo name
|
||||
# path: Path to the source file within the repo
|
||||
# note: Set if the library is skipped or has no parseable source
|
||||
|
||||
SOURCE_CONFIG: dict[str, dict] = {
|
||||
"hipblas": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/hipblas/docs/reference/data-type-support.rst",
|
||||
},
|
||||
"hipblaslt": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/hipblaslt/docs/reference/data-type-support.rst",
|
||||
},
|
||||
"hipfft": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/hipfft/docs/reference/hipfft-api-usage.rst",
|
||||
},
|
||||
"hiprand": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/hiprand/docs/api-reference/data-type-support.rst",
|
||||
},
|
||||
"hipsolver": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/hipsolver/docs/reference/precision.rst",
|
||||
},
|
||||
"hipsparse": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/hipsparse/docs/reference/precision.rst",
|
||||
},
|
||||
"hipsparselt": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/hipsparselt/docs/reference/data-type-support.rst",
|
||||
},
|
||||
"hiptensor": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/hiptensor/docs/api-reference/api-reference.rst",
|
||||
},
|
||||
"hipcub": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/hipcub/docs/api-reference/data-type-support.rst",
|
||||
"note": "No data-type-support page exists — hipCUB is header-only and type-agnostic",
|
||||
},
|
||||
"rocblas": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/rocblas/docs/reference/data-type-support.rst",
|
||||
},
|
||||
"rocfft": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/rocfft/library/include/rocfft/rocfft.h",
|
||||
},
|
||||
"rocrand": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/rocrand/docs/api-reference/data-type-support.rst",
|
||||
},
|
||||
"rocsolver": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/rocsolver/docs/reference/precision.rst",
|
||||
},
|
||||
"rocsparse": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/rocsparse/docs/reference/precision.rst",
|
||||
},
|
||||
"rocwmma": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/rocwmma/docs/api-reference/api-reference-guide.rst",
|
||||
},
|
||||
"rocprim": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/rocprim/docs/reference/data-type-support.rst",
|
||||
},
|
||||
"rocthrust": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/rocthrust/docs/data-type-support.rst",
|
||||
"note": "No data-type-support page exists — rocThrust is a template library and type-agnostic",
|
||||
},
|
||||
"composable-kernel": {
|
||||
"org": "ROCm",
|
||||
"repo": "composable_kernel",
|
||||
"path": "docs/reference/Composable_Kernel_supported_scalar_types.rst",
|
||||
},
|
||||
"miopen": {
|
||||
"org": "ROCm",
|
||||
"repo": "MIOpen",
|
||||
"path": "docs/reference/datatypes.rst",
|
||||
},
|
||||
"migraphx": {
|
||||
"org": "ROCm",
|
||||
"repo": "AMDMIGraphX",
|
||||
"path": "src/api/include/migraphx/migraphx.h",
|
||||
},
|
||||
"rccl": {
|
||||
"org": "ROCm",
|
||||
"repo": "rccl",
|
||||
"path": "src/nccl.h.in",
|
||||
},
|
||||
"tensile": {
|
||||
"org": "ROCm",
|
||||
"repo": "rocm-libraries",
|
||||
"path": "projects/hipblaslt/tensilelite/Tensile/docs/src/reference/precision-support.rst",
|
||||
"note": "Tensile has no docs folder — it is an internal kernel generator, not a user-facing library",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# GitHub helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_GH_API = "https://api.github.com"
|
||||
|
||||
|
||||
def _gh_request(token: str, url: str) -> dict:
|
||||
req = Request(url, headers={
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Accept": "application/vnd.github+json",
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
})
|
||||
with urlopen(req, timeout=30) as resp:
|
||||
return json.loads(resp.read())
|
||||
|
||||
|
||||
def _version_to_ref(version: str) -> str:
|
||||
"""Convert a ROCm version string to a release branch ref.
|
||||
|
||||
e.g. '7.2.0' → 'release/rocm-rel-7.2'
|
||||
"""
|
||||
major_minor = ".".join(version.split(".")[:2])
|
||||
return f"release/rocm-rel-{major_minor}"
|
||||
|
||||
|
||||
def fetch_yaml(token: str, version: str) -> dict:
|
||||
"""Fetch precision-support.yaml from the ROCm/ROCm repo.
|
||||
|
||||
Tries the release branch first, falls back to the release tag.
|
||||
"""
|
||||
path = "docs/data/reference/precision-support/precision-support.yaml"
|
||||
for ref in _refs_for_version(version):
|
||||
url = f"{_GH_API}/repos/ROCm/ROCm/contents/{path}?ref={ref}"
|
||||
try:
|
||||
data = _gh_request(token, url)
|
||||
return yaml.safe_load(base64.b64decode(data["content"]).decode())
|
||||
except HTTPError as e:
|
||||
if e.code in (401, 403):
|
||||
sys.exit(f"GitHub authentication failed (HTTP {e.code}) — check your token.")
|
||||
continue
|
||||
except URLError as e:
|
||||
sys.exit(f"Network error: {e}")
|
||||
sys.exit(f"Cannot fetch precision-support.yaml for ROCm {version}: not found at branch or tag.")
|
||||
|
||||
|
||||
def _refs_for_version(version: str) -> list[str]:
|
||||
"""Return refs to try in order: release branch first, tag as fallback."""
|
||||
return [_version_to_ref(version), f"rocm-{version}"]
|
||||
|
||||
|
||||
def fetch_file_sha(token: str, org: str, repo_name: str, path: str, version: str) -> str | None:
|
||||
"""Return the blob SHA of a file at the given ROCm version, or None if not found.
|
||||
|
||||
Tries the release branch first, falls back to the release tag.
|
||||
"""
|
||||
for ref in _refs_for_version(version):
|
||||
url = f"{_GH_API}/repos/{org}/{repo_name}/contents/{path}?ref={ref}"
|
||||
try:
|
||||
data = _gh_request(token, url)
|
||||
return data.get("sha")
|
||||
except HTTPError as e:
|
||||
if e.code in (401, 403):
|
||||
sys.exit(f"GitHub authentication failed (HTTP {e.code}) — check your token.")
|
||||
continue
|
||||
except URLError as e:
|
||||
sys.exit(f"Network error fetching SHA for {path}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def fetch_source_file(token: str, org: str, repo_name: str, path: str, version: str) -> str | None:
|
||||
"""Fetch a source file from GitHub at the given ROCm version.
|
||||
|
||||
Tries the release branch first, falls back to the release tag.
|
||||
Returns the file content as a string, or None if not found at either ref.
|
||||
"""
|
||||
for ref in _refs_for_version(version):
|
||||
url = f"{_GH_API}/repos/{org}/{repo_name}/contents/{path}?ref={ref}"
|
||||
try:
|
||||
data = _gh_request(token, url)
|
||||
return base64.b64decode(data["content"]).decode()
|
||||
except HTTPError as e:
|
||||
if e.code in (401, 403):
|
||||
sys.exit(f"GitHub authentication failed (HTTP {e.code}) — check your token.")
|
||||
continue
|
||||
except URLError as e:
|
||||
sys.exit(f"Network error fetching {path}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def load_yaml_types(yaml_data: dict) -> dict[str, dict[str, str]]:
|
||||
"""Return {tag: {type: support}} from precision-support.yaml."""
|
||||
result: dict[str, dict[str, str]] = {}
|
||||
for group in yaml_data.get("library_groups", []):
|
||||
for lib in group.get("libraries", []):
|
||||
tag = lib["tag"]
|
||||
result[tag] = {dt["type"]: dt["support"] for dt in lib.get("data_types", [])}
|
||||
return result
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Scoping
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def sha_filter_scope(token: str, previous: str, current: str) -> list[str]:
|
||||
"""Return sorted list of library tags where the source file changed between two ROCm versions.
|
||||
|
||||
Checks all tracked libraries — no manifest diff. Skips libraries where the
|
||||
source file SHA is identical at both tags, writing a skip file so Claude knows why.
|
||||
"""
|
||||
print(f"SHA-filtering all tracked libraries {previous} → {current}...", file=sys.stderr)
|
||||
changed = []
|
||||
for lib, config in SOURCE_CONFIG.items():
|
||||
if config.get("note"):
|
||||
continue # permanently skipped libraries (type-agnostic, internal, etc.)
|
||||
org, repo, path = config["org"], config["repo"], config["path"]
|
||||
sha_prev = fetch_file_sha(token, org, repo, path, previous)
|
||||
sha_curr = fetch_file_sha(token, org, repo, path, current)
|
||||
if sha_prev is None and sha_curr is None:
|
||||
Path(f"/tmp/precision_{lib}_skip.txt").write_text(
|
||||
f"Source file not found at either {previous} or {current}",
|
||||
encoding="utf-8",
|
||||
)
|
||||
print(f" {lib}: not found at either version — skip", file=sys.stderr)
|
||||
elif sha_prev == sha_curr:
|
||||
Path(f"/tmp/precision_{lib}_skip.txt").write_text(
|
||||
f"Source file unchanged between {previous} and {current} (SHA match)",
|
||||
encoding="utf-8",
|
||||
)
|
||||
print(f" {lib}: unchanged — skip", file=sys.stderr)
|
||||
else:
|
||||
changed.append(lib)
|
||||
print(f" {lib}: changed — include", file=sys.stderr)
|
||||
print(f" {len(changed)} libraries with changed source files", file=sys.stderr)
|
||||
return sorted(changed)
|
||||
|
||||
|
||||
def scope_from_manifest(token: str, previous: str, current: str) -> list[str]:
|
||||
"""Return sorted list of library tags that changed between two ROCm versions."""
|
||||
print(f"Diffing manifests {previous} → {current}...", file=sys.stderr)
|
||||
prev_manifest = fetch_manifest(previous)
|
||||
curr_manifest = fetch_manifest(current)
|
||||
added, removed, version_changed, _ = diff_manifests(prev_manifest, curr_manifest)
|
||||
|
||||
changed_components = (
|
||||
set(added)
|
||||
| set(removed)
|
||||
| {c.name for c in version_changed}
|
||||
)
|
||||
|
||||
# Expand monorepo entries
|
||||
for monorepo, sub_libs in MONOREPO_LIBS.items():
|
||||
if monorepo in changed_components:
|
||||
changed_components |= set(sub_libs)
|
||||
|
||||
tags = sorted(
|
||||
MANIFEST_TO_TAG[name]
|
||||
for name in changed_components
|
||||
if name in MANIFEST_TO_TAG
|
||||
)
|
||||
print(f" {len(changed_components)} components changed → {len(tags)} tracked libraries", file=sys.stderr)
|
||||
return tags
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fetching
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def fetch_library(token: str, lib: str, version: str) -> None:
|
||||
"""Fetch source file and YAML entry for one library, write to /tmp/."""
|
||||
config = SOURCE_CONFIG.get(lib)
|
||||
if not config:
|
||||
print(f" {lib}: no SOURCE_CONFIG entry — skipping", file=sys.stderr)
|
||||
return
|
||||
|
||||
note = config.get("note")
|
||||
if note:
|
||||
Path(f"/tmp/precision_{lib}_skip.txt").write_text(note, encoding="utf-8")
|
||||
print(f" {lib}: skipped — {note}", file=sys.stderr)
|
||||
return
|
||||
|
||||
content = fetch_source_file(
|
||||
token,
|
||||
config["org"],
|
||||
config["repo"],
|
||||
config["path"],
|
||||
version,
|
||||
)
|
||||
|
||||
if content is None:
|
||||
Path(f"/tmp/precision_{lib}_skip.txt").write_text(
|
||||
f"Source file not found: {config['path']}", encoding="utf-8"
|
||||
)
|
||||
print(f" {lib}: source file not found", file=sys.stderr)
|
||||
return
|
||||
|
||||
Path(f"/tmp/precision_{lib}_source.txt").write_text(content, encoding="utf-8")
|
||||
|
||||
ref = _version_to_ref(version)
|
||||
gh_url = f"https://github.com/{config['org']}/{config['repo']}/blob/{ref}/{config['path']}"
|
||||
Path(f"/tmp/precision_{lib}_url.txt").write_text(gh_url, encoding="utf-8")
|
||||
|
||||
print(f" {lib}: source written ({len(content):,} chars)", file=sys.stderr)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Entry point
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Fetch precision support source files for Claude to compare."
|
||||
)
|
||||
parser.add_argument("-t", "--token", required=True, help="GitHub personal access token")
|
||||
|
||||
mode = parser.add_mutually_exclusive_group(required=True)
|
||||
mode.add_argument("--previous", help="Previous ROCm version (use with --current)")
|
||||
mode.add_argument("--version", help="ROCm version for explicit --libs mode")
|
||||
|
||||
parser.add_argument("--current", help="Current ROCm version (use with --previous)")
|
||||
parser.add_argument("--libs", help="Comma-separated library tags (use with --version)")
|
||||
parser.add_argument(
|
||||
"--sha-filter",
|
||||
action="store_true",
|
||||
help="Check all tracked libraries; skip those whose source file SHA is unchanged. "
|
||||
"Use with --previous/--current. No manifest diff is performed.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Resolve version and library list
|
||||
if args.previous:
|
||||
if not args.current:
|
||||
sys.exit("--current is required when using --previous")
|
||||
current_version = args.current
|
||||
if args.sha_filter:
|
||||
libs = sha_filter_scope(args.token, args.previous, args.current)
|
||||
else:
|
||||
libs = scope_from_manifest(args.token, args.previous, args.current)
|
||||
else:
|
||||
if args.sha_filter:
|
||||
sys.exit("--sha-filter requires --previous and --current")
|
||||
if not args.libs:
|
||||
sys.exit("--libs is required when using --version")
|
||||
current_version = args.version
|
||||
libs = [lib.strip() for lib in args.libs.split(",")]
|
||||
|
||||
# Fetch YAML once
|
||||
print(f"\nFetching precision-support.yaml for ROCm {current_version}...", file=sys.stderr)
|
||||
yaml_data = fetch_yaml(args.token, current_version)
|
||||
yaml_types = load_yaml_types(yaml_data)
|
||||
|
||||
# Write YAML entries for all tracked libraries (not just changed ones —
|
||||
# Claude needs the full context for comparison)
|
||||
for lib, types in yaml_types.items():
|
||||
Path(f"/tmp/precision_{lib}_yaml.txt").write_text(
|
||||
yaml.dump({lib: types}, allow_unicode=True, default_flow_style=False),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
# Write manifest-scoped library list so Claude knows what to check
|
||||
libs_file = Path("/tmp/precision_libs.txt")
|
||||
libs_file.write_text("\n".join(libs), encoding="utf-8")
|
||||
print(f"\nLibraries to check: {', '.join(libs)}", file=sys.stderr)
|
||||
|
||||
# Fetch source files
|
||||
print("\nFetching source files...", file=sys.stderr)
|
||||
for lib in libs:
|
||||
fetch_library(args.token, lib, current_version)
|
||||
|
||||
print(f"\nDone. Files written to /tmp/precision_*", file=sys.stderr)
|
||||
print(f"Library list: /tmp/precision_libs.txt", file=sys.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user