From 3210df3f445dc130eba4b6d5d2f3161a308f767c Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Mon, 30 Dec 2024 13:07:18 +0100 Subject: [PATCH] Initial commit --- .github/workflows/ci.yml | 45 ++++++++++++++++++++++ .gitignore | 28 ++++++++++++++ .pre-commit-config.yaml | 11 ++++++ .pre-commit-hooks.yaml | 7 ++++ LICENSE | 21 ++++++++++ README.md | 58 ++++++++++++++++++++++++++++ pyproject.toml | 11 ++++++ setup.cfg | 29 ++++++++++++++ setup.py | 10 +++++ vcpkg_precommit/__init__.py | 3 ++ vcpkg_precommit/hook.py | 76 +++++++++++++++++++++++++++++++++++++ 11 files changed, 299 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .pre-commit-hooks.yaml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 pyproject.toml create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 vcpkg_precommit/__init__.py create mode 100644 vcpkg_precommit/hook.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b283193 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,45 @@ +# File: .github/workflows/ci.yml +name: CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox tox-gh-actions + + - name: Test with tox + run: tox + + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Run pre-commit hooks + uses: pre-commit/action@v3.0.1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6c25eaf --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +.pytest_cache/ +.env +.venv +env/ +venv/ +ENV/ +.idea/ +.vscode/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..d070d16 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +repos: + - repo: https://github.com/psf/black + rev: 24.10.0 + hooks: + - id: black + + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + args: ["--profile", "black", "--filter-files"] diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 0000000..bebb6bf --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,7 @@ +- id: vcpkg-format-manifest + name: Format vcpkg.json files + description: Format vcpkg.json manifests using the vcpkg binary + entry: vcpkg-format-manifest + language: python + files: vcpkg\.json$ + minimum_pre_commit_version: "2.9.0" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0ec8749 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Claude AI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e6c87f --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# vcpkg precommit hooks + +This repository provides [vcpkg](https://vcpkg.io/) hooks for [pre-commit](https://pre-commit.com/). + +The following section assumes that you [installed pre-commit](https://pre-commit.com/index.html#install) and run `pre-commit install` in your repository. + +## Features + +- Formats manifests using the vcpkg `format-manifest` command +- Automatically downloads the appropriate vcpkg binary for your platform +- Cross-platform support (Windows, Linux, macOS) +- Works with x64 and ARM64 architectures +- Caches the vcpkg binary for better performance + +## Installation + +Add this to your `.pre-commit-config.yaml`: + +```yaml +repos: +- repo: https://github.com/open-vcpkg/vcpkg-precommit + rev: v1.0.0 # Use the ref you want to point at + hooks: + - id: vcpkg-format-manifest +``` + +## Usage + +Once installed, the hook will automatically run on any commits that modify `vcpkg.json` files. + +You can also run the hook manually: + +```bash +pre-commit run vcpkg-format-manifest --all-files +``` + +## Development + +To contribute to this hook: + +1. Clone the repository +2. Create a virtual environment: + ```bash + python -m venv venv + source venv/bin/activate # or `venv\Scripts\activate` on Windows + ``` +3. Install development dependencies: + ```bash + pip install -e ".[dev]" + ``` +4. Install pre-commit: + ```bash + pre-commit install + ``` + +## License + +MIT diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f266b82 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,11 @@ +[build-system] +requires = ["setuptools>=45", "wheel", "setuptools_scm>=6.2"] +build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 100 +target-version = ["py37"] + +[tool.isort] +profile = "black" +multi_line_output = 3 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b280d13 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,29 @@ +[metadata] +name = vcpkg-precommit-hook +version = attr: vcpkg_precommit.__version__ +description = A pre-commit hook for validating vcpkg.json files +long_description = file: README.md +long_description_content_type = text/markdown +author = Your Name +author_email = your.email@example.com +url = https://github.com/yourusername/vcpkg-precommit-hook +license = MIT +classifiers = + Development Status :: 4 - Beta + Intended Audience :: Developers + License :: OSI Approved :: MIT License + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + +[options] +packages = find: +python_requires = >=3.7 +install_requires = + requests>=2.25.0 + +[options.entry_points] +console_scripts = + vcpkg-format-manifest = vcpkg_precommit.hook:main diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..0e233ed --- /dev/null +++ b/setup.py @@ -0,0 +1,10 @@ +from setuptools import setup + +setup( + name="vcpkg_precommit", + version="0.1.0", + packages=["vcpkg_precommit"], + entry_points={ + "console_scripts": ["vcpkg-format-manifest=vcpkg_precommit:main"], + }, +) diff --git a/vcpkg_precommit/__init__.py b/vcpkg_precommit/__init__.py new file mode 100644 index 0000000..4ab2b7f --- /dev/null +++ b/vcpkg_precommit/__init__.py @@ -0,0 +1,3 @@ +from .hook import main + +__version__ = "0.1.0" diff --git a/vcpkg_precommit/hook.py b/vcpkg_precommit/hook.py new file mode 100644 index 0000000..5620486 --- /dev/null +++ b/vcpkg_precommit/hook.py @@ -0,0 +1,76 @@ +import argparse +import platform +import subprocess +from pathlib import Path +from typing import Optional, Sequence +from urllib.request import urlretrieve + + +def get_vcpkg_binary() -> Path: + """Download and return path to vcpkg binary for current platform.""" + system = platform.system().lower() + machine = platform.machine().lower() + + binary_map = { + ("windows", "amd64"): ("vcpkg.exe", "vcpkg-windows-x64.exe"), + ("linux", "x86_64"): ("vcpkg", "vcpkg-linux"), + ("darwin", "arm64"): ("vcpkg", "vcpkg-macos-arm64"), + ("darwin", "x86_64"): ("vcpkg", "vcpkg-macos"), + } + + if (system, machine) not in binary_map: + raise Exception(f"Unsupported platform: {system} {machine}") + + binary_name, url_suffix = binary_map[(system, machine)] + url = f"https://github.com/microsoft/vcpkg-tool/releases/latest/download/{url_suffix}" + + vcpkg_dir = Path.home() / ".vcpkg" + vcpkg_dir.mkdir(exist_ok=True) + + vcpkg_path = vcpkg_dir / binary_name + + if not vcpkg_path.exists(): + print(f"Downloading vcpkg from {url}...") + urlretrieve(url, vcpkg_path) + vcpkg_path.chmod(0o755) + + return vcpkg_path + + +def format_manifest_vcpkg_json(filename: str, vcpkg_binary: Path) -> bool: + """Format a single vcpkg.json file.""" + result = subprocess.run( + [str(vcpkg_binary), "format-manifest", filename], capture_output=True, text=True + ) + + if result.returncode != 0: + print(f"Error formatting {filename}:") + print(result.stderr) + return False + + return True + + +def main(argv: Optional[Sequence[str]] = None) -> int: + parser = argparse.ArgumentParser() + parser.add_argument("filenames", nargs="*", help="Filenames to check") + args = parser.parse_args(argv) + + try: + vcpkg_binary = get_vcpkg_binary() + + retval = 0 + for filename in args.filenames: + print(f"Formatting {filename}...") + if not format_manifest_vcpkg_json(filename, vcpkg_binary): + retval = 1 + + return retval + + except Exception as e: + print(f"Error: {str(e)}") + return 1 + + +if __name__ == "__main__": + exit(main())