From a8d56abccf0b22a5ffbfdc8332ff19107660998d Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Mon, 15 Jan 2024 14:38:32 +0800 Subject: [PATCH 1/4] feat: support new install param `--tool` --- README.rst | 30 +++++++++++++++++++++++++++++- clang_tools/install.py | 5 +++-- clang_tools/main.py | 24 ++++++++++++++++-------- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/README.rst b/README.rst index 5ff9b0e..383dbbc 100644 --- a/README.rst +++ b/README.rst @@ -21,7 +21,7 @@ clang-tools Introduction :alt: PyPI - Downloads -Install clang-tools binaries (clang-format, clang-tidy) with pip. +Install clang-tools binaries (clang-format, clang-tidy, clang-query and clang-apply-replacements) with pip. .. important:: This package only manages binary executables (& corresponding symbolic links) that @@ -32,6 +32,7 @@ Features -------- - Binaries are statically linked for improved portability. +- Binaries can be specified installed for increased flexibility. - Binaries are checked with SHA512 checksum. This ensures: 1. Downloads are not corrupted. @@ -102,6 +103,12 @@ Or install to a specified directory clang-tools --install 13 --directory . +Or install a specified tool, such as clang-format and clang-query version 14. + +.. code-block:: shell + + clang-tools --install 14 --tool clang-format clang-query + If the installed directory is in your path, you can run the installed tools. .. code-block:: shell @@ -141,6 +148,27 @@ clang-tidy Windows,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ macOS,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ +clang-query +********** +.. csv-table:: + :header: "Version", "17", "16", "15", "14", "13", "12", "11", "10", "9", "8", "7" + :stub-columns: 1 + + Linux,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ + Windows,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ + macOS,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ + + +clang-apply-replacements +************************ +.. csv-table:: + :header: "Version", "17", "16", "15", "14", "13", "12", "11", "10", "9", "8", "7" + :stub-columns: 1 + + Linux,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ + Windows,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ + macOS,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ + .. warning:: All clang-tidy v14+ builds for MacOS are still ~1.7 GB in size. diff --git a/clang_tools/install.py b/clang_tools/install.py index 27c05b1..b270885 100644 --- a/clang_tools/install.py +++ b/clang_tools/install.py @@ -249,11 +249,12 @@ def uninstall_clang_tools(version: str, directory: str): def install_clang_tools( - version: str, directory: str, overwrite: bool, no_progress_bar: bool + version: str, tools: str, directory: str, overwrite: bool, no_progress_bar: bool ) -> None: """Wraps functions used to individually install tools. :param version: The version of the tools to install. + :param tools: The specify tool(s) to install. :param directory: The installation directory. :param overwrite: A flag to indicate if the creation of a symlink has permission to overwrite an existing symlink. @@ -265,7 +266,7 @@ def install_clang_tools( f"{YELLOW}{install_dir}", f"directory is not in your environment variable PATH.{RESET_COLOR}", ) - for tool_name in ("clang-format", "clang-tidy"): + for tool_name in tools: native_bin = is_installed(tool_name, version) if native_bin is None: # (not already installed) # `install_tool()` guarantees that the binary exists now diff --git a/clang_tools/main.py b/clang_tools/main.py index f82caab..2617956 100644 --- a/clang_tools/main.py +++ b/clang_tools/main.py @@ -20,6 +20,14 @@ def get_parser() -> argparse.ArgumentParser: metavar="VERSION", help="Install clang-tools about a specific version.", ) + parser.add_argument( + "-t", + "--tool", + nargs='+', + default=['clang-format', 'clang-tidy'], + metavar="TOOL", + help="Specify which tool(s) to install.", + ) parser.add_argument( "-d", "--directory", @@ -54,19 +62,19 @@ def main(): """The main entrypoint to the CLI program.""" parser = get_parser() args = parser.parse_args() - if not args.install and not args.uninstall: + + if args.uninstall: + uninstall_clang_tools(args.uninstall, args.directory) + if args.install: + install_clang_tools( + args.install, args.tool, args.directory, args.overwrite, args.no_progress_bar + ) + else: print( f"{YELLOW}Nothing to do because `--install` and `--uninstall`", f"was not specified.{RESET_COLOR}" ) parser.print_help() - else: - if args.uninstall: - uninstall_clang_tools(args.uninstall, args.directory) - if args.install: - install_clang_tools( - args.install, args.directory, args.overwrite, args.no_progress_bar - ) if __name__ == "__main__": From 861cfd55bd0fc440c8139a00c48016f132de2c45 Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Mon, 15 Jan 2024 14:42:56 +0800 Subject: [PATCH 2/4] fix: try to fix test case failure --- tests/test_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_install.py b/tests/test_install.py index 54b0a7c..5c63c3a 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -72,7 +72,7 @@ def test_path_warning(capsys: pytest.CaptureFixture): 2. indicates a failure to download a tool """ try: - install_clang_tools("x", ".", False, False) + install_clang_tools("x", "x", ".", False, False) except OSError as exc: result = capsys.readouterr() assert "directory is not in your environment variable PATH" in result.out From 6617507cd39538361f4cd20734b69ee41387a5ce Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Mon, 15 Jan 2024 17:16:40 +0800 Subject: [PATCH 3/4] fix: try to fix test case failure --- tests/test_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_main.py b/tests/test_main.py index 513bbbd..6ca365a 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -22,7 +22,7 @@ def parser() -> ArgumentParser: return get_parser() -@pytest.mark.parametrize("arg_name", ["install", "directory", "uninstall"]) +@pytest.mark.parametrize("arg_name", ["install", "tool", "directory", "uninstall"]) @pytest.mark.parametrize("arg_value", [str(v) for v in range(7, 17)] + ["12.0.1"]) def test_arg_parser(arg_name: str, arg_value: str, parser: ArgumentParser): """Test CLI arg parsing using a set of fake args.""" From 7427f37cfb93381abf44bf9be216c4e40a66a506 Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Mon, 15 Jan 2024 10:05:38 +0000 Subject: [PATCH 4/4] fix: try to fix test case failure --- .pre-commit-config.yaml | 6 +++--- README.rst | 35 ++--------------------------------- clang_tools/util.py | 2 +- tests/test_install.py | 2 +- tests/test_main.py | 15 +++++++++++---- 5 files changed, 18 insertions(+), 42 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7652217..a9d114f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.5.0 hooks: - id: trailing-whitespace exclude: \.output @@ -12,11 +12,11 @@ repos: - id: debug-statements - id: requirements-txt-fixer - repo: https://github.com/asottile/pyupgrade - rev: v2.37.3 + rev: v3.15.0 hooks: - id: pyupgrade - repo: https://github.com/pycqa/flake8 - rev: '5.0.4' + rev: '7.0.0' hooks: - id: flake8 args: [--max-line-length=120] diff --git a/README.rst b/README.rst index 383dbbc..ce53b8b 100644 --- a/README.rst +++ b/README.rst @@ -128,39 +128,8 @@ If the installed directory is in your path, you can run the installed tools. Supported versions ------------------ -clang-format -************ -.. csv-table:: - :header: "Version", "17", "16", "15", "14", "13", "12", "11", "10", "9", "8", "7" - :stub-columns: 1 - - Linux,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ - Windows,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ - macOS,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ - -clang-tidy -********** -.. csv-table:: - :header: "Version", "17", "16", "15", "14", "13", "12", "11", "10", "9", "8", "7" - :stub-columns: 1 - - Linux,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ - Windows,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ - macOS,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ - -clang-query -********** -.. csv-table:: - :header: "Version", "17", "16", "15", "14", "13", "12", "11", "10", "9", "8", "7" - :stub-columns: 1 - - Linux,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ - Windows,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ - macOS,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️,✔️ - - -clang-apply-replacements -************************ +clang-format, clang-tidy, clang-query, clang-apply-replacements +*************************************************************** .. csv-table:: :header: "Version", "17", "16", "15", "14", "13", "12", "11", "10", "9", "8", "7" :stub-columns: 1 diff --git a/clang_tools/util.py b/clang_tools/util.py index 0783061..87d296c 100644 --- a/clang_tools/util.py +++ b/clang_tools/util.py @@ -48,7 +48,7 @@ def download_file(url: str, file_name: str, no_progress_bar: bool) -> Optional[s return None assert response.length is not None length = response.length - buffer = bytes() + buffer = b'' progress_bar = "=" if check_install_os() == "windows" else "█" while len(buffer) < length: block_size = int(length / 20) diff --git a/tests/test_install.py b/tests/test_install.py index 5c63c3a..374d9e8 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -14,7 +14,7 @@ @pytest.mark.parametrize("version", [str(v) for v in range(7, 17)] + ["12.0.1"]) -@pytest.mark.parametrize("tool_name", ["clang-format", "clang-tidy"]) +@pytest.mark.parametrize("tool_name", ["clang-format", "clang-tidy", "clang-query", "clang-apply-replacements"]) def test_clang_tools_binary_url(tool_name: str, version: str): """Test `clang_tools_binary_url()`""" url = clang_tools_binary_url(tool_name, version) diff --git a/tests/test_main.py b/tests/test_main.py index 6ca365a..8419c49 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -22,7 +22,7 @@ def parser() -> ArgumentParser: return get_parser() -@pytest.mark.parametrize("arg_name", ["install", "tool", "directory", "uninstall"]) +@pytest.mark.parametrize("arg_name", ["install", "directory", "uninstall"]) @pytest.mark.parametrize("arg_value", [str(v) for v in range(7, 17)] + ["12.0.1"]) def test_arg_parser(arg_name: str, arg_value: str, parser: ArgumentParser): """Test CLI arg parsing using a set of fake args.""" @@ -37,8 +37,15 @@ def test_cli_switch(switch_name: str, parser: ArgumentParser): assert getattr(args, switch_name.replace("-", "_")) -def test_default_args(parser: ArgumentParser): +@pytest.mark.parametrize("name, default_value", [ + ("install", None), + ("uninstall", None), + ("overwrite", False), + ("no_progress_bar", False), + ("directory", ""), + ("tool", ['clang-format', 'clang-tidy']) +]) +def test_default_args(parser: ArgumentParser, name, default_value): """Test the default values of CLI args""" args = parser.parse_args([]) - for name, value in args.__dict__.items(): - assert getattr(Args, name) == value + assert getattr(args, name) == default_value