diff --git a/.github/workflows/.beman_submodule b/.github/workflows/.beman_submodule deleted file mode 100644 index bb152318..00000000 --- a/.github/workflows/.beman_submodule +++ /dev/null @@ -1,4 +0,0 @@ -[beman_submodule] -remote=https://github.com/bemanproject/infra-workflows.git -commit_hash=f1afd008de5fcee15a2a20a8b513e5dcde41e67e -allow_untracked_files=True diff --git a/.github/workflows/.github/CODEOWNERS b/.github/workflows/.github/CODEOWNERS deleted file mode 100644 index 7a5f53c5..00000000 --- a/.github/workflows/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @ednolan diff --git a/.github/workflows/LICENSE b/.github/workflows/LICENSE deleted file mode 100644 index 111a208f..00000000 --- a/.github/workflows/LICENSE +++ /dev/null @@ -1,230 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - ----- LLVM Exceptions to the Apache 2.0 License ---- - -As an exception, if, as a result of your compiling your source code, portions -of this Software are embedded into an Object form of such source code, you -may redistribute such embedded portions in such Object form without complying -with the conditions of Sections 4(a), 4(b) and 4(d) of the License. - -In addition, if you combine or link compiled forms of this Software with -software that is licensed under the GPLv2 ("Combined Software") and if a -court of competent jurisdiction determines that the patent provision (Section -3), the indemnity provision (Section 9) or other Section of the License -conflicts with the conditions of the GPLv2, you may retroactively and -prospectively choose to deem waived or otherwise exclude such Section(s) of -the License, but only in their entirety and only with respect to the Combined -Software. - -============================================================================== -Software from third parties included in the Beman Project: -============================================================================== -The Beman Project contains third party software which is under different license -terms. All such code will be identified clearly using at least one of two -mechanisms: -1) It will be in a separate directory tree with its own `LICENSE.txt` or - `LICENSE` file at the top containing the specific license and restrictions - which apply to that software, or -2) It will contain specific license and restriction terms at the top of every - file. diff --git a/.github/workflows/README.md b/.github/workflows/README.md deleted file mode 100644 index f71fd913..00000000 --- a/.github/workflows/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# Beman Project Reusable Github Actions Repository - - - -This repository contains [reusable GitHub Actions -workflows](https://docs.github.com/en/actions/how-tos/sharing-automations/reusing-workflows) -workflow files, intended to help unify the GitHub Actions machinery used across Beman -repositories for CI. It contains the following reusable workflows: - -## `reusable-beman-build-and-test.yml` - -This is the main workflow file used for CI. It takes in a JSON build configuration like -the following example: - -```json -{ - "gcc": [ - { "versions": ["15"], - "tests": [ - { "cxxversions": ["c++26"], - "tests": [ - { "stdlibs": ["libstdc++"], - "tests": [ - "Debug.Default", "Release.Default", "Debug.TSan", "Debug.MaxSan", - "Debug.Werror", "Debug.Dynamic" - ] - } - ] - }, - { "cxxversions": ["c++23", "c++20", "c++17"], - "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}] - } - ] - }, - "clang-p2996": [ - { "versions": ["trunk"], - "tests": [ - { "cxxversions": ["c++26"], - "tests": [{"stdlibs": ["libc++"], "tests": ["Release.-DCMAKE_CXX_FLAGS='-freflection-latest'"]}] - } - ] - } - ] -} -``` - -It then runs jobs corresponding to the specified set of configurations. - -## `reusable-beman-create-issue-when-fault.yml` - -This workflow is intended to help with projects that invoke CI on a scheduled basis when -those jobs fail. It creates a GitHub issue describing the CI failure. - -## `reusable-beman-preset-test.yml` - -This workflow is intended to ensure that the CMake presets provided by beman/infra are -valid and working for the given repository. It takes in a JSON build configuration like -the following: - -```json -[ - {"preset": "gcc-debug", "image": "ghcr.io/bemanproject/infra-containers-gcc:latest"}, - {"preset": "gcc-release", "image": "ghcr.io/bemanproject/infra-containers-gcc:latest"}, - {"preset": "llvm-debug", "image": "ghcr.io/bemanproject/infra-containers-clang:latest"}, - {"preset": "llvm-release", "image": "ghcr.io/bemanproject/infra-containers-clang:latest"}, - {"preset": "appleclang-debug", "runner": "macos-latest"}, - {"preset": "appleclang-release", "runner": "macos-latest"}, - {"preset": "msvc-debug", "runner": "windows-latest"}, - {"preset": "msvc-release", "runner": "windows-latest"} -] -``` - -It then runs jobs corresponding to the specified set of presets. - -## `reusable-beman-pre-commit.yml` - -This provides a workflow for running the -[pre-commit](https://github.com/pre-commit/pre-commit) checks Beman libraries use, on pull -requests and on push. - -## `reusable-beman-submodule-check.yml` - -This provides a workflow for checking consistency of -[`beman-submodule`](https://github.com/bemanproject/infra/blob/main/tools/beman-submodule/README.md) -directories used by Beman repositories to deduplicate infrastructure. diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 7c0b9871..6392abc1 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -13,10 +13,10 @@ on: jobs: beman-submodule-check: - uses: ./.github/workflows/reusable-beman-submodule-check.yml + uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-submodule-check.yml@1.1.0 preset-test: - uses: ./.github/workflows/reusable-beman-preset-test.yml + uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-preset-test.yml@1.1.0 with: matrix_config: > [ @@ -29,7 +29,7 @@ jobs: ] build-and-test: - uses: ./.github/workflows/reusable-beman-build-and-test.yml + uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-build-and-test.yml@1.1.0 with: matrix_config: > { @@ -114,4 +114,4 @@ jobs: create-issue-when-fault: needs: [preset-test, build-and-test] if: failure() && github.event_name == 'schedule' - uses: ./.github/workflows/reusable-beman-create-issue-when-fault.yml + uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-create-issue-when-fault.yml@1.1.0 diff --git a/.github/workflows/reusable-beman-build-and-test.yml b/.github/workflows/reusable-beman-build-and-test.yml deleted file mode 100644 index b1cd4f10..00000000 --- a/.github/workflows/reusable-beman-build-and-test.yml +++ /dev/null @@ -1,175 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -name: 'Beman build-and-test matrix' -on: - workflow_call: - inputs: - matrix_config: - description: 'JSON specification of tests to run' - type: string - required: true -jobs: - configure_test_matrix: - name: Configure test matrix - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} - steps: - - uses: actions/checkout@v4 - - id: set-matrix - shell: python - run: | - import json - import os - import sys - - input_data = json.loads('''${{inputs.matrix_config}}''') - output_list = [] - - image_prefix = "ghcr.io/bemanproject/infra-containers-" - for compiler, compiler_tests in input_data.items(): - for compiler_test in compiler_tests: - for version in compiler_test["versions"]: - image = None - if compiler == "gcc" or compiler.startswith("clang"): - image = image_prefix + compiler + ":" + version - for versions_test in compiler_test["tests"]: - for cxxversion in versions_test["cxxversions"]: - for cxxversion_test in versions_test["tests"]: - for stdlib in cxxversion_test["stdlibs"]: - for stdlib_test in cxxversion_test["tests"]: - test = { - "compiler": compiler, - "version": version, - "cxxversion": cxxversion, - "stdlib": stdlib, - "test": stdlib_test - } - if image is not None: - test["image"] = image - output_list.append(test) - json_string = json.dumps(output_list) - with open(os.environ['GITHUB_OUTPUT'], 'a') as output_file: - print(f"matrix={json_string}", file=output_file) - test_matrix: - needs: configure_test_matrix - strategy: - fail-fast: false - matrix: - config: ${{ fromJson(needs.configure_test_matrix.outputs.matrix) }} - name: "${{ matrix.config.compiler }} ${{ matrix.config.version }} ${{ matrix.config.cxxversion }} ${{ matrix.config.stdlib }} ${{ matrix.config.test }}" - runs-on: >- - ${{ (matrix.config.compiler == 'gcc' || startsWith(matrix.config.compiler, 'clang')) && 'ubuntu-latest' - || (matrix.config.compiler == 'appleclang' && 'macos-latest') - || (matrix.config.compiler == 'msvc' && 'windows-latest') }} - container: ${{ matrix.config.image }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - submodules: 'recursive' - - name: Setup MSVC - if: matrix.config.compiler == 'msvc' - uses: TheMrMilchmann/setup-msvc-dev@v3 - with: - arch: x64 - - name: Setup Macos - if: matrix.config.compiler == 'appleclang' - shell: bash - run: sudo chmod -R 777 /opt/ - - name: Print installed software - shell: bash - run: | - echo "Build system:" - cmake --version - ninja --version - - name: Process configuration - id: vars - shell: bash - run: | - cxxversion=${{ matrix.config.cxxversion }} - echo "cpp_version=${cxxversion#c++}" >> "$GITHUB_OUTPUT" - case ${{ matrix.config.compiler }} in - gcc) echo "toolchain_file=infra/cmake/gnu-toolchain.cmake" >> "$GITHUB_OUTPUT" ;; - clang*) - case ${{ matrix.config.stdlib }} in - libstdc++) - echo "toolchain_file=infra/cmake/llvm-toolchain.cmake" >> "$GITHUB_OUTPUT" ;; - libc++) - echo "toolchain_file=infra/cmake/llvm-libc++-toolchain.cmake" >> "$GITHUB_OUTPUT" ;; - esac ;; - appleclang) - echo "toolchain_file=infra/cmake/appleclang-toolchain.cmake" >> "$GITHUB_OUTPUT" ;; - msvc) - echo "toolchain_file=infra/cmake/msvc-toolchain.cmake" >> "$GITHUB_OUTPUT" ;; - esac - test=${{ matrix.config.test }} - echo "build_config=${test%%[.]*}" >> "$GITHUB_OUTPUT" - test_type=${test##*[.]} - echo "test_type=$test_type" >> "$GITHUB_OUTPUT" - case $test_type in - Default) ;; - TSan) - echo "cmake_extra_args=-DBEMAN_BUILDSYS_SANITIZER=TSan" >> "$GITHUB_OUTPUT" ;; - MaxSan) - echo "cmake_extra_args=-DBEMAN_BUILDSYS_SANITIZER=MaxSan" >> "$GITHUB_OUTPUT" ;; - Werror) - echo "cmake_extra_args=-DCMAKE_CXX_FLAGS='-Werror=all -Werror=extra'" >> "$GITHUB_OUTPUT" ;; - Dynamic) - echo "cmake_extra_args=-DBUILD_SHARED_LIBS=on" >> "$GITHUB_OUTPUT" ;; - Coverage) - echo "cmake_extra_args=-DCMAKE_CXX_FLAGS='-fno-default-inline -fno-inline --coverage -fprofile-abs-path'" >> "$GITHUB_OUTPUT";; - *) - echo "cmake_extra_args=$test_type" >> "$GITHUB_OUTPUT" ;; - esac - - name: Print parameters - shell: bash - run: | - echo ${{ matrix.config.compiler }} ${{ matrix.config.cxxversion }} ${{ matrix.config.stdlib }} ${{ matrix.config.test }} - echo ${{ steps.vars.outputs.cpp_version }} ${{ steps.vars.outputs.toolchain_file }} ${{ steps.vars.outputs.cmake_extra_args }} ${{ steps.vars.outputs.build_config }} - - name: Configure CMake - shell: bash - run: | - cmake \ - -B build \ - -S . \ - -DCMAKE_CXX_STANDARD=${{ steps.vars.outputs.cpp_version }} \ - -DCMAKE_TOOLCHAIN_FILE="${{ steps.vars.outputs.toolchain_file }}" \ - -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES="./infra/cmake/use-fetch-content.cmake" \ - ${{ steps.vars.outputs.cmake_extra_args }} - env: - CMAKE_GENERATOR: "Ninja Multi-Config" - - name: Build - shell: bash - run: | - cmake --build build --config ${{ steps.vars.outputs.build_config }} --parallel --verbose - cmake --build build --config ${{ steps.vars.outputs.build_config }} --target all_verify_interface_header_sets - cmake --install build --config ${{ steps.vars.outputs.build_config }} --prefix /opt/beman.package - ls -R /opt/beman.package - - name: Test - shell: bash - run: ctest --test-dir build --build-config ${{ steps.vars.outputs.build_config }} --output-on-failure - - name: Generate Coverage Files - if: steps.vars.outputs.test_type == 'Coverage' - shell: bash - run: | - cat > gcovr.cfg < -This repository contains the infrastructure for The Beman Project. This is NOT a library repository, so it does not -respect the usual structure of a Beman library repository nor The Beman Standard! +This repository contains the infrastructure for The Beman Project. This is NOT a library repository, +so it does not respect the usual structure of a Beman library repository nor The Beman Standard! ## Description +* `cmake/`: CMake modules and toolchain files used by Beman libraries. * `containers/`: Containers used for CI builds and tests in the Beman org. * `tools/`: Tools used to manage the infrastructure and the codebase (e.g., linting, formatting, etc.). + +## Usage + +This repository is intended to be used as a beman-submodule in other Beman repositories. See +[the Beman Submodule documentation](./tools/beman-submodule/README.md) for details. + + +### CMake Modules + + +#### `beman_install_library` + +The CMake modules in this repository are intended to be used by Beman libraries. Use the +`beman_add_install_library_config()` function to install your library, along with header +files, any metadata files, and a CMake config file for `find_package()` support. + +```cmake +add_library(beman.something) +add_library(beman::something ALIAS beman.something) + +# ... configure your target as needed ... + +find_package(beman-install-library REQUIRED) +beman_install_library(beman.something) +``` + +Note that the target must be created before calling `beman_install_library()`. The module +also assumes that the target is named using the `beman.something` convention, and it +uses that assumption to derive the names to match other Beman standards and conventions. +If your target does not follow that convention, raise an issue or pull request to add +more configurability to the module. + +The module will configure the target to install: + +* The library target itself +* Any public headers associated with the target +* CMake files for `find_package(beman.something)` support + +Some options for the project and target will also be supported: + +* `BEMAN_INSTALL_CONFIG_FILE_PACKAGES` - a list of package names (e.g., `beman.something`) for which to install the config file + (default: all packages) +* `_INSTALL_CONFIG_FILE_PACKAGE` - a per-project option to enable/disable config file installation (default: `ON` if the project is top-level, `OFF` otherwise). For instance for `beman.something`, the option would be `BEMAN_SOMETHING_INSTALL_CONFIG_FILE_PACKAGE`. diff --git a/infra/cmake/appleclang-toolchain.cmake b/infra/cmake/appleclang-toolchain.cmake index 5f44e802..70ef548e 100644 --- a/infra/cmake/appleclang-toolchain.cmake +++ b/infra/cmake/appleclang-toolchain.cmake @@ -39,3 +39,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") + +# Add this dir to the module path so that `find_package(beman-install-library)` works +list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/infra/cmake/beman-install-library-config.cmake b/infra/cmake/beman-install-library-config.cmake new file mode 100644 index 00000000..e7fd0ad3 --- /dev/null +++ b/infra/cmake/beman-install-library-config.cmake @@ -0,0 +1,169 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +include_guard(GLOBAL) + +# This file defines the function `beman_install_library` which is used to +# install a library target and its headers, along with optional CMake +# configuration files. +# +# The function is designed to be reusable across different Beman libraries. + +function(beman_install_library name) + # Usage + # ----- + # + # beman_install_library(NAME) + # + # Brief + # ----- + # + # This function installs the specified library target and its headers. + # It also handles the installation of the CMake configuration files if needed. + # + # CMake variables + # --------------- + # + # Note that configuration of the installation is generally controlled by CMake + # cache variables so that they can be controlled by the user or tool running the + # `cmake` command. Neither `CMakeLists.txt` nor `*.cmake` files should set these + # variables directly. + # + # - BEMAN_INSTALL_CONFIG_FILE_PACKAGES: + # List of packages that require config file installation. + # If the package name is in this list, it will install the config file. + # + # - _INSTALL_CONFIG_FILE_PACKAGE: + # Boolean to control config file installation for the specific library. + # The prefix `` is the uppercased name of the library with dots + # replaced by underscores. + # + if(NOT TARGET "${name}") + message(FATAL_ERROR "Target '${name}' does not exist.") + endif() + + if(NOT ARGN STREQUAL "") + message( + FATAL_ERROR + "beman_install_library does not accept extra arguments: ${ARGN}" + ) + endif() + + # Given foo.bar, the component name is bar + string(REPLACE "." ";" name_parts "${name}") + # fail if the name doesn't look like foo.bar + list(LENGTH name_parts name_parts_length) + if(NOT name_parts_length EQUAL 2) + message( + FATAL_ERROR + "beman_install_library expects a name of the form 'beman.', got '${name}'" + ) + endif() + + set(target_name "${name}") + set(install_component_name "${name}") + set(export_name "${name}") + set(package_name "${name}") + list(GET name_parts -1 component_name) + + install( + TARGETS "${target_name}" + COMPONENT "${install_component_name}" + EXPORT "${export_name}" + FILE_SET HEADERS + ) + + set_target_properties( + "${target_name}" + PROPERTIES EXPORT_NAME "${component_name}" + ) + + include(GNUInstallDirs) + + # Determine the prefix for project-specific variables + string(TOUPPER "${name}" project_prefix) + string(REPLACE "." "_" project_prefix "${project_prefix}") + + option( + ${project_prefix}_INSTALL_CONFIG_FILE_PACKAGE + "Enable building examples. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }." + ${PROJECT_IS_TOP_LEVEL} + ) + + # By default, install the config package + set(install_config_package ON) + + # Turn OFF installation of config package by default if, + # in order of precedence: + # 1. The specific package variable is set to OFF + # 2. The package name is not in the list of packages to install config files + if(DEFINED BEMAN_INSTALL_CONFIG_FILE_PACKAGES) + if( + NOT "${install_component_name}" + IN_LIST + BEMAN_INSTALL_CONFIG_FILE_PACKAGES + ) + set(install_config_package OFF) + endif() + endif() + if(DEFINED ${project_prefix}_INSTALL_CONFIG_FILE_PACKAGE) + set(install_config_package + ${${project_prefix}_INSTALL_CONFIG_FILE_PACKAGE} + ) + endif() + + if(install_config_package) + message( + DEBUG + "beman-install-library: Installing a config package for '${name}'" + ) + + include(CMakePackageConfigHelpers) + + find_file( + config_file_template + NAMES "${package_name}-config.cmake.in" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}" + NO_DEFAULT_PATH + NO_CACHE + REQUIRED + ) + set(config_package_file + "${CMAKE_CURRENT_BINARY_DIR}/${package_name}-config.cmake" + ) + set(package_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${package_name}") + configure_package_config_file( + "${config_file_template}" + "${config_package_file}" + INSTALL_DESTINATION "${package_install_dir}" + PATH_VARS PROJECT_NAME PROJECT_VERSION + ) + + set(config_version_file + "${CMAKE_CURRENT_BINARY_DIR}/${package_name}-config-version.cmake" + ) + write_basic_package_version_file( + "${config_version_file}" + VERSION "${PROJECT_VERSION}" + COMPATIBILITY ExactVersion + ) + + install( + FILES "${config_package_file}" "${config_version_file}" + DESTINATION "${package_install_dir}" + COMPONENT "${install_component_name}" + ) + + set(config_targets_file "${package_name}-targets.cmake") + install( + EXPORT "${export_name}" + DESTINATION "${package_install_dir}" + NAMESPACE beman:: + FILE "${config_targets_file}" + COMPONENT "${install_component_name}" + ) + else() + message( + DEBUG + "beman-install-library: Not installing a config package for '${name}'" + ) + endif() +endfunction() diff --git a/infra/cmake/gnu-toolchain.cmake b/infra/cmake/gnu-toolchain.cmake index b6dddf6a..d3b9f92d 100644 --- a/infra/cmake/gnu-toolchain.cmake +++ b/infra/cmake/gnu-toolchain.cmake @@ -36,3 +36,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") + +# Add this dir to the module path so that `find_package(beman-install-library)` works +list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/infra/cmake/llvm-toolchain.cmake b/infra/cmake/llvm-toolchain.cmake index 5f5ee4b8..f1623b7e 100644 --- a/infra/cmake/llvm-toolchain.cmake +++ b/infra/cmake/llvm-toolchain.cmake @@ -36,3 +36,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") + +# Add this dir to the module path so that `find_package(beman-install-library)` works +list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/infra/cmake/msvc-toolchain.cmake b/infra/cmake/msvc-toolchain.cmake index c2fffa79..bdc24de9 100644 --- a/infra/cmake/msvc-toolchain.cmake +++ b/infra/cmake/msvc-toolchain.cmake @@ -36,3 +36,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}") set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}") + +# Add this dir to the module path so that `find_package(beman-install-library)` works +list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/infra/cmake/use-fetch-content.cmake b/infra/cmake/use-fetch-content.cmake index 07c1a15d..4ed48397 100644 --- a/infra/cmake/use-fetch-content.cmake +++ b/infra/cmake/use-fetch-content.cmake @@ -152,7 +152,12 @@ function(BemanExemplar_provideDependency method package_name) APPEND BemanExemplar_debug "Redirecting find_package calls for ${BemanExemplar_pkgName} " - "to FetchContent logic fetching ${BemanExemplar_repo} at " + "to FetchContent logic.\n" + ) + string( + APPEND + BemanExemplar_debug + "Fetching ${BemanExemplar_repo} at " "${BemanExemplar_tag} according to ${BemanExemplar_lockfile}." ) message(DEBUG "${BemanExemplar_debug}") @@ -177,3 +182,6 @@ cmake_language( SET_DEPENDENCY_PROVIDER BemanExemplar_provideDependency SUPPORTED_METHODS FIND_PACKAGE ) + +# Add this dir to the module path so that `find_package(beman-install-library)` works +list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/infra/tools/beman-tidy/.markdownlintignore b/infra/tools/beman-tidy/.markdownlintignore deleted file mode 100644 index 2bfa6a4d..00000000 --- a/infra/tools/beman-tidy/.markdownlintignore +++ /dev/null @@ -1 +0,0 @@ -tests/ diff --git a/infra/tools/beman-tidy/.python-version b/infra/tools/beman-tidy/.python-version deleted file mode 100644 index e4fba218..00000000 --- a/infra/tools/beman-tidy/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12 diff --git a/infra/tools/beman-tidy/README.md b/infra/tools/beman-tidy/README.md deleted file mode 100644 index c01045e8..00000000 --- a/infra/tools/beman-tidy/README.md +++ /dev/null @@ -1,160 +0,0 @@ -# beman-tidy: The Codebase Bemanification Tool - - - -## Description - -`beman-tidy` is a tool used to check and apply -[The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). - -Purpose: The tool is used to `check` (`--dry-run`) and `apply` (`--fix-inplace`) the Beman Standard to a repository. -Note: `2025-06-07`: In order to make the best and quickly use of the tool in the entire organization, most of the -checks will not support the `--fix-inplace` flag in the first iteration. - -## Installation - -- The current recommended workflow relies on [Astral's uv](https://docs.astral.sh/uv/) -- However, we provide a [PEP 751](https://peps.python.org/pep-0751/) `pylock.toml`, so don't feel forced to use uv -- You can use beman-tidy as a pre-commit hook or install it on your system using `pipx` - -```shell -uv build -pipx install path/to/wheel -``` - -
-beman-tidy: Full example - build and install - -```shell -$ uv build -Building source distribution... -Building wheel from source distribution... -Successfully built dist/beman_tidy-0.1.0.tar.gz -Successfully built dist/beman_tidy-0.1.0-py3-none-any.whl - -$ pipx install dist/beman_tidy-0.1.0-py3-none-any.whl -Installing to existing venv 'beman-tidy' - installed package beman-tidy 0.1.0, installed using Python 3.13.4 - These apps are now globally available - - beman-tidy -... -You will need to open a new terminal or re-login for the PATH changes to take effect. Alternatively, you can source your shell's config file with e.g. 'source ~/.bashrc'. - -$ beman-tidy --help -usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] [--checks CHECKS] repo_path -... -``` - -
- -## Usage - -- Display help: - -```shell -$ uv run beman-tidy --help -usage: beman-tidy [-h] [--fix-inplace | --no-fix-inplace] [--verbose | --no-verbose] [--require-all | --no-require-all] [--checks CHECKS] repo_path - -positional arguments: - repo_path path to the repository to check - -options: - -h, --help show this help message and exit - --fix-inplace, --no-fix-inplace - Try to automatically fix found issues - --verbose, --no-verbose - print verbose output for each check - --require-all, --no-require-all - all checks are required regardless of the check type (e.g., RECOMMENDATION becomes REQUIREMENT) - --checks CHECKS array of checks to run -``` - -- Run beman-tidy on the exemplar repository **(default: dry-run mode)** - -```shell -# dry-run, require-all, non-verbose -$ uv run beman-tidy /path/to/exemplar --require-all -Summary REQUIREMENT: 1 checks PASSED, 0 checks FAILED, 4 skipped (NOT implemented). -Summary RECOMMENDATION: 2 checks PASSED, 1 checks FAILED, 35 skipped (NOT implemented). - -Coverage REQUIREMENT: 100.0% (1/1 checks passed). -Coverage RECOMMENDATION: 66.67% (2/3 checks passed). - -# dry-run, non-require-all, non-verbose -$ uv run beman-tidy /path/to/exemplar -Summary REQUIREMENT: 1 checks PASSED, 0 checks FAILED, 4 skipped (NOT implemented). -Summary RECOMMENDATION: 2 checks PASSED, 1 checks FAILED, 35 skipped (NOT implemented). - -Coverage REQUIREMENT: 100.0% (1/1 checks passed). -Note: RECOMMENDATIONs are not included (--require-all NOT set). - -``` - -or verbose mode: - -```shell -# dry-run, require-all, verbose mode - no errors -$ uv run beman-tidy /path/to/exemplar --require-all --verbose -beman-tidy pipeline started ... - -Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... PASSED - -Running check [REQUIREMENT][README.BADGES] ... - check [REQUIREMENT][README.BADGES] ... PASSED - -Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED - -Running check [RECOMMENDATION][DIRECTORY.SOURCES] ... -[WARNING ][DIRECTORY.SOURCES ]: The directory '/Users/dariusn/dev/dn/git/Beman/exemplar/src/beman/exemplar' does not exist. - check [RECOMMENDATION][DIRECTORY.SOURCES] ... FAILED - - -beman-tidy pipeline finished. - -Summary REQUIREMENT: 1 checks PASSED, 0 checks FAILED, 4 skipped (NOT implemented). -Summary RECOMMENDATION: 2 checks PASSED, 1 checks FAILED, 35 skipped (NOT implemented). - -Coverage REQUIREMENT: 100.0% (1/1 checks passed). -Coverage RECOMMENDATION: 66.67% (2/3 checks passed). -``` - -```shell -# dry-run, require-all, verbose mode - no errors -$ uv run beman-tidy /path/to/exemplar --require-all --verbose -beman-tidy pipeline started ... - -Running check [RECOMMENDATION][README.TITLE] ... - check [RECOMMENDATION][README.TITLE] ... PASSED - -Running check [REQUIREMENT][README.BADGES] ... - check [REQUIREMENT][README.BADGES] ... PASSED - -Running check [RECOMMENDATION][README.LIBRARY_STATUS] ... - check [RECOMMENDATION][README.LIBRARY_STATUS] ... PASSED - -Running check [RECOMMENDATION][DIRECTORY.SOURCES] ... - check [RECOMMENDATION][DIRECTORY.SOURCES] ... PASSED - - -beman-tidy pipeline finished. - -Summary REQUIREMENT: 1 checks PASSED, 0 checks FAILED, 4 skipped (NOT implemented). -Summary RECOMMENDATION: 3 checks PASSED, 0 checks FAILED, 35 skipped (NOT implemented). - -Coverage REQUIREMENT: 100.0% (1/1 checks passed). -Coverage RECOMMENDATION: 100.0% (3/3 checks passed). -``` - -- Run beman-tidy on the exemplar repository (fix issues in-place): - -```shell -uv run beman-tidy path/to/exemplar --fix-inplace --verbose -``` - -## beman-tidy Development - -Please refer to the [Beman Tidy Development Guide](./docs/dev-guide.md) for more details. diff --git a/infra/tools/beman-tidy/beman_tidy/.beman-standard.yml b/infra/tools/beman-tidy/beman_tidy/.beman-standard.yml deleted file mode 100644 index 47519973..00000000 --- a/infra/tools/beman-tidy/beman_tidy/.beman-standard.yml +++ /dev/null @@ -1,163 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -# TODO: 2025-06-07: This file is a partial stable snapshot of the standard. -# TODOs and placeholders will be solved in follow-up PRs when implementing the checks. - -# LICENSE -LICENSE.APPROVED: - - type: REQUIREMENT - - licenses: - - apache-v2: - - spdx: "Apache License v2.0 with LLVM Exceptions" - - path: "docs/licenses/apache-v2.txt" - - boost-v1: - - spdx: "Boost Software License 1.0" - - path: "docs/licenses/boost-v1.txt" - - mit: - - spdx: "The MIT License" - - path: "docs/licenses/mit.txt" -LICENSE.APACHE_LLVM: - - type: RECOMMENDATION -LICENSE.CRITERIA: - - type: REQUIREMENT - -# GENERAL -LIBRARY.NAMES: - - type: RECOMMENDATION - - regex: -REPOSITORY.NAME: - - type: RECOMMENDATION - - regex: -REPOSITORY.CODEOWNERS: - - type: REQUIREMENT - - default_group: "@bemanproject/core-reviewers" -REPOSITORY.DISALLOW_GIT_SUBMODULES: - - type: RECOMMENDATION - -# RELEASE -RELEASE.GITHUB: - - type: REQUIREMENT -RELEASE.NOTES: - - type: RECOMMENDATION -RELEASE.GODBOLT_TRUNK_VERSION: - - type: RECOMMENDATION -# TOP LEVEL -TOPLEVEL.CMAKE: - - type: REQUIREMENT - - value: CMakeLists.txt -TOPLEVEL.LICENSE: - - type: REQUIREMENT - - file_name: LICENSE -TOPLEVEL.README: - - type: REQUIREMENT - - file_name: README.md - -# README -README.TITLE: - - type: RECOMMENDATION -README.BADGES: - - type: REQUIREMENT - - values: [ - "![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg)", - "![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_production_ready_api_may_undergo_changes.svg)", - "![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_production_ready_stable_api.svg)", - "![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_retired.svg)" - ] -README.PURPOSE: - - type: RECOMMENDATION -README.IMPLEMENTS: - - type: RECOMMENDATION -README.LIBRARY_STATUS: - - type: REQUIREMENT - - values: [ - "**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use)", - "**Status**: [Production ready. API may undergo changes.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-api-may-undergo-changes)", - "**Status**: [Production ready. Stable API.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-stable-api)", - "**Status**: [Retired. No longer maintained or actively developed.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#retired-no-longer-maintained-or-actively-developed)", - ] - -# CMAKE -CMAKE.DEFAULT: - - type: RECOMMENDATION -CMAKE.USE_FETCH_CONTENT: - - type: RECOMMENDATION -CMAKE.PROJECT_NAME: - - type: RECOMMENDATION -CMAKE.PASSIVE_PROJECTS: - - type: RECOMMENDATION -CMAKE.LIBRARY_NAME: - - type: RECOMMENDATION - - regex: -CMAKE.LIBRARY_ALIAS: - - type: REQUIREMENT - - regex: -CMAKE.TARGET_NAMES: - - type: RECOMMENDATION - - regex: -CMAKE.PASSIVE_TARGETS: - - type: REQUIREMENT - - regex: -CMAKE.CONFIG: - - type: REQUIREMENT -CMAKE.SKIP_TESTS: - - type: RECOMMENDATION - - regex: -CMAKE.SKIP_EXAMPLES: - - type: RECOMMENDATION - - regex: -CMAKE.AVOID_PASSTHROUGHS: - - type: RECOMMENDATION - -# DIRECTORY -DIRECTORY.INTERFACE_HEADERS: - - type: REQUIREMENT - - directory_name: include - - regex: -DIRECTORY.IMPLEMENTATION_HEADERS: - - type: REQUIREMENT - - regex: -DIRECTORY.SOURCES: - - type: REQUIREMENT - - directory_name: src - - regex: -DIRECTORY.TESTS: - - type: REQUIREMENT - - directory_name: tests - - regex: -DIRECTORY.EXAMPLES: - - type: REQUIREMENT - - directory_name: examples - - regex: -DIRECTORY.DOCS: - - type: REQUIREMENT - - directory_name: docs - - regex: -DIRECTORY.PAPERS: - - type: REQUIREMENT - - directory_name: papers - -# FILE -FILE.CPP_NAMES: - - type: RECOMMENDATION - - regex: -FILE.TEST_NAMES: - - type: REQUIREMENT - - regex: -FILE.LICENSE_ID: - - type: REQUIREMENT - - regex: [ - "// SPDX-License-Identifier: ", - "# SPDX-License-Identifier: ", - "" - ] -FILE.COPYRIGHT: - - type: RECOMMENDATION - - regex: - -# CPP -CPP.NAMESPACE: - - type: RECOMMENDATION -CPP.NO_FLAG_FORKING: - - type: REQUIREMENT -CPP.EXTENSION_IDENTIFIERS: - - type: RECOMMENDATION diff --git a/infra/tools/beman-tidy/beman_tidy/__init__.py b/infra/tools/beman-tidy/beman_tidy/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/beman_tidy/cli.py b/infra/tools/beman-tidy/beman_tidy/cli.py deleted file mode 100755 index de648110..00000000 --- a/infra/tools/beman-tidy/beman_tidy/cli.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import argparse -import sys - -from beman_tidy.lib.utils.git import get_repo_info, load_beman_standard_config -from beman_tidy.lib.pipeline import run_checks_pipeline - - -def parse_args(): - """ - Parse the CLI arguments. - """ - - parser = argparse.ArgumentParser() - parser.add_argument("repo_path", help="path to the repository to check", type=str) - parser.add_argument( - "--fix-inplace", - help="Try to automatically fix found issues", - action=argparse.BooleanOptionalAction, - default=False, - ) - parser.add_argument( - "--verbose", - help="print verbose output for each check", - action=argparse.BooleanOptionalAction, - default=False, - ) - parser.add_argument( - "--require-all", - help="all checks are required regardless of their type (e.g., all RECOMMENDATIONs become REQUIREMENTs)", - action=argparse.BooleanOptionalAction, - default=False, - ) - parser.add_argument( - "--checks", help="array of checks to run", type=str, default=None - ) - args = parser.parse_args() - - args.repo_info = get_repo_info(args.repo_path) - args.checks = args.checks.split(",") if args.checks else None - - return args - - -def main(): - """ - The beman-tidy main entry point. - """ - args = parse_args() - - beman_standard_check_config = load_beman_standard_config() - if not beman_standard_check_config or len(beman_standard_check_config) == 0: - print("Failed to download the beman standard. STOP.") - return - - checks_to_run = ( - [check for check in beman_standard_check_config] - if args.checks is None - else args.checks - ) - - failed_checks = run_checks_pipeline( - checks_to_run, args, beman_standard_check_config - ) - sys.exit(failed_checks) - - -if __name__ == "__main__": - main() diff --git a/infra/tools/beman-tidy/beman_tidy/lib/__init__.py b/infra/tools/beman-tidy/beman_tidy/lib/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/__init__.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/base/__init__.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/base/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py deleted file mode 100644 index f3431ab6..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/base/base_check.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -from abc import ABC, abstractmethod -from pathlib import Path - -from ..system.registry import get_beman_standard_check_name_by_class - - -class BaseCheck(ABC): - """ - Base class for checks. - This class is not meant to be used directly, it's meant to be subclassed. - e.g., check for repository name, check for changelog, check for license, etc. - """ - - def __init__(self, repo_info, beman_standard_check_config, name=None): - """ - Create a new check instance. - """ - - # check name - e.g. "README.TITLE" - self.name = ( - name - if name is not None - else get_beman_standard_check_name_by_class(self.__class__) - ) - assert self.name is not None, ( - f"Check name not found for class: {self.__class__.__name__}" - ) - - # save the check config - self.config = beman_standard_check_config[self.name] - - # set type - e.g. "REQUIREMENT" or "RECOMMENDATION" - self.type = beman_standard_check_config[self.name]["type"] - assert self.type in ["REQUIREMENT", "RECOMMENDATION"], ( - f"Invalid check type: {self.type} for check = {self.name}." - ) - - # set full text body - e.g. "The README.md should begin ..." - self.full_text_body = beman_standard_check_config[self.name]["full_text_body"] - assert self.full_text_body is not None - - # set log level - e.g. "ERROR" or "WARNING" - self.log_level = "ERROR" if self.type == "REQUIREMENT" else "WARNING" - self.log_enabled = False - - # set repo info - self.repo_info = repo_info - assert "name" in repo_info - self.repo_name = repo_info["name"] - assert "top_level" in repo_info - self.repo_path = Path(repo_info["top_level"]) - assert self.repo_path is not None - self.library_name = f"beman.{self.repo_name}" - assert self.library_name is not None - - # set beman library maturity model - beman_library_maturity_model = beman_standard_check_config[ - "README.LIBRARY_STATUS" - ] - assert "values" in beman_library_maturity_model - assert len(beman_library_maturity_model["values"]) == 4 - self.beman_library_maturity_model = beman_library_maturity_model["values"] - - def pre_check(self): - """ - Pre-checks if this rule is properly initialized. - Usually, this is internal use only. - - Note: This method is internally called by the framework. - """ - if self.name is None: - self.log("The name is not set.") - return False - - if self.repo_name is None: - self.log(f"The repo_name is not set for check = {self.name}.") - return False - - if not self.repo_path: - self.log(f"The repo_path is not set for check = {self.name}.") - return False - - return True - - @abstractmethod - def check(self): - """ - Checks if the Beman Standard check is already applied. - - If it's applied, this method should return True. - - Otherwise, it returns False and self.fix() must be able to fix the issue. - - Note: This methods must be always implemented. - """ - pass - - @abstractmethod - def fix(self): - """ - Fixes the issue if the Beman Standard is not applied. - - If check already applied, this method is a no-op and should return True. - - Otherwise, it will try to apply the check inplace. Returns the status of the fix attempt. - - Note: The subclasses might not implement more than a stub if the fix method - is too difficult to implement or does not make sense. - """ - pass - - def log(self, message, enabled=True): - """ - Logs a message with the check's log level. - e.g. [WARN][REPOSITORY.NAME]: The name "${name}" should be snake_case.' - e.g. [ERROR][TOPLEVEL.CMAKE]: Missing top level CMakeLists.txt.' - """ - - if self.log_enabled and enabled: - print(f"[{self.log_level:<15}][{self.name:<25}]: {message}") diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py deleted file mode 100644 index d43a39fe..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/base/directory_base_check.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -from abc import abstractmethod -from pathlib import Path - -from .base_check import BaseCheck - - -class DirectoryBaseCheck(BaseCheck): - """ - Base class for checks that operate on a directory. - """ - - def __init__(self, repo_info, beman_standard_check_config, relative_path): - super().__init__(repo_info, beman_standard_check_config) - - # set path - e.g. "src/beman/exemplar" - self.path = self.repo_path / relative_path - - def pre_check(self): - """ - Override. - Pre-checks if the directory exists and is not empty. - """ - if not super().pre_check(): - return False - - if self.path is None: - self.log("The path is not set.") - return False - - if not self.path.exists(): - self.log(f"The directory '{self.path}' does not exist.") - return False - - if self.is_empty(): - self.log(f"The directory '{self.path}' is empty.") - return False - - return True - - @abstractmethod - def check(self): - """ - Override this method, make it abstract because this is style an abstract class. - """ - pass - - @abstractmethod - def fix(self): - """ - Override this method, make it abstract because this is style an abstract class. - """ - pass - - def read(self) -> list[Path]: - """ - Read the directory content. - """ - try: - return list(self.path.iterdir()) - except Exception: - return [] - - def is_empty(self): - """ - Check if the directory is empty. - """ - return len(self.read()) == 0 diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py deleted file mode 100644 index bea8eeee..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/base/file_base_check.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -from abc import abstractmethod -import re - -from .base_check import BaseCheck - - -class FileBaseCheck(BaseCheck): - """ - Base class for checks that operate on a file. - """ - - def __init__(self, repo_info, beman_standard_check_config, relative_path): - super().__init__(repo_info, beman_standard_check_config) - - # set path - e.g. "README.md" - self.path = self.repo_path / relative_path - - def pre_check(self): - """ - Override. - Pre-checks if the file exists and is not empty. - """ - if not super().pre_check(): - return False - - if self.path is None: - self.log("The path is not set.") - return False - - if not self.path.exists(): - self.log(f"The file '{self.path}' does not exist.") - return False - - if self.is_empty(): - self.log(f"The file '{self.path}' is empty.") - return False - - return True - - @abstractmethod - def check(self): - """ - Override this method, make it abstract because this is style an abstract class. - """ - pass - - @abstractmethod - def fix(self): - """ - Override this method, make it abstract because this is style an abstract class. - """ - pass - - def read(self): - """ - Read the file content. - """ - try: - with open(self.path, "r") as file: - return file.read() - except Exception: - return "" - - def read_lines(self): - """ - Read the file content as lines. - """ - try: - with open(self.path, "r") as file: - return file.readlines() - except Exception: - return [] - - def read_lines_strip(self): - """ - Read the file content as lines and strip them. - """ - return [line.strip() for line in self.read_lines()] - - def write(self, content): - """ - Write the content to the file. - """ - try: - with open(self.path, "w") as file: - file.write(content) - except Exception as e: - self.log(f"Error writing the file '{self.path}': {e}") - - def write_lines(self, lines): - """ - Write the lines to the file. - """ - self.write("\n".join(lines)) - - def replace_line(self, line_number, new_line): - """ - Replace the line at the given line number with the new line. - """ - lines = self.read_lines() - lines[line_number] = new_line - self.write_lines(lines) - - def is_empty(self): - """ - Check if the file is empty. - """ - return len(self.read()) == 0 - - def has_content(self, content_to_match): - """ - Check if the file contains the given content (literal string match). - """ - readme_content = self.read() - if not readme_content or len(readme_content) == 0: - return False - return re.search(re.escape(content_to_match), readme_content) is not None diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/__init__.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py deleted file mode 100644 index 49d9d24c..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cmake.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -from ..base.file_base_check import FileBaseCheck - -# [CMAKE.*] checks category. -# All checks in this file extend the CMakeBaseCheck class. -# -# Note: CMakeBaseCheck is not a registered check! - - -class CMakeBaseCheck(FileBaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config, "CMakeLists.txt") - - -# TODO CMAKE.DEFAULT - - -# TODO CMAKE.USE_FETCH_CONTENT - - -# TODO CMAKE.PROJECT_NAME - - -# TODO CMAKE.PASSIVE_PROJECTS - - -# TODO CMAKE.LIBRARY_NAME - - -# TODO CMAKE.LIBRARY_ALIAS - - -# TODO CMAKE.TARGET_NAMES - - -# TODO CMAKE.PASSIVE_TARGETS - - -# TODO CMAKE.SKIP_TESTS - - -# TODO CMAKE.SKIP_EXAMPLES - - -# TODO CMAKE.AVOID_PASSTHROUGHS diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py deleted file mode 100644 index 6868f23e..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/cpp.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -# [CPP.*] checks category. - - -# TODO CPP.NAMESPACE - - -# TODO CPP.NO_FLAG_FORKING - - -# TODO CPP.EXTENSION_IDENTIFIERS diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py deleted file mode 100644 index d533bb3a..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/directory.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -from ..base.directory_base_check import DirectoryBaseCheck -from ..system.registry import register_beman_standard_check - - -# [DIRECTORY.*] checks category. -class BemanTreeDirectoryCheck(DirectoryBaseCheck): - """ - Check if the directory tree is a Beman tree. - """ - - def __init__(self, repo_info, beman_standard_check_config, prefix_path): - super().__init__( - repo_info, - beman_standard_check_config, - f"{prefix_path}/beman/{repo_info['name']}", - ) - - -# TODO DIRECTORY.INTERFACE_HEADERS - - -# TODO DIRECTORY.IMPLEMENTATION_HEADERS - - -# TODO DIRECTORY.SOURCES -@register_beman_standard_check("DIRECTORY.SOURCES") -class DirectorySourcesCheck(BemanTreeDirectoryCheck): - """ - Check if the sources directory is src/beman/. - """ - - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config, "src") - - def check(self): - return self.pre_check() - - def fix(self): - """ - TODO: Implement the fix. - """ - pass - - -# TODO DIRECTORY.TESTS - - -# TODO DIRECTORY.EXAMPLES - - -# TODO DIRECTORY.DOCS - - -# TODO DIRECTORY.PAPERS diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py deleted file mode 100644 index b66e8bec..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/file.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -# [FILE.*] checks category. -# All checks in this file extend the FileBaseCheck class. -# -# Note: FileBaseCheck is not a registered check! - - -# TODO FILE.NAMES - - -# TODO FILE.TEST_NAMES - - -# TODO FILE.LICENSE_ID - - -# TODO FILE.COPYRIGHT diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py deleted file mode 100644 index d0847539..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/general.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -# TODO LIBRARY.NAMES -# TODO REPOSITORY.NAME -# TODO REPOSITORY.CODEOWNERS -# TODO REPOSITORY.DISALLOW_GIT_SUBMODULES diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py deleted file mode 100644 index 6eb75ab5..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/license.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -from ..base.file_base_check import FileBaseCheck - -# [LICENSE.*] checks category. -# All checks in this file extend the LicenseBaseCheck class. -# -# Note: LicenseBaseCheck is not a registered check! - - -class LicenseBaseCheck(FileBaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config, "LICENSE") - - -# TODO LICENSE.APPROVED - - -# TODO LICENSE.APACHE_LLVM - - -# TODO LICENSE.CRITERIA diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py deleted file mode 100644 index 92a85751..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/readme.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import re - -from ..base.file_base_check import FileBaseCheck -from ..system.registry import register_beman_standard_check - -# [README.*] checks category. -# All checks in this file extend the ReadmeBaseCheck class. -# -# Note: ReadmeBaseCheck is not a registered check! - - -class ReadmeBaseCheck(FileBaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config, "README.md") - - -@register_beman_standard_check("README.TITLE") -class ReadmeTitleCheck(ReadmeBaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config) - - def check(self): - lines = self.read_lines_strip() - first_line = lines[0] - - # Match the pattern "# [: ]" - regex = rf"^# {re.escape(self.library_name)}: (.*)$" # noqa: F541 - if not re.match(regex, first_line): - self.log( - f"The first line of the file '{self.path}' is invalid. It should start with '# {self.library_name}: '." - ) - return False - - return True - - def fix(self): - """ - Fix the issue if the Beman Standard is not applied. - """ - new_title_line = f"# {self.library_name}: TODO Short Description" - self.replace_line(0, new_title_line) - return True - - -@register_beman_standard_check("README.BADGES") -class ReadmeBadgesCheck(ReadmeBaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config) - - def check(self): - """ - self.config["values"] contains a fixed set of Beman badges. - """ - badges = self.config["values"] - assert len(badges) == 4 # The number of library maturity model states - - # Check if exactly one of the required badges is present. - badge_count = len([badge for badge in badges if self.has_content(badge)]) - if badge_count != 1: - self.log( - f"The file '{self.path}' does not contain exactly one of the required badges from {badges}" - ) - return False - - return True - - def fix(self): - # TODO: Implement the fix. - pass - - -@register_beman_standard_check("README.IMPLEMENTS") -class ReadmeImplementsCheck(ReadmeBaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config) - - def check(self): - lines = self.read_lines_strip() - - # Match the pattern to start with "Implements:" and then have a paper reference and a wg21.link URL. - # Examples of valid lines: - # **Implements**: [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - # **Implements**: [Give *std::optional* Range Support (P3168R2)](https://wg21.link/P3168R2) and [`std::optional` (P2988R5)](https://wg21.link/P2988R5) - # **Implements**: [.... (PxyzwRr)](https://wg21.link/PxyzwRr), [.... (PabcdRr)](https://wg21.link/PabcdRr), and [.... (PijklRr)](https://wg21.link/PijklRr), - regex = r"^\*\*Implements\*\*:\s+.*\bP\d{4}R\d+\b.*wg21\.link/\S+" - - # Count how many lines match the regex - implement_lines = 0 - for line in lines: - if re.match(regex, line): - implement_lines += 1 - - # If there is exactly one "Implements:" line, it is valid - if implement_lines == 1: - return True - - # Invalid/missing/duplicate "Implements:" line - self.log( - f"Invalid/missing/duplicate 'Implements:' line in '{self.path}'. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#readmeimplements for more information." - ) - return False - - def fix(self): - self.log( - "Please write a Implements line in README.md file. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#readmeimplements for the desired format." - ) - return False - - -@register_beman_standard_check("README.LIBRARY_STATUS") -class ReadmeLibraryStatusCheck(ReadmeBaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config) - - def check(self): - """ - self.config["values"] contains a fixed set of Beman library statuses. - """ - statuses = self.config["values"] - assert len(statuses) == len(self.beman_library_maturity_model) - - # Check if at least one of the required status values is present. - status_count = len([status for status in statuses if self.has_content(status)]) - if status_count != 1: - self.log( - f"The file '{self.path}' does not contain exactly one of the required statuses from {statuses}" - ) - return False - - return True - - def fix(self): - # TODO: Implement the fix. - pass diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py deleted file mode 100644 index 6c2f59b1..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/release.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -# [RELEASE.*] checks category. -# Note: Data is stored online - e.g. https://github.com/bemanproject/exemplar/releases -# TBD - Do we want to implement these checks? - - -# TODO RELEASE.GITHUB - - -# TODO RELEASE.NOTES - - -# TODO RELEASE.GODBOLT_TRUNK_VERSION diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py deleted file mode 100644 index f4c4ad30..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/beman_standard/toplevel.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -from .cmake import CMakeBaseCheck -from .license import LicenseBaseCheck -from .readme import ReadmeBaseCheck -from ..system.registry import register_beman_standard_check - -# [TOPLEVEL.*] checks category. -# All checks in this file extend the ToplevelBaseCheck class. -# -# Note: ToplevelBaseCheck is not a registered check! - - -@register_beman_standard_check(check="TOPLEVEL.CMAKE") -class ToplevelCmakeCheck(CMakeBaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config) - - def check(self): - return super().pre_check() - - def fix(self): - # TODO: Implement the fix. - pass - - -@register_beman_standard_check("TOPLEVEL.LICENSE") -class ToplevelLicenseCheck(LicenseBaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config) - - def check(self): - # since this class simply checks for the existence of a LICENSE file, - # there's nothing more to do than the default pre-check. - return super().pre_check() - - def fix(self): - self.log( - "Please add a LICENSE file to the repository. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#license for more information." - ) - - -@register_beman_standard_check("TOPLEVEL.README") -class ToplevelReadmeCheck(ReadmeBaseCheck): - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config) - - def check(self): - # since this class simply checks for the existence of a README file, - # there's nothing more to do than the default pre-check. - return super().pre_check() - - def fix(self): - self.log( - "Please write a README file. See https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md#readmemd for the desired format." - ) diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/system/__init__.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/system/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/system/git.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/system/git.py deleted file mode 100644 index ecc11456..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/system/git.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import sys - -from ..base.base_check import BaseCheck - - -class DisallowFixInplaceAndUnstagedChangesCheck(BaseCheck): - """ - If fix is attempted, disallow it if there are unstaged changes. - """ - - def __init__(self, repo_info, beman_standard_check_config): - super().__init__(repo_info, beman_standard_check_config, "NO_UNSTAGED_CHANGES") - - def check(self): - """ - Should not allow fix if there are unstaged changes. - """ - return len(self.repo_info["unstaged_changes"]) == 0 - - def fix(self): - """ - Stop the program if there are unstaged changes. - """ - self.log( - "The fix cannot be applied inplace. Please commit or stash your changes. STOP." - ) - sys.exit(1) diff --git a/infra/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py b/infra/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py deleted file mode 100644 index cabb8ac2..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/checks/system/registry.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -from typing import Dict, Type, List - -# Registry to store all The Beman Standard check classes. -_beman_standard_check_registry: Dict[str, Type] = {} - - -def register_beman_standard_check(check: str): - """ - Decorator to register a check class with a specific ID. - - Usage: - @register_beman_standard_check("README.TITLE") - class ReadmeTitleCheck(ReadmeBaseCheck): - ... - - Notes: Only register most derived check classes, which are actually part from - The Beman Standard - e.g., README.TITLE, README.BADGES, etc. - """ - - def decorator(check_class: Type) -> Type: - _beman_standard_check_registry[check] = check_class - return check_class - - return decorator - - -def get_registered_beman_standard_checks() -> Dict[str, Type]: - """Get all registered check classes""" - return _beman_standard_check_registry.copy() - - -def get_beman_standard_check_by_name(check_name: str) -> Type: - """Get a specific check class by its name""" - return _beman_standard_check_registry.get(check_name) - - -def get_all_beman_standard_check_names() -> List[str]: - """Get all registered check names""" - return list(_beman_standard_check_registry.keys()) - - -def get_beman_standard_check_name_by_class(target_check_class: Type) -> str: - """Get the name of a check class""" - for check_name, check_class in _beman_standard_check_registry.items(): - if check_class == target_check_class: - return check_name - return None diff --git a/infra/tools/beman-tidy/beman_tidy/lib/pipeline.py b/infra/tools/beman-tidy/beman_tidy/lib/pipeline.py deleted file mode 100644 index a5d7d408..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/pipeline.py +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import sys - -from .checks.system.registry import get_registered_beman_standard_checks -from .checks.system.git import DisallowFixInplaceAndUnstagedChangesCheck - -# import all the implemented checks. -# TODO: Consider removing F403 from ignored lint checks -from .checks.beman_standard.cmake import * # noqa: F401, F403 -from .checks.beman_standard.cpp import * # noqa: F401, F403 -from .checks.beman_standard.directory import * # noqa: F401, F403 -from .checks.beman_standard.file import * # noqa: F401, F403 -from .checks.beman_standard.general import * # noqa: F401, F403 -from .checks.beman_standard.license import * # noqa: F401, F403 -from .checks.beman_standard.readme import * # noqa: F401, F403 -from .checks.beman_standard.release import * # noqa: F401, F403 -from .checks.beman_standard.toplevel import * # noqa: F401, F403 - -red_color = "\033[91m" -green_color = "\033[92m" -yellow_color = "\033[93m" -gray_color = "\033[90m" -no_color = "\033[0m" - - -def run_checks_pipeline(checks_to_run, args, beman_standard_check_config): - """ - Run the checks pipeline for The Beman Standard. - Read-only checks if args.fix_inplace is False, otherwise try to fix the issues in-place. - Verbosity is controlled by args.verbose. - - @return: The number of failed checks. - """ - - """ - Helper function to log messages. - """ - - def log(msg): - if args.verbose: - print(msg) - - """ - Helper function to run a check. - @param check_class: The check class type to run. - @param log_enabled: Whether to log the check result. - @return: True if the check passed, False otherwise. - """ - - def run_check(check_class, log_enabled=args.verbose): - check_instance = check_class(args.repo_info, beman_standard_check_config) - check_instance.log_enabled = log_enabled - check_type = check_instance.type - - log(f"Running check [{check_instance.type}][{check_instance.name}] ... ") - - if (check_instance.pre_check() and check_instance.check()) or ( - args.fix_inplace and check_instance.fix() - ): - log( - f"\tcheck [{check_instance.type}][{check_instance.name}] ... {green_color}PASSED{no_color}\n" - ) - return check_type, True - else: - log( - f"\tcheck [{check_instance.type}][{check_instance.name}] ... {red_color}FAILED{no_color}\n" - ) - return check_type, False - - """ - Main pipeline. - """ - - def run_pipeline_helper(): - # Internal checks - if args.fix_inplace: - run_check(DisallowFixInplaceAndUnstagedChangesCheck, log_enabled=False) - - implemented_checks = get_registered_beman_standard_checks() - all_checks = beman_standard_check_config - - cnt_passed = { - "REQUIREMENT": 0, - "RECOMMENDATION": 0, - } - cnt_failed = { - "REQUIREMENT": 0, - "RECOMMENDATION": 0, - } - for check_name in checks_to_run: - if check_name not in implemented_checks: - continue - - check_type, passed = run_check(implemented_checks[check_name]) - if passed: - cnt_passed[check_type] += 1 - else: - cnt_failed[check_type] += 1 - - cnt_skipped = { - "REQUIREMENT": 0, - "RECOMMENDATION": 0, - } - cnt_all_beman_standard_checks = { - "REQUIREMENT": 0, - "RECOMMENDATION": 0, - } - cnt_implemented_checks = { - "REQUIREMENT": 0, - "RECOMMENDATION": 0, - } - for check_name in all_checks: - check_type = all_checks[check_name]["type"] - cnt_all_beman_standard_checks[check_type] += 1 - - if check_name not in implemented_checks: - cnt_skipped[check_type] += 1 - else: - cnt_implemented_checks[check_type] += 1 - - return ( - cnt_passed, - cnt_failed, - cnt_skipped, - cnt_implemented_checks, - cnt_all_beman_standard_checks, - ) - - log("beman-tidy pipeline started ...\n") - ( - cnt_passed, - cnt_failed, - cnt_skipped, - cnt_implemented_checks, - cnt_all_beman_standard_checks, - ) = run_pipeline_helper() - log("\nbeman-tidy pipeline finished.\n") - - # Always print the summary. - print( - f"Summary REQUIREMENT: {green_color} {cnt_passed['REQUIREMENT']} checks PASSED{no_color}, {red_color}{cnt_failed['REQUIREMENT']} checks FAILED{no_color}, {gray_color}{cnt_skipped['REQUIREMENT']} skipped (NOT implemented).{no_color}" - ) - print( - f"Summary RECOMMENDATION: {green_color} {cnt_passed['RECOMMENDATION']} checks PASSED{no_color}, {red_color}{cnt_failed['RECOMMENDATION']} checks FAILED{no_color}, {gray_color}{cnt_skipped['RECOMMENDATION']} skipped (NOT implemented).{no_color}" - ) - - # Always print the coverage. - coverage_requirement = round( - cnt_passed["REQUIREMENT"] / cnt_implemented_checks["REQUIREMENT"] * 100, 2 - ) - coverage_recommendation = round( - cnt_passed["RECOMMENDATION"] / cnt_implemented_checks["RECOMMENDATION"] * 100, 2 - ) - total_passed = cnt_passed["REQUIREMENT"] + cnt_passed["RECOMMENDATION"] - total_implemented = ( - cnt_implemented_checks["REQUIREMENT"] + cnt_implemented_checks["RECOMMENDATION"] - ) - total_coverage = round((total_passed) / (total_implemented) * 100, 2) - print( - f"\n{__calculate_coverage_color(coverage_requirement)}Coverage REQUIREMENT: {coverage_requirement:{6}.2f}% ({cnt_passed['REQUIREMENT']}/{cnt_implemented_checks['REQUIREMENT']} checks passed).{no_color}" - ) - if args.require_all: - print( - f"{__calculate_coverage_color(coverage_recommendation)}Coverage RECOMMENDATION: {coverage_recommendation:{6}.2f}% ({cnt_passed['RECOMMENDATION']}/{cnt_implemented_checks['RECOMMENDATION']} checks passed).{no_color}" - ) - print( - f"{__calculate_coverage_color(total_coverage)}Coverage TOTAL: {total_coverage:{6}.2f}% ({total_passed}/{total_implemented} checks passed).{no_color}" - ) - else: - print("Note: RECOMMENDATIONs are not included (--require-all NOT set).") - total_cnt_failed = cnt_failed["REQUIREMENT"] + ( - cnt_failed["RECOMMENDATION"] if args.require_all else 0 - ) - - sys.stdout.flush() - return total_cnt_failed - - -def __calculate_coverage_color(cov): - """ - Returns the colour for the coverage print based on severity - Green for 100% - Red for 0% - Yellow for anything else - """ - if cov == 100: - return green_color - elif cov == 0: - return red_color - else: - return yellow_color diff --git a/infra/tools/beman-tidy/beman_tidy/lib/utils/__init__.py b/infra/tools/beman-tidy/beman_tidy/lib/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/beman_tidy/lib/utils/git.py b/infra/tools/beman-tidy/beman_tidy/lib/utils/git.py deleted file mode 100644 index 7f8e3d85..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/utils/git.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import sys -import yaml -from pathlib import Path - -from git import Repo, InvalidGitRepositoryError - - -def get_repo_info(path: str): - """ - Get information about the repository at the given path. - Returns data as a dictionary. - """ - - path: Path = Path(path) - try: - # Initialize the repository object - repo = Repo(path.absolute(), search_parent_directories=True) - - # Get the top-level directory of the repository - top_level_dir = Path(repo.git.rev_parse("--show-toplevel")) - - # Get the repository name (directory name of the top level) - repo_name = top_level_dir.name - - # Get the remote URL (assuming 'origin' is the remote name) - remote_url = None - if "origin" in repo.remotes: - remote_url = repo.remotes.origin.url - - # Get the current branch - current_branch = repo.active_branch.name - - # Get the commit hash - commit_hash = repo.head.commit.hexsha - - # Get the status of the repository - status = repo.git.status() - - # Get unstaged changes - unstaged_changes = repo.git.diff("--stat") - - return { - "top_level": top_level_dir, - "name": repo_name, - "remote_url": remote_url, - "current_branch": current_branch, - "commit_hash": commit_hash, - "status": status, - "unstaged_changes": unstaged_changes, - } - except InvalidGitRepositoryError: - print(f"The path '{path}' is not inside a valid Git repository.") - sys.exit(1) - except Exception: - print(f"An error occurred while getting repository information. Check {path}.") - sys.exit(1) - - -def get_beman_standard_config_path(): - """ - Get the path to the Beman Standard YAML configuration file. - """ - return Path(__file__).parent.parent.parent / ".beman-standard.yml" - - -def load_beman_standard_config(path=get_beman_standard_config_path()): - """ - Load the Beman Standard YAML configuration file from the given path. - """ - with open(path, "r") as file: - beman_standard_yml = yaml.safe_load(file) - - beman_standard_check_config = {} - for check_name in beman_standard_yml: - check_config = { - "name": check_name, - "full_text_body": "", - "type": "", - "regex": "", - "file_name": "", - "directory_name": "", - "badge_lines": "", - "status_lines": "", - "licenses": "", - "default_group": "", - } - for entry in beman_standard_yml[check_name]: - if "type" in entry: - check_config["type"] = entry["type"] - elif "value" in entry: # e.g., "a string value" - check_config["value"] = entry["value"] - # e.g., ["a string value", "another string value"] - elif "values" in entry: - check_config["values"] = entry["values"] - elif "regex" in entry: - # TODO: Implement the regex check. - pass - elif "file_name" in entry: - check_config["file_name"] = entry["file_name"] - elif "directory_name" in entry: - pass - elif "values" in entry: - # TODO: Implement the values check. - pass - elif "status_lines" in entry: - # TODO: Implement the status check. - pass - elif "licenses" in entry: - # TODO: Implement the license check. - pass - elif "default_group" in entry: - check_config["default_group"] = entry["default_group"] - else: - raise ValueError(f"Invalid entry in Beman Standard YAML: {entry}") - - beman_standard_check_config[check_name] = check_config - - return beman_standard_check_config diff --git a/infra/tools/beman-tidy/beman_tidy/lib/utils/string.py b/infra/tools/beman-tidy/beman_tidy/lib/utils/string.py deleted file mode 100644 index 07329da2..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/utils/string.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import re - - -def is_snake_case(name): - return re.match("(^[a-z0-9]+$)|(^[a-z0-9][a-z0-9_.]+[a-z0-9]$)", name) - - -def is_beman_snake_case(name): - """ - Has prefix "beman." and continues with snake_case. - It must NOT end with a C++ target standard version - e.g. 17, 20, 23, 26, 32, etc. - """ - - return ( - name[:6] == "beman." - and is_snake_case(name[6:]) - and not re.match(".*[0-9]+$", name[6:]) - ) - - -def match_badges(string): - """ - e.g., ![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - """ - if string is None: - return None - - badges_str = re.findall(r"!\[[^\]]+\]\([^)]+\)", string) - return [ - re.match(r"!\[([^\]]+)\]\(([^)]+)\)", badge).groups() for badge in badges_str - ] - - -def skip_lines(lines, n): - return lines[n:] if lines is not None else None - - -def skip_empty_lines(lines): - if lines is None: - return None - - while len(lines) > 0 and len(lines[0].strip()) == 0: - lines = lines[1:] - return lines diff --git a/infra/tools/beman-tidy/beman_tidy/lib/utils/terminal.py b/infra/tools/beman-tidy/beman_tidy/lib/utils/terminal.py deleted file mode 100644 index 6ba12977..00000000 --- a/infra/tools/beman-tidy/beman_tidy/lib/utils/terminal.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import subprocess - - -def run_command(command, return_stdout=False, cwd=None): - """ - Run a command in the shell and return the return code. - If return_stdout is True, return the stdout of the command. - Optionally, change the current working directory to cwd. - """ - print(f"Running command: {command} with cwd: {cwd}") - if return_stdout: - bin = subprocess.Popen( - command, shell=True, stdout=subprocess.PIPE, cwd=cwd - ).stdout.read() - return bin.decode("utf-8") - else: - return subprocess.run(command, shell=True, cwd=cwd).returncode diff --git a/infra/tools/beman-tidy/docs/dev-guide.md b/infra/tools/beman-tidy/docs/dev-guide.md deleted file mode 100644 index 036e4732..00000000 --- a/infra/tools/beman-tidy/docs/dev-guide.md +++ /dev/null @@ -1,135 +0,0 @@ -# Beman Tidy Development Guide - -## Tree structure - -* `README.md`: The public documentation for the `beman-tidy` tool. -* `docs/`: The internal documentation. -* `beman_tidy/`: The package/production code for the tool. - * `beman_tidy/cli.py`: The CLI / entry point for the tool. - * `beman_tidy/lib/`: The library for the tool. - * `beman_tidy/lib/checks/`: The checks for the tool. - * `beman_tidy/lib/pipeline.py`: The checks pipeline for the `beman-tidy` tool. - * `beman_tidy/.beman-standard.yml`: Stable (offline) version of the standard. -* `tests/`: Unit tests for the tool. - * Structure is similar to the `beman_tidy/` directory. - * `pytest` is used for testing. - -## Adding a new check - -Find an unimplemented check in the [BEMAN_STANDARD.md](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md) file and check that is not already assigned in [Planning for beman-tidy: The Codebase Bemanification Tool](https://github.com/orgs/bemanproject/projects/8/views/1). - - -Check this PR example: [beman-tidy: add check - README.LIBRARY_STATUS](https://github.com/bemanproject/infra/pull/35). - -
-Step by step tutorial: add a new check - -* `[mandatory]` Make sure `beman_tidy/.beman-standard.yml` reflects your check metadata (latest status from [BEMAN_STANDARD.md](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md)). - * `[optional]` New syntax / keys from yml config can be added in - [infra/tools/beman-tidy/beman_tidy/lib/utils_git.py:load_beman_standard_config()](https://github.com/bemanproject/infra/blob/main/tools/beman-tidy/beman_tidy/lib/utils/git.py) - if not already implemented. Checks for TODOs in `load_beman_standard_config()`. -* `[mandatory]` Add the check to the `beman_tidy/lib/checks/beman_standard/` directory. - * `[mandatory]` e.g., `README.*` checks will most likely go to a path similar to `beman_tidy/lib/checks/beman_standard/readme.py`. - * `[mandatory]` Use an appropriate base class - e.g., defaults like `FileBaseCheck` / `DirectoryBaseCheck` or create - specializations for reusing code - e.g., `ReadmeBaseCheck(FileBaseCheck)` / `CmakeBaseCheck(FileBaseCheck)` / - `CppBaseCheck(FileBaseCheck)` etc. - * `[mandatory]` Register the new check via `@register_beman_standard_check` decorator - e.g., - - ```python - @register_beman_standard_check("README.TITLE") - class ReadmeTitleCheck(ReadmeBaseCheck): - ``` - -* `[mandatory]` Add tests for the check to the `tests/beman_standard/` directory. More in [Writing Tests](#writing-tests). -* `[optional]` Updates docs if needed in `README.md` and `docs/dev-guide.md` files. -* `[optional]` Update the `beman_tidy/cli.py` file if the public API has changed. - -
- - -## Linting - -Run the linter on the beman-tidy's codebase: - -```shell -uv run ruff check --diff -uv run ruff check --fix -``` - -## Testing - -### Running Tests - -Run the tests: - -```shell -$ uv run pytest -================================================================================================================ test session starts ================================================================================================================ -platform darwin -- Python 3.14.0b2, pytest-8.4.0, pluggy-1.6.0 -- /Users/dariusn/dev/dn/git/Beman/infra/tools/beman-tidy/.venv/bin/python -cachedir: .pytest_cache -rootdir: /Users/dariusn/dev/dn/git/Beman/infra/tools/beman-tidy -configfile: pyproject.toml -collected 6 items - -tests/beman_standard/readme/test_readme.py::test__README_TITLE__valid PASSED [ 16%] -tests/beman_standard/readme/test_readme.py::test__README_TITLE__invalid PASSED [ 33%] -tests/beman_standard/readme/test_readme.py::test__README_TITLE__fix_inplace PASSED [ 50%] -tests/beman_standard/readme/test_readme.py::test__README_BADGES__valid PASSED [ 66%] -tests/beman_standard/readme/test_readme.py::test__README_BADGES__invalid PASSED [ 83%] -tests/beman_standard/readme/test_readme.py::test__README_BADGES__fix_inplace SKIPPED (NOT implemented) [100%] - -=========================================================================================================== 5 passed, 1 skipped in 0.07s ============================================================================================================ -``` - -### Writing Tests - -* `tests/lib/checks/beman_standard//test_.py`: The test file for the `` - check. - * e.g., for `check_category = "readme"` the test file is `tests/lib/checks/beman_standard/readme/test_readme.py`. -* `test____()` function inside the test file. - * e.g., for `check_category = "readme"` and `test_case_name = "valid"` the function is `test__README_TITLE__valid()`. - * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the function is - `test__README_TITLE__invalid()`. -* `tests/beman_standard//data/`: The data for the tests (e.g., files, directories, etc.). - * e.g., for `check_category = "readme"` and `test_case_name = "valid"` the data is in - `tests/lib/checks/beman_standard/readme/data/valid/`. - * e.g., for `check_category = "readme"` and `test_case_name = "invalid"` the data is in - `tests/lib/checks/beman_standard/readme/data/invalid/`. - * e.g., for `check_category = "readme"` and `test_case_name = "fix_inplace"` the data may use both `valid` and - `invalid` files. It is recommended to not change these files and use temporary copies having suffix `.delete_me` - (which are not tracked by git). -* Default setup / mocks: - * `repo_info`: The repository information (e.g., path, name, etc.). Mocked with hardcoded values of `beman.exemplar`. - * `beman_standard_check_config`: The Beman Standard configuration file. Actual load of the `.beman-standard.yml` - file. -* Always add at least 3 test cases for each check. - * `valid`: The test case for the valid case. - * `invalid`: The test case for the invalid case. - * `fix_inplace`: The test case for the fix invalid case. If the fix is not (yet) implementable, add a - `@pytest.mark.skip(reason="NOT implemented")` decorator to track the progress. - -## Changing dependencies - -* Add / update the dependency to the `pyproject.toml` file. -* Run `uv clean` to make sure the dependencies are updated. -* Run `uv sync` to update the uv lockfile -* Run `uv export -o pylock.toml` to update `pylock.toml` -* Run `uv build` to build the wheel. -* Run `uv run beman-tidy --help` to check if the new dependency is available. -* Commit the changes from `pyproject.toml`, `pylock.toml` and `uv.lock`. - -## Development Notes - -Requirements: - -* `beman-tidy` must be able to run on Windows, Linux, and macOS, thus it's 100% Python. -* `beman-tidy` must NOT use internet access. A local snapshot of the standard is used (check `.beman-standard.yml`). -* `beman-tidy` must have `verbose` and `non-verbose` modes. Default is `non-verbose`. -* `beman-tidy` must have `dry-run` and `fix-inplace` modes. Default is `dry-run`. -* `beman-tidy` must detect types of checks: failed, passed, skipped (not implemented) and print the summary/coverage. - -Limitations: - -* `2025-06-07`: `beman-tidy` will not support the `--fix-inplace` flag in the first iteration for most of the checks. -* `2025-06-07`: `beman-tidy` may generate small changes to the standard (e.g., for automated fixes), while the standard - is not stable. Thus, the tool itself may be unstable. diff --git a/infra/tools/beman-tidy/pylock.toml b/infra/tools/beman-tidy/pylock.toml deleted file mode 100644 index 8fb1d543..00000000 --- a/infra/tools/beman-tidy/pylock.toml +++ /dev/null @@ -1,124 +0,0 @@ -# This file was autogenerated by uv via the following command: -# uv export -o pylock.toml -lock-version = "1.0" -created-by = "uv" -requires-python = ">=3.12" - -[[packages]] -name = "beman-tidy" -directory = { path = ".", editable = true } - -[[packages]] -name = "colorama" -version = "0.4.6" -marker = "sys_platform == 'win32'" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", upload-time = 2022-10-25T02:36:22Z, size = 27697, hashes = { sha256 = "08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", upload-time = 2022-10-25T02:36:20Z, size = 25335, hashes = { sha256 = "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" } }] - -[[packages]] -name = "gitdb" -version = "4.0.12" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", upload-time = 2025-01-02T07:20:46Z, size = 394684, hashes = { sha256 = "5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", upload-time = 2025-01-02T07:20:43Z, size = 62794, hashes = { sha256 = "67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf" } }] - -[[packages]] -name = "gitpython" -version = "3.1.44" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/c0/89/37df0b71473153574a5cdef8f242de422a0f5d26d7a9e231e6f169b4ad14/gitpython-3.1.44.tar.gz", upload-time = 2025-01-02T07:32:43Z, size = 214196, hashes = { sha256 = "c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269" } } -wheels = [{ name = "gitpython-3.1.44-py3-none-any.whl", url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", upload-time = 2025-01-02T07:32:40Z, size = 207599, hashes = { sha256 = "9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110" } }] - -[[packages]] -name = "iniconfig" -version = "2.1.0" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", upload-time = 2025-03-19T20:09:59Z, size = 4793, hashes = { sha256 = "3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", upload-time = 2025-03-19T20:10:01Z, size = 6050, hashes = { sha256 = "9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" } }] - -[[packages]] -name = "packaging" -version = "25.0" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", upload-time = 2025-04-19T11:48:59Z, size = 165727, hashes = { sha256 = "d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", upload-time = 2025-04-19T11:48:57Z, size = 66469, hashes = { sha256 = "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484" } }] - -[[packages]] -name = "pluggy" -version = "1.6.0" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", upload-time = 2025-05-15T12:30:07Z, size = 69412, hashes = { sha256 = "7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", upload-time = 2025-05-15T12:30:06Z, size = 20538, hashes = { sha256 = "e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" } }] - -[[packages]] -name = "pygments" -version = "2.19.1" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", upload-time = 2025-01-06T17:26:30Z, size = 4968581, hashes = { sha256 = "61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", upload-time = 2025-01-06T17:26:25Z, size = 1225293, hashes = { sha256 = "9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c" } }] - -[[packages]] -name = "pytest" -version = "8.4.0" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/fb/aa/405082ce2749be5398045152251ac69c0f3578c7077efc53431303af97ce/pytest-8.4.0.tar.gz", upload-time = 2025-06-02T17:36:30Z, size = 1515232, hashes = { sha256 = "14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/2f/de/afa024cbe022b1b318a3d224125aa24939e99b4ff6f22e0ba639a2eaee47/pytest-8.4.0-py3-none-any.whl", upload-time = 2025-06-02T17:36:27Z, size = 363797, hashes = { sha256 = "f40f825768ad76c0977cbacdf1fd37c6f7a468e460ea6a0636078f8972d4517e" } }] - -[[packages]] -name = "pyyaml" -version = "6.0.2" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", upload-time = 2024-08-06T20:33:50Z, size = 130631, hashes = { sha256 = "d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e" } } -wheels = [ - { name = "pyyaml-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", upload-time = 2024-08-06T20:32:25Z, size = 183873, hashes = { sha256 = "c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab" } }, - { name = "pyyaml-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", upload-time = 2024-08-06T20:32:26Z, size = 173302, hashes = { sha256 = "ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725" } }, - { name = "pyyaml-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2024-08-06T20:32:28Z, size = 739154, hashes = { sha256 = "1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5" } }, - { name = "pyyaml-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2024-08-06T20:32:30Z, size = 766223, hashes = { sha256 = "9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425" } }, - { name = "pyyaml-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-08-06T20:32:31Z, size = 767542, hashes = { sha256 = "80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476" } }, - { name = "pyyaml-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", upload-time = 2024-08-06T20:32:37Z, size = 731164, hashes = { sha256 = "0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48" } }, - { name = "pyyaml-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", upload-time = 2024-08-06T20:32:38Z, size = 756611, hashes = { sha256 = "8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b" } }, - { name = "pyyaml-6.0.2-cp312-cp312-win32.whl", url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", upload-time = 2024-08-06T20:32:40Z, size = 140591, hashes = { sha256 = "ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4" } }, - { name = "pyyaml-6.0.2-cp312-cp312-win_amd64.whl", url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", upload-time = 2024-08-06T20:32:41Z, size = 156338, hashes = { sha256 = "7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8" } }, - { name = "pyyaml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", upload-time = 2024-08-06T20:32:43Z, size = 181309, hashes = { sha256 = "efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba" } }, - { name = "pyyaml-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", upload-time = 2024-08-06T20:32:44Z, size = 171679, hashes = { sha256 = "50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1" } }, - { name = "pyyaml-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2024-08-06T20:32:46Z, size = 733428, hashes = { sha256 = "0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133" } }, - { name = "pyyaml-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2024-08-06T20:32:51Z, size = 763361, hashes = { sha256 = "17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484" } }, - { name = "pyyaml-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-08-06T20:32:53Z, size = 759523, hashes = { sha256 = "70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5" } }, - { name = "pyyaml-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", upload-time = 2024-08-06T20:32:54Z, size = 726660, hashes = { sha256 = "41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc" } }, - { name = "pyyaml-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", upload-time = 2024-08-06T20:32:56Z, size = 751597, hashes = { sha256 = "68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652" } }, - { name = "pyyaml-6.0.2-cp313-cp313-win32.whl", url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", upload-time = 2024-08-06T20:33:03Z, size = 140527, hashes = { sha256 = "bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183" } }, - { name = "pyyaml-6.0.2-cp313-cp313-win_amd64.whl", url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", upload-time = 2024-08-06T20:33:04Z, size = 156446, hashes = { sha256 = "8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563" } }, -] - -[[packages]] -name = "ruff" -version = "0.11.13" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/ed/da/9c6f995903b4d9474b39da91d2d626659af3ff1eeb43e9ae7c119349dba6/ruff-0.11.13.tar.gz", upload-time = 2025-06-05T21:00:15Z, size = 4282054, hashes = { sha256 = "26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514" } } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/ce/a11d381192966e0b4290842cc8d4fac7dc9214ddf627c11c1afff87da29b/ruff-0.11.13-py3-none-linux_armv6l.whl", upload-time = 2025-06-05T20:59:32Z, size = 10292516, hashes = { sha256 = "4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46" } }, - { url = "https://files.pythonhosted.org/packages/78/db/87c3b59b0d4e753e40b6a3b4a2642dfd1dcaefbff121ddc64d6c8b47ba00/ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", upload-time = 2025-06-05T20:59:37Z, size = 11106083, hashes = { sha256 = "aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48" } }, - { url = "https://files.pythonhosted.org/packages/77/79/d8cec175856ff810a19825d09ce700265f905c643c69f45d2b737e4a470a/ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", upload-time = 2025-06-05T20:59:39Z, size = 10436024, hashes = { sha256 = "53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b" } }, - { url = "https://files.pythonhosted.org/packages/8b/5b/f6d94f2980fa1ee854b41568368a2e1252681b9238ab2895e133d303538f/ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2025-06-05T20:59:42Z, size = 10646324, hashes = { sha256 = "ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a" } }, - { url = "https://files.pythonhosted.org/packages/6c/9c/b4c2acf24ea4426016d511dfdc787f4ce1ceb835f3c5fbdbcb32b1c63bda/ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", upload-time = 2025-06-05T20:59:44Z, size = 10174416, hashes = { sha256 = "6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc" } }, - { url = "https://files.pythonhosted.org/packages/f3/10/e2e62f77c65ede8cd032c2ca39c41f48feabedb6e282bfd6073d81bb671d/ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", upload-time = 2025-06-05T20:59:46Z, size = 11724197, hashes = { sha256 = "1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629" } }, - { url = "https://files.pythonhosted.org/packages/bb/f0/466fe8469b85c561e081d798c45f8a1d21e0b4a5ef795a1d7f1a9a9ec182/ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", upload-time = 2025-06-05T20:59:49Z, size = 12511615, hashes = { sha256 = "d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933" } }, - { url = "https://files.pythonhosted.org/packages/17/0e/cefe778b46dbd0cbcb03a839946c8f80a06f7968eb298aa4d1a4293f3448/ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", upload-time = 2025-06-05T20:59:51Z, size = 12117080, hashes = { sha256 = "55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165" } }, - { url = "https://files.pythonhosted.org/packages/5d/2c/caaeda564cbe103bed145ea557cb86795b18651b0f6b3ff6a10e84e5a33f/ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2025-06-05T20:59:54Z, size = 11326315, hashes = { sha256 = "633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71" } }, - { url = "https://files.pythonhosted.org/packages/75/f0/782e7d681d660eda8c536962920c41309e6dd4ebcea9a2714ed5127d44bd/ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2025-06-05T20:59:56Z, size = 11555640, hashes = { sha256 = "4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9" } }, - { url = "https://files.pythonhosted.org/packages/5d/d4/3d580c616316c7f07fb3c99dbecfe01fbaea7b6fd9a82b801e72e5de742a/ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", upload-time = 2025-06-05T20:59:59Z, size = 10507364, hashes = { sha256 = "4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc" } }, - { url = "https://files.pythonhosted.org/packages/5a/dc/195e6f17d7b3ea6b12dc4f3e9de575db7983db187c378d44606e5d503319/ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", upload-time = 2025-06-05T21:00:01Z, size = 10141462, hashes = { sha256 = "d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7" } }, - { url = "https://files.pythonhosted.org/packages/f4/8e/39a094af6967faa57ecdeacb91bedfb232474ff8c3d20f16a5514e6b3534/ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", upload-time = 2025-06-05T21:00:04Z, size = 11121028, hashes = { sha256 = "26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432" } }, - { url = "https://files.pythonhosted.org/packages/5a/c0/b0b508193b0e8a1654ec683ebab18d309861f8bd64e3a2f9648b80d392cb/ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", upload-time = 2025-06-05T21:00:06Z, size = 11602992, hashes = { sha256 = "51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492" } }, - { url = "https://files.pythonhosted.org/packages/7c/91/263e33ab93ab09ca06ce4f8f8547a858cc198072f873ebc9be7466790bae/ruff-0.11.13-py3-none-win32.whl", upload-time = 2025-06-05T21:00:08Z, size = 10474944, hashes = { sha256 = "96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250" } }, - { url = "https://files.pythonhosted.org/packages/46/f4/7c27734ac2073aae8efb0119cae6931b6fb48017adf048fdf85c19337afc/ruff-0.11.13-py3-none-win_amd64.whl", upload-time = 2025-06-05T21:00:11Z, size = 11548669, hashes = { sha256 = "29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3" } }, - { url = "https://files.pythonhosted.org/packages/ec/bf/b273dd11673fed8a6bd46032c0ea2a04b2ac9bfa9c628756a5856ba113b0/ruff-0.11.13-py3-none-win_arm64.whl", upload-time = 2025-06-05T21:00:13Z, size = 10683928, hashes = { sha256 = "b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b" } }, -] - -[[packages]] -name = "smmap" -version = "5.0.2" -index = "https://pypi.org/simple" -sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", upload-time = 2025-01-02T07:14:40Z, size = 22329, hashes = { sha256 = "26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5" } } -wheels = [{ url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", upload-time = 2025-01-02T07:14:38Z, size = 24303, hashes = { sha256 = "b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e" } }] diff --git a/infra/tools/beman-tidy/pyproject.toml b/infra/tools/beman-tidy/pyproject.toml deleted file mode 100644 index fdc1d372..00000000 --- a/infra/tools/beman-tidy/pyproject.toml +++ /dev/null @@ -1,22 +0,0 @@ -[project] -name = "beman-tidy" -version = "0.1.0" -description = "The Codebase Bemanification Tool" -readme = "README.md" -requires-python = ">=3.12" -authors = [{ name = "Darius Neațu", email = "neatudarius@gmail.com" }] -maintainers = [{ name = "Rishyak", email = "hello@rishyak.com" }] -dependencies = ["gitpython==3.1.44", "pyyaml==6.0.2"] - -[build-system] -requires = ["flit_core >=3.2,<4"] -build-backend = "flit_core.buildapi" - -[dependency-groups] -dev = ["pytest>=8.4.0", "ruff>=0.11.13"] - -[project.scripts] -beman-tidy = "beman_tidy.cli:main" - -[tool.pytest.ini_options] -addopts = "-v" diff --git a/infra/tools/beman-tidy/tests/__init__.py b/infra/tools/beman-tidy/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/tests/conftest.py b/infra/tools/beman-tidy/tests/conftest.py deleted file mode 100644 index 430a7be8..00000000 --- a/infra/tools/beman-tidy/tests/conftest.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import pytest -import os -from pathlib import Path - - -def pytest_configure(config): - """ - Add custom markers to pytest. - """ - config.addinivalue_line( - "markers", "use_test_repo: mark test to use test repository instead of exemplar" - ) - - -@pytest.fixture(autouse=True) -def _setup_test_environment(): - """ - Setup test environment variables and paths. - This runs automatically for all tests. - """ - # Get the root directory of the project - root_dir = Path(__file__).parent.parent - - # Add the project root to PYTHONPATH if not already there - if str(root_dir) not in os.environ.get("PYTHONPATH", ""): - os.environ["PYTHONPATH"] = f"{root_dir}:{os.environ.get('PYTHONPATH', '')}" - - yield diff --git a/infra/tools/beman-tidy/tests/lib/__init__.py b/infra/tools/beman-tidy/tests/lib/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/tests/lib/checks/__init__.py b/infra/tools/beman-tidy/tests/lib/checks/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/__init__.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/__init__.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py deleted file mode 100644 index 515dc2bd..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/conftest.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import pytest - -from tests.utils.conftest import mock_repo_info, mock_beman_standard_check_config # noqa: F401 - - -@pytest.fixture(autouse=True) -def repo_info(mock_repo_info): # noqa: F811 - return mock_repo_info - - -@pytest.fixture -def beman_standard_check_config(mock_beman_standard_check_config): # noqa: F811 - return mock_beman_standard_check_config diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md deleted file mode 100644 index 5be8ed82..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v1.md +++ /dev/null @@ -1,16 +0,0 @@ -# beman.exemplar: A Beman Library Exemplar - - - - -![Library typo Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - - -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) - -This is NOT a valid README.md according to the Beman Standard: typos in badges. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md deleted file mode 100644 index 4aa668e9..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v2.md +++ /dev/null @@ -1,15 +0,0 @@ -# beman.exemplar: A Beman Library Exemplar - - - - -![Other display text](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) - -This is NOT a valid README.md according to the Beman Standard: invalid badge display text. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md deleted file mode 100644 index ffc08c34..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-badge-v3.md +++ /dev/null @@ -1,15 +0,0 @@ -# beman.exemplar: A Beman Library Exemplar - - - - -![Library Status](https://raw.githubusercontent.com/mylogo) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) - -This is NOT a valid README.md according to the Beman Standard: invalid badge URL. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md deleted file mode 100644 index bdef5791..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v1.md +++ /dev/null @@ -1,15 +0,0 @@ -# beman.exemplar: A Beman Library Exemplar - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: Under development and not yet ready for production use. - -This is NOT a valid README.md according to the Beman Standard: the library status is not properly formatted. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md deleted file mode 100644 index a4da50fc..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v2.md +++ /dev/null @@ -1,16 +0,0 @@ -# beman.exemplar: A Beman Library Exemplar - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - - -**Status**: [under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md# TYPO HERE under-development-and-not-yet-ready-for-production-use) - -This is NOT a valid README.md according to the Beman Standard: the library status line has typos. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md deleted file mode 100644 index 8d5e2bdd..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-status-line-v3.md +++ /dev/null @@ -1,18 +0,0 @@ -# beman.exemplar: A Beman Library Exemplar - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use), -**Status**: [Production ready. API may undergo changes.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-api-may-undergo-changes), -**Status**: [Production ready. Stable API.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-stable-api), -**Status**: [Retired. No longer maintained or actively developed.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#retired-no-longer-maintained-or-actively-developed), - -This is NOT a valid README.md according to the Beman Standard: the library status is duplicated. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md deleted file mode 100644 index 7f91a7a3..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v1.md +++ /dev/null @@ -1,15 +0,0 @@ -# beman exemplar: A Beman Library Exemplar - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) - -This is NOT a valid README.md according to the Beman Standard: missing beman.exemplar. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md deleted file mode 100644 index e92b46f4..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v2.md +++ /dev/null @@ -1,15 +0,0 @@ -# beman.exemplar A Beman Library Exemplar - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) - -This is NOT a valid README.md according to the Beman Standard: missing : diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md deleted file mode 100644 index 6ae059f0..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v3.md +++ /dev/null @@ -1,16 +0,0 @@ -# beman.optional: C++26 Optional Library - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - - -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) - -This is NOT a valid README.md according to the Beman Standard: wrong library name. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md deleted file mode 100644 index eea29e4b..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid-title-v4.md +++ /dev/null @@ -1,15 +0,0 @@ -# beman.optional: C++26 Optional Library - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) - -This is NOT a valid README.md according to the Beman Standard: wrong library name. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid.md deleted file mode 100644 index 7048d188..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/invalid/invalid.md +++ /dev/null @@ -1,11 +0,0 @@ -# Wrong Title Format - -This is an invalid README.md file that doesn't follow the Beman Standard: the title doesn't have the correct format. - -This is an invalid README.md file that doesn't follow the Beman Standard: the badges are missing. - -This is an invalid README.md file that doesn't follow the Beman Standard: the purpose is missing. - -This is an invalid README.md file that doesn't follow the Beman Standard: the library status is missing. - -This is an invalid README.md file that doesn't follow the Beman Standard: the license is missing. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md deleted file mode 100644 index 403859dd..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v1.md +++ /dev/null @@ -1,26 +0,0 @@ -# beman.exemplar: A Beman Library Exemplar - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) - - -This is a valid README.md file that follows the Beman Standard: the title is properly formatted with the library name and a short description. - -This is a valid README.md file that follows the Beman Standard: the badges are properly formatted. - -This is a valid README.md file that follows the Beman Standard: the purpose is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the implements is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the library status is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the license is properly formatted. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md deleted file mode 100644 index 56e5a729..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v2.md +++ /dev/null @@ -1,26 +0,0 @@ -# beman.exemplar: Another Beman Library - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: [Production ready. API may undergo changes.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-api-may-undergo-changes) - - -This is a valid README.md file that follows the Beman Standard: the title is properly formatted with the library name and a short description. - -This is a valid README.md file that follows the Beman Standard: the badges are properly formatted. - -This is a valid README.md file that follows the Beman Standard: the purpose is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the implements is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the library status is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the license is properly formatted. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md deleted file mode 100644 index dbfbacee..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v3.md +++ /dev/null @@ -1,27 +0,0 @@ -# beman.exemplar: Awesome Beman Library - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - - -**Status**: [Production ready. Stable API.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#production-ready-stable-api) - - -This is a valid README.md file that follows the Beman Standard: the title is properly formatted with the library name and a short description. - -This is a valid README.md file that follows the Beman Standard: the badges are properly formatted. - -This is a valid README.md file that follows the Beman Standard: the purpose is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the implements is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the library status is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the license is properly formatted. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md deleted file mode 100644 index c33c6037..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/data/valid/README-v4.md +++ /dev/null @@ -1,26 +0,0 @@ -# beman.exemplar: The Most Awesome Beman Library - - - - -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/exemplar/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/exemplar/actions/workflows/pre-commit.yml/badge.svg) - - -`beman.exemplar` is a minimal C++ library conforming to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_STANDARD.md). This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure. - -**Implements**: `std::identity` proposed in [Standard Library Concepts (P0898R3)](https://wg21.link/P0898R3). - -**Status**: [Retired. No longer maintained or actively developed.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#retired-no-longer-maintained-or-actively-developed) - - -This is a valid README.md file that follows the Beman Standard: the title is properly formatted with the library name and a short description. - -This is a valid README.md file that follows the Beman Standard: the badges are properly formatted. - -This is a valid README.md file that follows the Beman Standard: the purpose is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the implements is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the library status is properly formatted. - -This is a valid README.md file that follows the Beman Standard: the license is properly formatted. diff --git a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py b/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py deleted file mode 100644 index 87df91ee..00000000 --- a/infra/tools/beman-tidy/tests/lib/checks/beman_standard/readme/test_readme.py +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import pytest -from pathlib import Path - -from tests.utils.path_runners import ( - run_check_for_each_path, - run_fix_inplace_for_each_file_path, -) - -# Actual tested checks. -from beman_tidy.lib.checks.beman_standard.readme import ( - ReadmeTitleCheck, - ReadmeBadgesCheck, - ReadmeImplementsCheck, - ReadmeLibraryStatusCheck, -) - -test_data_prefix = "tests/lib/checks/beman_standard/readme/data" -valid_prefix = f"{test_data_prefix}/valid" -invalid_prefix = f"{test_data_prefix}/invalid" - - -def test__README_TITLE__valid(repo_info, beman_standard_check_config): - """ - Test that a valid README.md title passes the check. - """ - valid_readme_paths = [ - # Title: # beman.exemplar: A Beman Library Exemplar - Path(f"{valid_prefix}/README-v1.md"), - # Title: # beman.exemplar: Another Beman Library - Path(f"{valid_prefix}/README-v2.md"), - # Title: # beman.exemplar: Awesome Beman Library - Path(f"{valid_prefix}/README-v3.md"), - # Title: # beman.exemplar: The Most Awesome Beman Library - Path(f"{valid_prefix}/README-v4.md"), - ] - - run_check_for_each_path( - True, - valid_readme_paths, - ReadmeTitleCheck, - repo_info, - beman_standard_check_config, - ) - - -def test__README_TITLE__invalid(repo_info, beman_standard_check_config): - """ - Test that an invalid README.md title fails the check. - """ - invalid_readme_paths = [ - Path(f"{invalid_prefix}/invalid.md"), - Path(f"{invalid_prefix}/invalid-title-v1.md"), - Path(f"{invalid_prefix}/invalid-title-v2.md"), - Path(f"{invalid_prefix}/invalid-title-v3.md"), - Path(f"{invalid_prefix}/invalid-title-v4.md"), - ] - - run_check_for_each_path( - False, - invalid_readme_paths, - ReadmeTitleCheck, - repo_info, - beman_standard_check_config, - ) - - -def test__README_TITLE__fix_inplace(repo_info, beman_standard_check_config): - """ - Test that the fix method corrects an invalid README.md title. - """ - invalid_readme_paths = [ - Path(f"{invalid_prefix}/invalid-title-v1.md"), - Path(f"{invalid_prefix}/invalid-title-v2.md"), - Path(f"{invalid_prefix}/invalid-title-v3.md"), - Path(f"{invalid_prefix}/invalid-title-v4.md"), - ] - - run_fix_inplace_for_each_file_path( - invalid_readme_paths, ReadmeTitleCheck, repo_info, beman_standard_check_config - ) - - -def test__README_BADGES__valid(repo_info, beman_standard_check_config): - """ - Test that a valid README.md badges passes the check. - """ - valid_readme_paths = [ - Path(f"{valid_prefix}/README-v1.md"), - Path(f"{valid_prefix}/README-v2.md"), - Path(f"{valid_prefix}/README-v3.md"), - Path(f"{valid_prefix}/README-v4.md"), - ] - - run_check_for_each_path( - True, - valid_readme_paths, - ReadmeBadgesCheck, - repo_info, - beman_standard_check_config, - ) - - -def test__README_BADGES__invalid(repo_info, beman_standard_check_config): - """ - Test that an invalid README.md badges fails the check. - """ - invalid_readme_paths = [ - Path(f"{invalid_prefix}/invalid.md"), - Path(f"{invalid_prefix}/invalid-badge-v1.md"), - Path(f"{invalid_prefix}/invalid-badge-v2.md"), - Path(f"{invalid_prefix}/invalid-badge-v3.md"), - ] - - run_check_for_each_path( - False, - invalid_readme_paths, - ReadmeBadgesCheck, - repo_info, - beman_standard_check_config, - ) - - -@pytest.mark.skip(reason="NOT implemented") -def test__README_BADGES__fix_inplace(repo_info, beman_standard_check_config): - """ - Test that the fix method corrects an invalid README.md badges. - """ - pass - - -def test__README_IMPLEMENTS__valid(repo_info, beman_standard_check_config): - """ - Test that a valid README.md "Implements" passes the check - """ - valid_readme_paths = [ - Path(f"{valid_prefix}/README-v1.md"), - Path(f"{valid_prefix}/README-v2.md"), - Path(f"{valid_prefix}/README-v3.md"), - Path(f"{valid_prefix}/README-v4.md"), - ] - - run_check_for_each_path( - True, - valid_readme_paths, - ReadmeImplementsCheck, - repo_info, - beman_standard_check_config, - ) - - -def test__README_IMPLEMENTS__invalid(repo_info, beman_standard_check_config): - """ - Test that an invalid README.md "Implements" fails the check - """ - invalid_readme_paths = [ - Path(f"{invalid_prefix}/invalid.md"), - Path(f"{invalid_prefix}/invalid-implements-v1.md"), - Path(f"{invalid_prefix}/invalid-implements-v2.md"), - Path(f"{invalid_prefix}/invalid-implements-v3.md"), - Path(f"{invalid_prefix}/invalid-implements-v4.md"), - ] - - run_check_for_each_path( - False, - invalid_readme_paths, - ReadmeImplementsCheck, - repo_info, - beman_standard_check_config, - ) - - -@pytest.mark.skip(reason="NOT implemented") -def test__README_IMPLEMENTS__fix_inplace(repo_info, beman_standard_check_config): - """ - Test that the fix method corrects an invalid README.md "Implements" - """ - pass - - -def test__README_LIBRARY_STATUS__valid(repo_info, beman_standard_check_config): - """ - Test that a valid README.md library status passes the check. - """ - valid_readme_paths = [ - Path(f"{valid_prefix}/README-v1.md"), - Path(f"{valid_prefix}/README-v2.md"), - Path(f"{valid_prefix}/README-v3.md"), - Path(f"{valid_prefix}/README-v4.md"), - ] - - run_check_for_each_path( - True, - valid_readme_paths, - ReadmeLibraryStatusCheck, - repo_info, - beman_standard_check_config, - ) - - -def test__README_LIBRARY_STATUS__invalid(repo_info, beman_standard_check_config): - """ - Test that an invalid README.md library status fails the check. - """ - invalid_readme_paths = [ - Path(f"{invalid_prefix}/invalid.md"), - Path(f"{invalid_prefix}/invalid-status-line-v1.md"), - Path(f"{invalid_prefix}/invalid-status-line-v2.md"), - Path(f"{invalid_prefix}/invalid-status-line-v3.md"), - ] - - run_check_for_each_path( - False, - invalid_readme_paths, - ReadmeLibraryStatusCheck, - repo_info, - beman_standard_check_config, - ) - - -@pytest.mark.skip(reason="NOT implemented") -def test__README_LIBRARY_STATUS__fix_inplace(repo_info, beman_standard_check_config): - """ - Test that the fix method corrects an invalid README.md library status. - """ - pass diff --git a/infra/tools/beman-tidy/tests/utils/__init__.py b/infra/tools/beman-tidy/tests/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/infra/tools/beman-tidy/tests/utils/conftest.py b/infra/tools/beman-tidy/tests/utils/conftest.py deleted file mode 100644 index 71d82c06..00000000 --- a/infra/tools/beman-tidy/tests/utils/conftest.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import pytest -from beman_tidy.lib.utils.git import load_beman_standard_config - - -@pytest.fixture -def mock_repo_info(): - """Return repository information for beman.exemplar library""" - return { - "top_level": ".", - "name": "exemplar", - "remote_url": "https://github.com/bemanproject/exemplar", - "current_branch": "main", - "commit_hash": 0, - "status": "", - "unstaged_changes": "", - } - - -@pytest.fixture -def mock_beman_standard_check_config(): - """Parse the Beman Standard YAML file and return a dictionary of check configurations""" - - return load_beman_standard_config() diff --git a/infra/tools/beman-tidy/tests/utils/path_runners.py b/infra/tools/beman-tidy/tests/utils/path_runners.py deleted file mode 100644 index e7b09ec0..00000000 --- a/infra/tools/beman-tidy/tests/utils/path_runners.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -import os -from pathlib import Path - - -def run_check_for_each_path( - expected_result, paths, check_class, repo_info, beman_standard_check_config -): - """ - Run path-based check (check_class) for each given path: evaluate check_class(paths[i]). - - Example: - expected_result = True / False - paths = [ - "tests/lib/checks/beman_standard/readme/data/valid/README-v1.md", - "tests/lib/checks/beman_standard/readme/data/valid/README-v2.md", - ] - check_class = ReadmeTitleCheck or DirectorySourcesCheck - repo_info = "beman.exemplar" - beman_standard_check_config = "/path/to/.beman-standard.yml" - """ - for path in paths: - check_instance = check_class(repo_info, beman_standard_check_config) - check_instance.path = Path(path) - check_instance.log_level = True - - assert check_instance.pre_check() is True, ( - f"[{check_instance.__class__.__name__}] pre_check() failed for {path}" - ) - assert check_instance.check() is expected_result, ( - f"[{check_instance.__class__.__name__}] check() failed for {path}" - ) - - -def run_fix_inplace_for_each_file_path( - invalid_file_paths, check_class, repo_info, beman_standard_check_config -): - """ - Run multiple testcases for a file-based check, for each file starting with a file that is invalid, - and then fixing it. - - Example: - invalid_file_paths = [ - "tests/lib/checks/beman_standard/readme/data/invalid/README-v1.md", - "tests/lib/checks/beman_standard/readme/data/invalid/README-v2.md", - ] - check_class = ReadmeTitleCheck - repo_info = "beman.exemplar" - beman_standard_check_config = "beman_tidy/.beman-standard.yml" - """ - for invalid_path in invalid_file_paths: - check_instance = check_class(repo_info, beman_standard_check_config) - check_instance.path = Path(f"{invalid_path}.delete_me") - check_instance.write(invalid_path.read_text()) - - assert check_instance.pre_check() is True - assert check_instance.check() is False - - assert check_instance.fix() is True - - assert check_instance.pre_check() is True - assert check_instance.check() is True - - # Delete the temporary file - os.remove(f"{invalid_path}.delete_me") - - -def run_fix_inplace_for_each_directory_path( - invalid_directory_paths, check_class, repo_info, beman_standard_check_config -): - # TODO: We may not provide a fix_inplace method for directory-based checks. - pass diff --git a/infra/tools/beman-tidy/uv.lock b/infra/tools/beman-tidy/uv.lock deleted file mode 100644 index da07ff4a..00000000 --- a/infra/tools/beman-tidy/uv.lock +++ /dev/null @@ -1,175 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.12" - -[[package]] -name = "beman-tidy" -version = "0.1.0" -source = { editable = "." } -dependencies = [ - { name = "gitpython" }, - { name = "pyyaml" }, -] - -[package.dev-dependencies] -dev = [ - { name = "pytest" }, - { name = "ruff" }, -] - -[package.metadata] -requires-dist = [ - { name = "gitpython", specifier = "==3.1.44" }, - { name = "pyyaml", specifier = "==6.0.2" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.4.0" }, - { name = "ruff", specifier = ">=0.11.13" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "gitdb" -version = "4.0.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "smmap" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, -] - -[[package]] -name = "gitpython" -version = "3.1.44" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "gitdb" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/89/37df0b71473153574a5cdef8f242de422a0f5d26d7a9e231e6f169b4ad14/gitpython-3.1.44.tar.gz", hash = "sha256:c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269", size = 214196, upload-time = "2025-01-02T07:32:43.59Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110", size = 207599, upload-time = "2025-01-02T07:32:40.731Z" }, -] - -[[package]] -name = "iniconfig" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, -] - -[[package]] -name = "packaging" -version = "25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, -] - -[[package]] -name = "pluggy" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - -[[package]] -name = "pytest" -version = "8.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fb/aa/405082ce2749be5398045152251ac69c0f3578c7077efc53431303af97ce/pytest-8.4.0.tar.gz", hash = "sha256:14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6", size = 1515232, upload-time = "2025-06-02T17:36:30.03Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/de/afa024cbe022b1b318a3d224125aa24939e99b4ff6f22e0ba639a2eaee47/pytest-8.4.0-py3-none-any.whl", hash = "sha256:f40f825768ad76c0977cbacdf1fd37c6f7a468e460ea6a0636078f8972d4517e", size = 363797, upload-time = "2025-06-02T17:36:27.859Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "ruff" -version = "0.11.13" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ed/da/9c6f995903b4d9474b39da91d2d626659af3ff1eeb43e9ae7c119349dba6/ruff-0.11.13.tar.gz", hash = "sha256:26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514", size = 4282054, upload-time = "2025-06-05T21:00:15.721Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/ce/a11d381192966e0b4290842cc8d4fac7dc9214ddf627c11c1afff87da29b/ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46", size = 10292516, upload-time = "2025-06-05T20:59:32.944Z" }, - { url = "https://files.pythonhosted.org/packages/78/db/87c3b59b0d4e753e40b6a3b4a2642dfd1dcaefbff121ddc64d6c8b47ba00/ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48", size = 11106083, upload-time = "2025-06-05T20:59:37.03Z" }, - { url = "https://files.pythonhosted.org/packages/77/79/d8cec175856ff810a19825d09ce700265f905c643c69f45d2b737e4a470a/ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b", size = 10436024, upload-time = "2025-06-05T20:59:39.741Z" }, - { url = "https://files.pythonhosted.org/packages/8b/5b/f6d94f2980fa1ee854b41568368a2e1252681b9238ab2895e133d303538f/ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a", size = 10646324, upload-time = "2025-06-05T20:59:42.185Z" }, - { url = "https://files.pythonhosted.org/packages/6c/9c/b4c2acf24ea4426016d511dfdc787f4ce1ceb835f3c5fbdbcb32b1c63bda/ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc", size = 10174416, upload-time = "2025-06-05T20:59:44.319Z" }, - { url = "https://files.pythonhosted.org/packages/f3/10/e2e62f77c65ede8cd032c2ca39c41f48feabedb6e282bfd6073d81bb671d/ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629", size = 11724197, upload-time = "2025-06-05T20:59:46.935Z" }, - { url = "https://files.pythonhosted.org/packages/bb/f0/466fe8469b85c561e081d798c45f8a1d21e0b4a5ef795a1d7f1a9a9ec182/ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933", size = 12511615, upload-time = "2025-06-05T20:59:49.534Z" }, - { url = "https://files.pythonhosted.org/packages/17/0e/cefe778b46dbd0cbcb03a839946c8f80a06f7968eb298aa4d1a4293f3448/ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165", size = 12117080, upload-time = "2025-06-05T20:59:51.654Z" }, - { url = "https://files.pythonhosted.org/packages/5d/2c/caaeda564cbe103bed145ea557cb86795b18651b0f6b3ff6a10e84e5a33f/ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71", size = 11326315, upload-time = "2025-06-05T20:59:54.469Z" }, - { url = "https://files.pythonhosted.org/packages/75/f0/782e7d681d660eda8c536962920c41309e6dd4ebcea9a2714ed5127d44bd/ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9", size = 11555640, upload-time = "2025-06-05T20:59:56.986Z" }, - { url = "https://files.pythonhosted.org/packages/5d/d4/3d580c616316c7f07fb3c99dbecfe01fbaea7b6fd9a82b801e72e5de742a/ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc", size = 10507364, upload-time = "2025-06-05T20:59:59.154Z" }, - { url = "https://files.pythonhosted.org/packages/5a/dc/195e6f17d7b3ea6b12dc4f3e9de575db7983db187c378d44606e5d503319/ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7", size = 10141462, upload-time = "2025-06-05T21:00:01.481Z" }, - { url = "https://files.pythonhosted.org/packages/f4/8e/39a094af6967faa57ecdeacb91bedfb232474ff8c3d20f16a5514e6b3534/ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432", size = 11121028, upload-time = "2025-06-05T21:00:04.06Z" }, - { url = "https://files.pythonhosted.org/packages/5a/c0/b0b508193b0e8a1654ec683ebab18d309861f8bd64e3a2f9648b80d392cb/ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492", size = 11602992, upload-time = "2025-06-05T21:00:06.249Z" }, - { url = "https://files.pythonhosted.org/packages/7c/91/263e33ab93ab09ca06ce4f8f8547a858cc198072f873ebc9be7466790bae/ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250", size = 10474944, upload-time = "2025-06-05T21:00:08.459Z" }, - { url = "https://files.pythonhosted.org/packages/46/f4/7c27734ac2073aae8efb0119cae6931b6fb48017adf048fdf85c19337afc/ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3", size = 11548669, upload-time = "2025-06-05T21:00:11.147Z" }, - { url = "https://files.pythonhosted.org/packages/ec/bf/b273dd11673fed8a6bd46032c0ea2a04b2ac9bfa9c628756a5856ba113b0/ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b", size = 10683928, upload-time = "2025-06-05T21:00:13.758Z" }, -] - -[[package]] -name = "smmap" -version = "5.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, -]