mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-26 06:52:57 +08:00
* chore(windows): gate Unix-only workspace code for MSVC Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * feat(windows): stub unsupported compute drivers Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * ci(windows): add MSVC mise build lane Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * docs(windows): document MSVC build-only design Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * docs(agent): add Windows MSVC build skill Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * feat(windows): add Windows build support Signed-off-by: Akber Raza <akberr@nvidia.com> * refactor(windows): consolidate Windows-specific dependencies and improve build logic Signed-off-by: Akber Raza <akberr@nvidia.com> * feat(windows): add libclang path resolution and update cargo commands with bundled Z3 features Signed-off-by: Akber Raza <akberr@nvidia.com> * chore(tooling): lock Windows tool artifacts Signed-off-by: Giedrius Burachas <gburachas@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * feat(windows): enhance libclang path resolution to support architecture-specific subdirectories Signed-off-by: Akber Raza <akberr@nvidia.com> * Fix Windows dependency gating after sync merge Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(z3): update Z3 header path requirements in Windows build documentation and scripts Signed-off-by: Akber Raza <akberr@nvidia.com> * docs(windows): relocate Windows MSVC build design to architecture/ Why: windows-msvc-build-design.mdx is a design document ("design decisions for the native Windows MSVC build lane"), but it lived in the published, user-facing docs/reference/ tree. Per AGENTS.md (Documentation) and architecture/README.md ("rfc/ vs architecture/"), design content belongs in architecture/ (or rfc/), not in published reference. It also shared Fern sidebar "position: 6" with the MXC compute-driver design page, colliding in the Reference nav ordering. What: - Move docs/reference/windows-msvc-build-design.mdx -> architecture/windows-msvc-build.md. - Strip the Fern publish frontmatter and add a plain H1, matching the other architecture docs. - Register it in the architecture doc index in architecture/README.md. - Repoint the inbound references (build-openshell-mxc-windows skill + reference, implement-openshell-mxc-driver skill) to the new path. With both design pages moved out of docs/reference/, the duplicate position-6 sidebar collision is resolved. Signed-off-by: Akber Raza <akberr@nvidia.com> * remove openshell-supervisor-network from unsupported driver package test exclusion list Signed-off-by: Akber Raza <akberr@nvidia.com> # Conflicts: # tasks/scripts/windows-msvc.ps1 * fix(interceptors): gate unix-only imports so the crate builds on Windows openshell-gateway-interceptors failed to compile on Windows (E0432: no UnixStream in tokio::net), breaking any Windows build of openshell-server (which depends on it unconditionally). The connect_unix_endpoint fn was already #[cfg(unix)]-gated, but the imports it uses (UnixStream, TokioIo, Uri, service_fn) were left ungated. Gate those four imports with #[cfg(unix)] too. No behavior change on unix; Windows now compiles (no errors, no unused-import warnings). Signed-off-by: Akber Raza <akberr@nvidia.com> * feat(windows): add native ARM64 test support Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(mise): skip Skaffold on Windows Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): harden ARM64 toolchain discovery Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): scope ARM64 toolchain preflight Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): restore compatibility after GitHub sync Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): avoid rate-limited Z3 source lookup Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(mise): skip Helm checks on Windows Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): support repository pre-commit checks Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): stabilize native MSVC validation Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): harden shared Z3 source cache Signed-off-by: Shailendra Singh <shailendras@nvidia.com> * fix(windows): avoid leaking MSVC flags into clang-cl Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): complete ARM64 migration audit Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): restore ARM64 Ninja discovery Signed-off-by: Akber Raza <akberr@nvidia.com> * refactor(windows): separate platform crate roots Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): restore proto include cfg gating Signed-off-by: Akber Raza <akberr@nvidia.com> * refactor: address lint errors * fix(windows): add preflight check for proxy auth file path * docs(windows): update GitHub checkout guidance Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): restore CI after dependency updates Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(mise): repair Windows sccache lock entry Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(windows): reconcile validation after rebase Signed-off-by: Akber Raza <akberr@nvidia.com> * refactor(server): exclude unsupported drivers on Windows Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com> * refactor(server): isolate platform driver config Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com> * fix(windows): repair unsupported driver contract test Signed-off-by: Akber Raza <akberr@nvidia.com> * fix(sandbox): remove stale dependencies Signed-off-by: Akber Raza <akberr@nvidia.com> * ci(windows): pin x64 workflow actions Signed-off-by: Akber Raza <akberr@nvidia.com> * ci(windows): align x64 Rust toolchain Signed-off-by: Akber Raza <akberr@nvidia.com> * ci(windows): align ARM64 workflow setup Signed-off-by: Akber Raza <akberr@nvidia.com> * refactor(windows): exclude unsupported runtime crates Signed-off-by: Akber Raza <akberr@nvidia.com> * refactor(windows): exclude unsupported crates at workspace boundary Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> * refactor(server): gate builtin driver config by platform Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> * fix(sandbox): restore crate documentation Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> * ci(windows): make build workflow manual Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> * ci(windows): temporarily enable pull request builds Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> * ci(windows): cache Rust dependencies Signed-off-by: Akber Raza <akberr@nvidia.com> * refactor(windows): remove unnecessary platform changes Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> * ci(windows): make build workflow manual Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> * fix(ci): synchronize mise lockfile Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> * fix(ci): normalize mise provenance metadata Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> * refactor(python): isolate Windows atomic replace retry Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> * fix(python): type Windows permission test errors Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> --------- Signed-off-by: Shailendra Singh <shailendras@nvidia.com> Signed-off-by: Akber Raza <akberr@nvidia.com> Signed-off-by: Giedrius Burachas <gburachas@nvidia.com> Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com> Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com> Co-authored-by: Shailendra Singh <shailendras@nvidia.com> Co-authored-by: Giedrius Burachas <gburachas@nvidia.com> Co-authored-by: Jamie King <jamiek@nvidia.com> Co-authored-by: Piotr Mlocek <pmlocek@nvidia.com> Co-authored-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>
360 lines
10 KiB
Python
Executable File
360 lines
10 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
"""Add or check SPDX license headers on source files.
|
|
|
|
Usage:
|
|
# Add/update headers on all source files
|
|
python scripts/update_license_headers.py
|
|
|
|
# Check mode (CI / pre-commit) — exit 1 if any file is missing a header
|
|
python scripts/update_license_headers.py --check
|
|
|
|
# Operate on specific files only (useful for pre-commit on staged files)
|
|
python scripts/update_license_headers.py path/to/file.rs path/to/other.py
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Configuration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
COPYRIGHT_TEXT = (
|
|
"Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved."
|
|
)
|
|
LICENSE_ID = "Apache-2.0"
|
|
|
|
# Map file extensions to their line-comment prefix.
|
|
COMMENT_STYLES: dict[str, str] = {
|
|
".rs": "//",
|
|
".proto": "//",
|
|
".py": "#",
|
|
".sh": "#",
|
|
".toml": "#",
|
|
".yaml": "#",
|
|
".yml": "#",
|
|
".rego": "#",
|
|
}
|
|
|
|
# Directories to skip entirely (relative to repo root).
|
|
EXCLUDE_DIRS: set[str] = {
|
|
"target",
|
|
"e2e/rust/target",
|
|
"architecture/plans",
|
|
"scripts/lint-mermaid/node_modules",
|
|
".venv",
|
|
".git",
|
|
".cache",
|
|
"python/openshell/_proto",
|
|
}
|
|
|
|
# Individual filenames to skip.
|
|
EXCLUDE_FILES: set[str] = {
|
|
"Cargo.lock",
|
|
"uv.lock",
|
|
".gitlab-ci.yml",
|
|
}
|
|
|
|
# Glob-style directory prefixes to also skip (CI / editor config dirs).
|
|
EXCLUDE_DIR_PREFIXES: tuple[str, ...] = (
|
|
".github/",
|
|
".agents/",
|
|
".claude/",
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Header generation
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def make_header(comment: str) -> str:
|
|
"""Return the two-line SPDX header for a given comment prefix."""
|
|
return (
|
|
f"{comment} SPDX-FileCopyrightText: {COPYRIGHT_TEXT}\n"
|
|
f"{comment} SPDX-License-Identifier: {LICENSE_ID}\n"
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# File discovery
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def find_repo_root() -> Path:
|
|
"""Walk up from CWD to find the directory containing .git."""
|
|
path = Path.cwd()
|
|
while path != path.parent:
|
|
if (path / ".git").exists():
|
|
return path
|
|
path = path.parent
|
|
return Path.cwd()
|
|
|
|
|
|
def is_excluded(rel: Path) -> bool:
|
|
"""Return True if a path should be skipped."""
|
|
rel_str = rel.as_posix()
|
|
|
|
# Exact filename exclusions.
|
|
if rel.name in EXCLUDE_FILES:
|
|
return True
|
|
|
|
# Directory exclusions.
|
|
for exc_dir in EXCLUDE_DIRS:
|
|
if rel_str == exc_dir or rel_str.startswith(exc_dir + "/"):
|
|
return True
|
|
|
|
# Prefix exclusions (CI config, editor config).
|
|
return any(rel_str.startswith(prefix) for prefix in EXCLUDE_DIR_PREFIXES)
|
|
|
|
|
|
def git_candidate_files(root: Path) -> list[Path] | None:
|
|
"""Return Git-tracked and unignored files, or None if Git is unavailable."""
|
|
try:
|
|
result = subprocess.run(
|
|
[
|
|
"git",
|
|
"-C",
|
|
str(root),
|
|
"ls-files",
|
|
"-z",
|
|
"--cached",
|
|
"--others",
|
|
"--exclude-standard",
|
|
],
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
except (OSError, subprocess.CalledProcessError):
|
|
return None
|
|
|
|
files = []
|
|
for raw_path in result.stdout.split(b"\0"):
|
|
if raw_path:
|
|
files.append(Path(os.fsdecode(raw_path)))
|
|
return files
|
|
|
|
|
|
def is_git_ignored(root: Path, rel: Path) -> bool:
|
|
"""Return True if Git ignore rules exclude a path."""
|
|
try:
|
|
result = subprocess.run(
|
|
["git", "-C", str(root), "check-ignore", "-q", "--", str(rel)],
|
|
check=False,
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
)
|
|
except OSError:
|
|
return False
|
|
return result.returncode == 0
|
|
|
|
|
|
def is_dockerfile(path: Path) -> bool:
|
|
"""Return True for Dockerfile variants (matched by name, not extension)."""
|
|
return path.name == "Dockerfile" or path.name.startswith("Dockerfile.")
|
|
|
|
|
|
def get_comment_style(path: Path) -> str | None:
|
|
"""Return the comment prefix for a file, or None if unsupported."""
|
|
if is_dockerfile(path):
|
|
return "#"
|
|
return COMMENT_STYLES.get(path.suffix)
|
|
|
|
|
|
def discover_files(root: Path) -> list[Path]:
|
|
"""Walk the repo and return all files that should have headers."""
|
|
results = []
|
|
|
|
git_files = git_candidate_files(root)
|
|
if git_files is not None:
|
|
for rel in git_files:
|
|
path = root / rel
|
|
if not path.is_file():
|
|
continue
|
|
if is_excluded(rel):
|
|
continue
|
|
if get_comment_style(rel) is not None:
|
|
results.append(path)
|
|
return sorted(results)
|
|
|
|
for dirpath, dirnames, filenames in os.walk(root):
|
|
rel_dir = Path(dirpath).relative_to(root)
|
|
|
|
# Prune excluded directories (modifying dirnames in-place).
|
|
dirnames[:] = [d for d in dirnames if not is_excluded(rel_dir / d)]
|
|
|
|
for fname in filenames:
|
|
fpath = Path(dirpath) / fname
|
|
rel = fpath.relative_to(root)
|
|
if is_excluded(rel):
|
|
continue
|
|
if get_comment_style(rel) is not None:
|
|
results.append(fpath)
|
|
|
|
return sorted(results)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Header checking and insertion
|
|
# ---------------------------------------------------------------------------
|
|
|
|
SPDX_MARKER = "SPDX-License-Identifier"
|
|
|
|
|
|
def has_header(lines: list[str]) -> bool:
|
|
"""Check if the SPDX header is present in the first 10 lines."""
|
|
return any(SPDX_MARKER in line for line in lines[:10])
|
|
|
|
|
|
def find_insertion_point(lines: list[str], path: Path) -> int:
|
|
"""Determine where to insert the header.
|
|
|
|
Returns the line index where the header should be placed. The header
|
|
will be inserted *before* this index, with a blank line after it.
|
|
|
|
Special cases:
|
|
- Shebang (#!/...) on line 0 → insert at line 1
|
|
- Dockerfile `# syntax=` on line 0 → insert at line 1
|
|
- Otherwise → insert at line 0
|
|
"""
|
|
if not lines:
|
|
return 0
|
|
|
|
first = lines[0]
|
|
|
|
# Shebang line — keep it on line 0, header goes after.
|
|
if first.startswith("#!"):
|
|
return 1
|
|
|
|
# Dockerfile syntax directive.
|
|
if is_dockerfile(path) and first.lower().startswith("# syntax="):
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
def insert_header(content: str, comment: str, path: Path) -> str:
|
|
"""Insert the SPDX header into file content, returning the new content."""
|
|
header = make_header(comment)
|
|
lines = content.splitlines(keepends=True)
|
|
insert_at = find_insertion_point(lines, path)
|
|
|
|
if insert_at == 0:
|
|
# Header at top, blank line before existing content (if any).
|
|
if lines:
|
|
return header + "\n" + content
|
|
return header
|
|
else:
|
|
# Insert after a first-line directive (shebang / # syntax=).
|
|
before = lines[:insert_at]
|
|
after = lines[insert_at:]
|
|
return "".join(before) + "\n" + header + "\n" + "".join(after)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Main logic
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def process_file(path: Path, root: Path, *, check: bool, verbose: bool) -> bool:
|
|
"""Process a single file. Returns True if the file is compliant."""
|
|
rel = path.relative_to(root)
|
|
comment = get_comment_style(rel)
|
|
if comment is None:
|
|
return True
|
|
|
|
content = path.read_text(encoding="utf-8")
|
|
lines = content.splitlines()
|
|
|
|
if has_header(lines):
|
|
if verbose:
|
|
print(f" ok: {rel}")
|
|
return True
|
|
|
|
if check:
|
|
print(f" MISSING: {rel}")
|
|
return False
|
|
|
|
# Insert the header.
|
|
new_content = insert_header(content, comment, rel)
|
|
path.write_text(new_content, encoding="utf-8")
|
|
if verbose:
|
|
print(f" added: {rel}")
|
|
return True
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(
|
|
description="Add or check SPDX license headers on source files.",
|
|
)
|
|
parser.add_argument(
|
|
"--check",
|
|
action="store_true",
|
|
help="Check mode: exit 1 if any file is missing a header.",
|
|
)
|
|
parser.add_argument(
|
|
"--verbose",
|
|
"-v",
|
|
action="store_true",
|
|
help="Print status for every file processed.",
|
|
)
|
|
parser.add_argument(
|
|
"paths",
|
|
nargs="*",
|
|
type=Path,
|
|
help="Specific files to process (default: all files under repo root).",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
root = find_repo_root()
|
|
|
|
if args.paths:
|
|
# Resolve relative paths and filter to supported + non-excluded files.
|
|
files = []
|
|
for p in args.paths:
|
|
p = p.resolve()
|
|
if not p.is_file():
|
|
continue
|
|
try:
|
|
rel = p.relative_to(root)
|
|
except ValueError:
|
|
continue
|
|
if is_excluded(rel) or is_git_ignored(root, rel):
|
|
continue
|
|
if get_comment_style(rel) is not None:
|
|
files.append(p)
|
|
else:
|
|
files = discover_files(root)
|
|
|
|
if args.check:
|
|
print(f"Checking {len(files)} files for SPDX headers...")
|
|
else:
|
|
print(f"Processing {len(files)} files...")
|
|
|
|
missing = []
|
|
for f in files:
|
|
if not process_file(f, root, check=args.check, verbose=args.verbose):
|
|
missing.append(f)
|
|
|
|
if args.check:
|
|
if missing:
|
|
print(f"\n{len(missing)} file(s) missing SPDX headers.")
|
|
return 1
|
|
print("All files have SPDX headers.")
|
|
return 0
|
|
|
|
print("Done.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|