Each script in this repo is designed as a standalone single-file download. Users run:
curl -sSL https://raw.githubusercontent.com/.../nvidia-install.sh | sudo bashThis means every script must be self-contained — no source, no external dependencies. Language packs (~700 lines per script) are currently copy-pasted into each script manually, leading to:
- Duplicated translations across scripts
- Manual sync errors when updating translations
- Business logic buried under hundreds of lines of language pack data
- Painful workflow: edit
.pot→ runlanguage_pack_generate.py→ manually copy output into script
Separate language packs from business logic at development time, automatically merge them at build time.
├── cuda-install.sh # Final script with embedded lang packs
├── nvidia-install.sh # Final script with embedded lang packs
├── nvidia-container-installer.sh
├── nvidia-container-uninstall.sh
├── nvidia-uninstall.sh
├── language_packs/
│ ├── ZH_CN.pot # nvidia-install.sh translations (source)
│ ├── ZH_CN.sh # nvidia-install.sh translations (generated)
│ ├── EN_US.pot
│ └── EN_US.sh
└── language_pack_generate.py # .pot → .sh converter
├── src/ # Template scripts (no embedded lang packs)
│ ├── nvidia-install.sh
│ ├── cuda-install.sh
│ ├── nvidia-container-installer.sh
│ ├── nvidia-container-uninstall.sh
│ └── nvidia-uninstall.sh
│
├── lang/ # Language packs, organized by script
│ ├── nvidia-install/
│ │ ├── ZH_CN.sh
│ │ └── EN_US.sh
│ ├── cuda-install/
│ │ ├── ZH_CN.sh
│ │ └── EN_US.sh
│ ├── nvidia-container-installer/
│ │ ├── ZH_CN.sh
│ │ └── EN_US.sh
│ ├── nvidia-container-uninstall/
│ │ ├── ZH_CN.sh
│ │ └── EN_US.sh
│ └── nvidia-uninstall/
│ ├── ZH_CN.sh
│ └── EN_US.sh
│
├── scripts/
│ ├── build.py # Template + lang packs → final scripts
│ └── extract_keys.py # Extract gettext keys from src/ for translation
│
├── dist/ # Build output (gitignored)
│ ├── nvidia-install.sh
│ ├── cuda-install.sh
│ └── ...
│
├── .github/workflows/
│ └── release.yml # Auto-build on release
│
├── language_packs/ # Deprecated, migrated to lang/
├── language_pack_generate.py # Deprecated, replaced by scripts/build.py
└── PLAN.md
Each template script contains a single placeholder where language packs will be injected:
#!/bin/bash
set -eo pipefail
readonly SCRIPT_VERSION="2.2"
# Color definitions...
# Exit code definitions...
# Global variables...
# ================ Language Packs ==================
# {{LANG_PACKS}}
# ================ Language Packs End ==============
gettext() {
local msgid="$1"
local translation=""
case "$LANG_CURRENT" in
"zh-cn"|"zh"|"zh_CN") translation="${LANG_PACK_ZH_CN[$msgid]:-}" ;;
"en-us"|"en"|"en_US") translation="${LANG_PACK_EN_US[$msgid]:-}" ;;
*) translation="${LANG_PACK_ZH_CN[$msgid]:-}" ;;
esac
if [[ -z "$translation" ]]; then
translation="$msgid" # Fallback: return key itself
fi
printf '%s' "$translation"
}
# ... rest of business logic ...Plain bash associative array declarations, one file per language per script:
# lang/cuda-install/ZH_CN.sh
declare -A LANG_PACK_ZH_CN
LANG_PACK_ZH_CN=(
["log.starting"]="开始执行 CUDA Toolkit 安装脚本"
["log.root_check.fail"]="此脚本需要 root 权限运行"
# ...
)For each src/<name>.sh:
1. Read template content
2. Find all lang/<name>/*.sh files
3. Concatenate language pack contents
4. Replace `# {{LANG_PACKS}}` with concatenated content
5. Write to dist/<name>.sh
6. chmod +x dist/<name>.sh
# Build all scripts
python3 scripts/build.py
# Build a specific script
python3 scripts/build.py --target cuda-install
# Build with specific languages only (e.g., for testing)
python3 scripts/build.py --langs ZH_CN,EN_US
# Output to custom directory
python3 scripts/build.py --outdir ./releaseThe build script should also:
- Verify all
gettextkeys used insrc/*.shexist in every language pack - Warn about unused keys in language packs
- Fail if any language pack has syntax errors (
bash -n) - Run
bash -non the final output
name: Build and Release
on:
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Build scripts
run: python3 scripts/build.py --outdir ./dist
- name: Verify syntax
run: |
for f in dist/*.sh; do
bash -n "$f"
echo "✓ $f"
done
- name: Upload release assets
uses: softprops/action-gh-release@v2
with:
files: dist/*.shname: CI
on:
pull_request:
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build scripts
run: python3 scripts/build.py
- name: Syntax check
run: |
for f in dist/*.sh; do
bash -n "$f"
done
- name: Verify translation completeness
run: python3 scripts/build.py --check-keysScans src/*.sh for all gettext "..." calls and outputs a list of required keys. This helps translators know what needs translating.
# Show all keys used in cuda-install.sh
python3 scripts/extract_keys.py src/cuda-install.sh
# Compare with existing language pack, show missing translations
python3 scripts/extract_keys.py src/cuda-install.sh --diff lang/cuda-install/EN_US.sh- Add
$(gettext "new.key.name")insrc/<script>.sh - Add
["new.key.name"]="Translation"to eachlang/<script>/<LANG>.sh - Run
python3 scripts/build.pyto verify - Commit
src/andlang/changes (notdist/)
- Create
lang/<script>/<LANG>.shfor each script (copy from existing and translate) - Update
gettext()function in templates to recognize the new language code - Run
python3 scripts/build.py— new language is automatically included
# Build and test locally
python3 scripts/build.py
sudo bash dist/nvidia-install.sh --help
# Or run template directly (works, but shows raw keys instead of translations)
sudo bash src/nvidia-install.sh --help- Create
scripts/build.py - Create
scripts/extract_keys.py - Add
dist/to.gitignore
For each script:
- Copy script to
src/<name>.sh - Extract language pack section from
src/<name>.shtolang/<name>/ZH_CN.shandlang/<name>/EN_US.sh - Replace extracted section with
# {{LANG_PACKS}}placeholder - Run
python3 scripts/build.pyand verifydist/<name>.shmatches original
- Create
.github/workflows/release.yml - Create
.github/workflows/ci.yml - Test with a pre-release
- Remove root-level script files (they now live in
src/) - Remove old
language_packs/directory - Remove old
language_pack_generate.py - Update
README.mdwith new development workflow - Update raw download URLs in documentation to point to release assets instead of raw repo files
The download instructions currently point to raw repo files:
# Before (points to repo, which will now be a template)
curl -sSL https://raw.githubusercontent.com/.../main/nvidia-install.sh
# After (points to latest release asset)
curl -sSL https://github.com/.../releases/latest/download/nvidia-install.sh- Existing users may have bookmarked raw GitHub URLs
- Keep root-level scripts for one release cycle as a transitional measure, or add a redirect/notice
The gettext() function already returns the raw key when no translation is found. This means:
- Templates are runnable without building (just with raw keys shown)
- Missing translations degrade gracefully
- New keys don't break existing language packs
scripts/build.pyshould be deterministic (same input → same output)- Consider embedding a build timestamp or commit hash in the output for traceability:
# Auto-generated from template. Do not edit directly. # Build: 2026-02-17T12:00:00Z (commit abc1234)
nvidia-install.sh maintains a hand-curated database of ~294 NVIDIA GPU PCI device IDs across 7 architectures (Maxwell → Blackwell) in init_gpu_database(). This database is used to determine:
- GPU architecture (for open vs proprietary kernel module selection)
- Whether a detected GPU is known/supported
Manual maintenance has issues:
- New GPUs are released regularly — database quickly becomes stale
- Missing IDs cause false "Unknown" architecture detection, leading to wrong module selection
- No systematic way to verify completeness against real-world device IDs
The PCI ID Repository (also mirrored at pciutils/pciids) maintains a comprehensive database of all PCI devices. NVIDIA is vendor 10de with 800+ device entries.
Key insight: NVIDIA device names in pci.ids consistently contain chip code prefixes that directly map to architectures:
| Chip Code Prefix | Architecture | Open Module Support |
|---|---|---|
| GK | Kepler | No (EOL) |
| GM | Maxwell | No |
| GP | Pascal | No |
| GV | Volta | No |
| TU | Turing | Yes |
| GA | Ampere | Yes |
| GH | Hopper | Yes (datacenter) |
| AD | Ada Lovelace | Yes |
| GB | Blackwell | Yes |
Example entries from pci.ids:
1b80 GP104 [GeForce GTX 1080] → prefix GP → Pascal
2204 GA102 [GeForce RTX 3090] → prefix GA → Ampere
2684 AD102 [GeForce RTX 4090] → prefix AD → Ada Lovelace
Extract the GPU ID database from the script into a standalone data file:
# data/gpu-ids.sh
# Auto-generated from pci.ids — do not edit manually
# Source: https://pci-ids.ucw.cz/
# Generated: 2026-02-17T12:00:00Z
# Total IDs: 450+
GPU_IDS_MAXWELL=("1340" "1341" "1344" ... )
GPU_IDS_PASCAL=("15f7" "15f8" "15f9" ... )
GPU_IDS_VOLTA=("1db0" "1db1" ... )
GPU_IDS_TURING=("1e02" "1e04" ... )
GPU_IDS_AMPERE=("2204" "2205" ... )
GPU_IDS_HOPPER=("2321" "2322" ... )
GPU_IDS_ADA=("2684" "2685" ... )
GPU_IDS_BLACKWELL=("2330" "2331" ... )#!/usr/bin/env python3
"""
Fetch NVIDIA GPU PCI device IDs from pci-ids.ucw.cz
and generate data/gpu-ids.sh with architecture mapping.
"""
# Core logic:
# 1. Download https://pci-ids.ucw.cz/v2.2/pci.ids (or GitHub mirror)
# 2. Parse vendor 10de section
# 3. For each device entry, extract chip code from device name
# (regex: r'\b(GK|GM|GP|GV|TU|GA|GH|AD|GB)\d{2,3}\b')
# 4. Map chip code prefix → architecture
# 5. Generate data/gpu-ids.sh
CHIP_TO_ARCH = {
"GK": "Kepler",
"GM": "Maxwell",
"GP": "Pascal",
"GV": "Volta",
"TU": "Turing",
"GA": "Ampere",
"GH": "Hopper",
"AD": "Ada Lovelace",
"GB": "Blackwell",
}
# Entries without chip codes (audio controllers, USB, bridges)
# are filtered out — only GPU/compute devices are included.The scripts/build.py pipeline embeds data/gpu-ids.sh into nvidia-install.sh during build, similar to language packs:
# In src/nvidia-install.sh template:
# ================ GPU ID Database ==================
# {{GPU_IDS}}
# ================ GPU ID Database End ==============name: Update GPU ID Database
on:
schedule:
- cron: '0 0 * * 1' # Weekly on Monday
workflow_dispatch: # Manual trigger
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate GPU ID database
run: python3 scripts/update_gpu_ids.py
- name: Check for changes
id: diff
run: |
if git diff --quiet data/gpu-ids.sh; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi
- name: Create PR if changed
if: steps.diff.outputs.changed == 'true'
uses: peter-evans/create-pull-request@v6
with:
title: "chore: update GPU PCI device ID database"
body: |
Auto-generated from [pci-ids.ucw.cz](https://pci-ids.ucw.cz/).
Please review the diff for new GPU architecture entries.
branch: auto/update-gpu-ids
commit-message: "chore: update GPU PCI device ID database"This runs weekly, compares against the existing data/gpu-ids.sh, and opens a PR if new device IDs are found — keeping humans in the loop for review.
- If a device ID is not in the database at all, the script already falls back to
"Unknown"architecture - Unknown architecture defaults to attempting open kernel module first (safe default for Turing+)
- The database should also include a manually curated override section at the bottom of
data/gpu-ids.shfor entries that pci.ids gets wrong or hasn't added yet
├── src/ # Template scripts
├── lang/ # Language packs
├── data/ # Generated data files
│ └── gpu-ids.sh # GPU PCI device ID → architecture mapping
├── scripts/
│ ├── build.py # Template + lang + data → final scripts
│ ├── extract_keys.py # Gettext key extraction
│ └── update_gpu_ids.py # Fetch & generate GPU ID database
├── dist/ # Build output (gitignored)
└── .github/workflows/
├── release.yml # Build on release
├── ci.yml # PR validation
└── update-gpu-ids.yml # Weekly GPU ID update
- Create
scripts/update_gpu_ids.pyand run it to generatedata/gpu-ids.sh - Verify generated data matches/exceeds current hand-curated database
- Add
# {{GPU_IDS}}placeholder tosrc/nvidia-install.sh - Update
scripts/build.pyto embeddata/gpu-ids.sh - Add
update-gpu-ids.ymlworkflow - Remove hand-curated
init_gpu_database()content from template