aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorEgor Tensin <egor@tensin.name>2026-10-05 10:34:55 +0500
committerEgor Tensin <egor@tensin.name>2026-10-05 10:53:25 +0500
commitb4f6e1253356370c8d8855ea0b155e844db98b83 (patch)
treef60faafa2ab66e391eec38480e56b2a845cdc539
parentpyproject.toml: make a guess about the required Python version (diff)
downloadcmake-common-b4f6e1253356370c8d8855ea0b155e844db98b83.tar.gz
cmake-common-b4f6e1253356370c8d8855ea0b155e844db98b83.zip
tools/project-clang-format.py -> project/format.py
-rw-r--r--.github/workflows/lint.yml6
-rw-r--r--[-rwxr-xr-x]project/format.py (renamed from tools/project-clang-format.py)66
-rw-r--r--project/utils.py30
-rw-r--r--pyproject.toml2
4 files changed, 36 insertions, 68 deletions
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index afefd20..5566327 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -5,7 +5,7 @@ on:
workflow_dispatch:
jobs:
- # Check that project-clang-format.py works (and the C/C++ files are formatted).
+ # Check that project.format works (and the C/C++ files are formatted).
lint:
runs-on: ubuntu-latest
name: Linting
@@ -13,11 +13,11 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v7
- - name: Run clang-format
- run: ./tools/project-clang-format.py
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: '3.x'
+ - name: Run clang-format
+ run: python -m project.format
- name: Run black
uses: psf/black@stable
diff --git a/tools/project-clang-format.py b/project/format.py
index 4b066c3..5f24062 100755..100644
--- a/tools/project-clang-format.py
+++ b/project/format.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-
# Copyright (c) 2020 Egor Tensin <egor@tensin.name>
# This file is part of the "cmake-common" project.
# For details, see https://github.com/egor-tensin/cmake-common
@@ -13,66 +11,12 @@ formatting the files in-place.
"""
import argparse
-from contextlib import contextmanager
import difflib
import logging
import os
-import subprocess
import sys
-
-@contextmanager
-def setup_logging():
- level_names = {
- logging.DEBUG: "DBG",
- logging.INFO: "INFO",
- logging.WARNING: "WARN",
- logging.ERROR: "ERR",
- logging.CRITICAL: "CRIT",
- }
- for lvl, name in level_names.items():
- logging.addLevelName(lvl, name)
-
- logging.basicConfig(
- level=logging.INFO,
- datefmt="%Y-%m-%d %H:%M:%S%z",
- format="%(asctime)s | %(levelname)4s | %(message)s",
- )
- try:
- yield
- except Exception as e:
- logging.exception(e)
- sys.exit(1)
-
-
-@contextmanager
-def cd(path):
- cwd = os.getcwd()
- os.chdir(path)
- try:
- yield
- finally:
- os.chdir(cwd)
-
-
-def normalize_path(entry):
- return os.path.abspath(entry)
-
-
-def run(cmd_line):
- logging.debug("Running executable: %s", cmd_line)
- try:
- return subprocess.run(
- cmd_line,
- check=True,
- universal_newlines=True,
- stderr=subprocess.STDOUT,
- stdout=subprocess.PIPE,
- )
- except subprocess.CalledProcessError as e:
- logging.error("Process finished with exit code %d: %s", e.returncode, cmd_line)
- logging.error("Its output was:\n%s", e.output)
- raise
+from project.utils import cd, normalize_path, run_capture, setup_logging
def read_file(path):
@@ -94,7 +38,7 @@ class ClangFormat:
return cmd_line
def format_in_place(self, paths):
- run(self._get_command_line(paths, in_place=True))
+ run_capture(self._get_command_line(paths, in_place=True))
@staticmethod
def _show_diff(path, formatted):
@@ -125,14 +69,14 @@ class ClangFormat:
def show_diff(self, paths):
clean = True
for path in paths:
- formatted = run(self._get_command_line([path])).stdout
+ formatted = run_capture(self._get_command_line([path]))
clean = self._show_diff(path, formatted) and clean
return clean
def git_root_dir():
cmd_line = ["git", "rev-parse", "--show-toplevel"]
- root_dir = run(cmd_line).stdout
+ root_dir = run_capture(cmd_line)
if root_dir[-1] != "\n":
raise RuntimeError("git rev-parse --show-toplevel should append a newline?")
return root_dir[:-1]
@@ -140,7 +84,7 @@ def git_root_dir():
def list_git_files():
cmd_line = ["git", "ls-tree", "-r", "-z", "--name-only", "HEAD"]
- repo_files = run(cmd_line).stdout
+ repo_files = run_capture(cmd_line)
repo_files = repo_files.split("\0")
return repo_files
diff --git a/project/utils.py b/project/utils.py
index 8ef6639..3fb73c4 100644
--- a/project/utils.py
+++ b/project/utils.py
@@ -7,6 +7,7 @@ from contextlib import contextmanager
import functools
import logging
import os.path
+import shlex
import shutil
import subprocess
import sys
@@ -81,9 +82,32 @@ def cd(path):
os.chdir(cwd)
-def run(cmd_line, **kwargs):
- logging.info("Running: %s", subprocess.list2cmdline(cmd_line))
- return subprocess.run(cmd_line, check=True, **kwargs)
+def run(cmd, **kwargs):
+ logging.info("Running: %s", shlex.join(cmd))
+ return subprocess.run(cmd, check=True, **kwargs)
+
+
+def _run_log_output(level, output):
+ if not output:
+ logging.log(level, "... No output")
+ logging.log(level, "Output (%d) characters):", len(output))
+ for line in output.splitlines():
+ logging.log(level, " %s", line)
+
+
+def run_capture(cmd, **kwargs):
+ stdout = subprocess.PIPE
+ stderr = subprocess.STDOUT
+
+ try:
+ result = run(cmd, **kwargs, stdout=stdout, stderr=stderr, encoding="utf-8")
+ except subprocess.CalledProcessError as e:
+ logging.error("... Exited with code %d", e.returncode)
+ _run_log_output(logging.ERROR, e.output)
+ raise
+
+ _run_log_output(logging.DEBUG, result.stdout)
+ return result.stdout
@contextmanager
diff --git a/pyproject.toml b/pyproject.toml
index beb76b9..7fd21f8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -30,11 +30,11 @@ classifiers = [
boost-build = "project.boost.build:_main"
boost-download = "project.boost.download:_main"
project-build = "project.build:main"
+project-format = "project.format:main"
[tool.setuptools]
script-files = [
"tools/ctest-driver.py",
- "tools/project-clang-format.py",
]
[tool.setuptools_scm]