#!/usr/bin/env python3 # Copyright Advanced Micro Devices, Inc. # SPDX-License-Identifier: MIT """Generate simple HTML index files for pip --find-links from local files. This module provides utilities to generate index.html files that pip can use with the --find-links option. By default, the CLI generates a flat multi-arch index for kpack-split package layouts where host, generic, and device packages all live in one directory. It can also generate per-family indexes for the kpack-disabled multi-arch layout where each GPU family has a subdirectory that also needs links to generic packages from the parent directory. For generating an index from packages already in S3, see generate_s3_index.py. Usage as a library: from generate_local_index import generate_simple_index generate_simple_index( output_path=Path("dist/gfx94X-dcgpu/index.html"), local_files=[Path("dist/gfx94X-dcgpu/rocm_sdk_libraries_gfx94x_dcgpu-7.2.0.whl")], parent_files=[Path("dist/rocm_sdk_core-7.2.0.whl")] ) Usage as a script: python generate_local_index.py dist/ python generate_local_index.py dist/ --output dist/index.html python generate_local_index.py dist/ --per-family-indexes """ import argparse from pathlib import Path from urllib.parse import quote def generate_simple_index( output_path: Path, local_files: list[Path], parent_files: list[Path] | None = None, title: str = "Package Index", ) -> None: """Generate a simple HTML index for pip --find-links. Creates an HTML file with links to package files. Local files are referenced with ./ prefix, parent files with ../ prefix. This allows a single index to reference packages in both the current directory and parent directory. Args: output_path: Where to write index.html local_files: Files in same directory (will use ./ prefix) parent_files: Files in parent directory (will use ../ prefix) title: HTML page title Example: For a multi-arch build where generic packages are at the top level and family-specific packages are in subdirectories: generate_simple_index( output_path=Path("dist/gfx94X-dcgpu/index.html"), local_files=[ Path("dist/gfx94X-dcgpu/rocm_sdk_libraries_gfx94x_dcgpu-7.2.0.whl"), Path("dist/gfx94X-dcgpu/rocm-gfx94x_dcgpu-7.2.0.tar.gz"), ], parent_files=[ Path("dist/rocm_sdk_core-7.2.0.whl"), ], title="ROCm Python Packages - gfx94X-dcgpu" ) This generates an index with: - ./rocm_sdk_libraries_gfx94x_dcgpu-7.2.0.whl - ./rocm-gfx94x_dcgpu-7.2.0.tar.gz - ../rocm_sdk_core-7.2.0.whl """ parent_files = parent_files or [] html_parts = [ "", "", "", ' ', f" {title}", "", "", f"

{title}

", ] # Add local files with ./ prefix for file_path in sorted(local_files): filename = file_path.name html_parts.append(f' {filename}
') # Add parent files with ../ prefix for file_path in sorted(parent_files): filename = file_path.name html_parts.append(f' {filename}
') html_parts.extend(["", "", ""]) # Trailing newline output_path.write_text("\n".join(html_parts), encoding="utf-8") print( f"Generated {output_path}: {len(local_files)} local, {len(parent_files)} parent files" ) def generate_multiarch_indexes( dist_dir: Path, patterns: list[str] | None = None ) -> None: """Generate per-family indexes for kpack-disabled multi-arch builds. For kpack-disabled multi-arch builds, the dist directory structure is: dist/ rocm_sdk_core-*.whl (generic, top-level) gfx94X-dcgpu/ rocm_sdk_libraries_gfx94x_dcgpu-*.whl rocm-gfx94x_dcgpu-*.tar.gz gfx120X-all/ rocm_sdk_libraries_gfx120x_all-*.whl ... This generates an index.html in each family subdir that includes: - Local family-specific packages (./relative) - Parent generic packages (../relative) Args: dist_dir: Root dist directory containing generic packages and family subdirs patterns: File patterns to include (default: ["*.whl", "*.tar.gz"]) Example: generate_multiarch_indexes(Path("packages/dist")) """ if patterns is None: patterns = ["*.whl", "*.tar.gz"] # Find generic packages at top level generic_packages = [] for pattern in patterns: generic_packages.extend([f for f in dist_dir.glob(pattern) if f.is_file()]) print(f"Found {len(generic_packages)} generic packages at top level: {dist_dir}") # Process each family subdirectory family_dirs = [d for d in dist_dir.iterdir() if d.is_dir()] if not family_dirs: raise FileNotFoundError( f"No family subdirectories found in {dist_dir}. " "generate_multiarch_indexes requires a multi-arch dist layout." ) for family_dir in sorted(family_dirs): family = family_dir.name # Find family-specific files family_files = [] for pattern in patterns: family_files.extend(family_dir.glob(pattern)) print( f"Generating index for {family}: {len(family_files)} local + {len(generic_packages)} parent files" ) generate_simple_index( output_path=family_dir / "index.html", local_files=family_files, parent_files=generic_packages, title=f"ROCm Python Packages - {family}", ) def _find_matching_files(directory: Path, patterns: list[str]) -> list[Path]: files = [] for pattern in patterns: files.extend(f for f in directory.glob(pattern) if f.is_file()) return files def main(argv: list[str] | None = None) -> None: parser = argparse.ArgumentParser( description="Generate HTML index files for pip --find-links" ) parser.add_argument( "directory", type=Path, help="Directory containing packages to index", ) parser.add_argument( "--output", type=Path, help="Output path for index.html (default: /index.html)", ) parser.add_argument( "--parent-dir", type=Path, help="Parent directory containing additional packages (will use ../ links)", ) parser.add_argument( "--per-family-indexes", action="store_true", help=( "Generate indexes for a kpack-disabled per-family layout. " "Creates index.html in each immediate subdirectory and links " "top-level packages as parent files." ), ) parser.add_argument( "--title", type=str, default="Package Index", help="HTML page title (default: 'Package Index')", ) parser.add_argument( "--patterns", nargs="+", default=["*.whl", "*.tar.gz"], help="File patterns to include (default: *.whl *.tar.gz)", ) args = parser.parse_args(argv) if args.per_family_indexes: if args.output: parser.error("--output is only supported for flat index generation") if args.parent_dir: parser.error("--parent-dir is only supported for flat index generation") # Kpack-disabled multi-arch mode: generate indexes for each family # subdirectory. generate_multiarch_indexes(args.directory, patterns=args.patterns) else: # Flat kpack-split multi-arch mode. output_path = args.output or (args.directory / "index.html") local_files = _find_matching_files(args.directory, args.patterns) parent_files = ( _find_matching_files(args.parent_dir, args.patterns) if args.parent_dir else [] ) generate_simple_index( output_path=output_path, local_files=local_files, parent_files=parent_files, title=args.title, ) if __name__ == "__main__": main()