diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000..b98fc09 --- /dev/null +++ b/.bazelrc @@ -0,0 +1 @@ +test --test_output=errors diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 0000000..ba7f754 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +7.4.0 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..0da4dea --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,6 @@ +# Comment out as not in score yet +# * @eclipse-score/automotive-score-committers +# .github @eclipse-score/automotive-score-committers + +# docs @eclipse-score/automotive-score-committers + diff --git a/.github/ISSUE_TEMPLATE/bug_fix.md b/.github/ISSUE_TEMPLATE/bug_fix.md new file mode 100644 index 0000000..43ba081 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_fix.md @@ -0,0 +1,13 @@ +--- +name: Bugfix +about: 'Issue to track a bugfix' +title: 'Bugfix: Your bugfix title' +labels: 'codeowner_review' +assignees: '' + +--- + +> [!IMPORTANT] +> Make sure to link this issue with the PR for your bugfix. + + diff --git a/.github/ISSUE_TEMPLATE/improvement.md b/.github/ISSUE_TEMPLATE/improvement.md new file mode 100644 index 0000000..fd2c171 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/improvement.md @@ -0,0 +1,11 @@ +--- +name: Improvement +about: 'Issue to track a improvement' +title: 'Improvement: Your improvement title' +labels: 'codeowner_review' +assignees: '' + +--- + +> [!IMPORTANT] +> Make sure to link this issue with the PR for your improvement. diff --git a/.github/PULL_REQUEST_TEMPLATE/bug_fix.md b/.github/PULL_REQUEST_TEMPLATE/bug_fix.md new file mode 100644 index 0000000..8341f51 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/bug_fix.md @@ -0,0 +1,19 @@ +# Bugfix + +> [!IMPORTANT] +> Use this template only for bugfixes that do not influence topics covered by contribution requests or improvements. + +> [!CAUTION] +> Make sure to submit your pull-request as **Draft** until you are ready to have it reviewed by the Committers. + +## Description + +[A short description of the bug being fixed by the contribution.] + +## Related ticket + +> [!IMPORTANT] +> Please replace `[ISSUE-NUMBER]` with the issue-number that tracks this bug fix. If there is no such +> ticket yet, create one via [this issue template](../ISSUE_TEMPLATE/new?template=bug_fix.md). + +closes [ISSUE-NUMBER] (bugfix ticket) diff --git a/.github/PULL_REQUEST_TEMPLATE/improvement.md b/.github/PULL_REQUEST_TEMPLATE/improvement.md new file mode 100644 index 0000000..090ad43 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/improvement.md @@ -0,0 +1,19 @@ +# Improvement + +> [!IMPORTANT] +> Use this template only for improvement that do not influence topics covered by contribution requests or bug fixes. + +> [!CAUTION] +> Make sure to submit your pull-request as **Draft** until you are ready to have it reviewed by the Committers. + +## Description + +[A short description of the improvement being addressed by the contribution.] + +## Related ticket + +> [!IMPORTANT] +> Please replace `[ISSUE-NUMBER]` with the issue-number that tracks this bug fix. If there is no such +> ticket yet, create one via [this issue template](../ISSUE_TEMPLATE/new?template=improvement.md). + +closes [ISSUE-NUMBER] (improvement ticket) diff --git a/.github/actions/gitlint/action.yml b/.github/actions/gitlint/action.yml new file mode 100644 index 0000000..d1a190c --- /dev/null +++ b/.github/actions/gitlint/action.yml @@ -0,0 +1,21 @@ +name: "Gitlint Action" +description: "An action to install and run Gitlint on PR commits" +inputs: + pr-number: + description: "Pull Request number used to fetch commits" + required: true + base-branch: + description: "Base branch to compare commits against (default: origin/main)" + default: "origin/main" + required: false +runs: + using: "docker" + image: "jorisroovers/gitlint:0.19.1" + entrypoint: /bin/sh + args: + - -c + - | + git config --global --add safe.directory /github/workspace && \ + git fetch origin +refs/heads/main:refs/remotes/origin/main && \ + git fetch origin +refs/pull/${{ inputs.pr-number }}/head && \ + gitlint --commits origin/main..HEAD diff --git a/.github/workflows/copyright.yml b/.github/workflows/copyright.yml new file mode 100644 index 0000000..4315b26 --- /dev/null +++ b/.github/workflows/copyright.yml @@ -0,0 +1,17 @@ +name: Copyright checks +on: + pull_request: + types: [opened, reopened, synchronize] + merge_group: + types: [checks_requested] +jobs: + copyright-check: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.2 + - name: Setup Bazel + uses: bazel-contrib/setup-bazel@0.9.1 + - name: Run copyright checks + run: | + bazel run //:copyright.check diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..2959f5d --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,60 @@ +name: Documentation build +on: + pull_request: + types: [opened, reopened, synchronize] + push: + branches: + - main + merge_group: + types: [checks_requested] +jobs: + docs-build: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.2 + - name: Setup Bazel + uses: bazel-contrib/setup-bazel@0.9.1 + - name: Build documentation + run: | + bazel build //docs:github-pages && cp bazel-bin/docs/github-pages.tar . + - name: Upload artifact for deployment + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: actions/upload-artifact@v4.4.0 + with: + name: github-pages + path: ${{ github.workspace }}/github-pages.tar + retention-days: 1 + if-no-files-found: error + - name: Upload artifact for pull request link + if: github.event_name == 'pull_request' + id: upload-artifact-pr + uses: actions/upload-artifact@v4.4.0 + with: + name: github-pages-${{ github.sha }} + path: ${{ github.workspace }}/github-pages.tar + retention-days: 1 + if-no-files-found: error + - name: Comment artifact URL + if: github.event_name == 'pull_request' + run: | + gh pr comment ${{ github.event.pull_request.number }} \ + --body "Documentation artifact: ${{ steps.upload-artifact-pr.outputs.artifact-url }}" + env: + GH_TOKEN: ${{ github.token }} + docs-deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + permissions: + pages: write + id-token: write + runs-on: ubuntu-latest + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: docs-build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4.0.5 diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000..6cf2b38 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,17 @@ +name: Formatting checks +on: + pull_request: + types: [opened, reopened, synchronize] + merge_group: + types: [checks_requested] +jobs: + formatting-check: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.2 + - name: Setup Bazel + uses: bazel-contrib/setup-bazel@0.9.1 + - name: Run formatting checks + run: | + bazel test //:format.check diff --git a/.github/workflows/gitlint.yml b/.github/workflows/gitlint.yml new file mode 100644 index 0000000..ae7d067 --- /dev/null +++ b/.github/workflows/gitlint.yml @@ -0,0 +1,19 @@ +name: Gitlint check +on: + pull_request: + types: [opened, synchronize, reopened] +jobs: + lint-commits: + name: check-commit-messages + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Run Gitlint Action + if: ${{ github.event_name == 'pull_request' }} + uses: ./.github/actions/gitlint + with: + pr-number: ${{ github.event.number }} + base-branch: ${{ github.event.pull_request.base.ref }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6c272ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Bazel +bazel-* +MODULE.bazel.lock + +# Ruff +.ruff_cache diff --git a/.gitlint b/.gitlint new file mode 100644 index 0000000..53a3c5c --- /dev/null +++ b/.gitlint @@ -0,0 +1,42 @@ +# Available rules: +# +# T1: title-max-length +# T2: title-trailing-whitespace +# T3: title-trailing-punctuation (disabled) +# T4: title-hard-tab +# T5: title-must-not-contain-word (disabled) +# T6: title-leading-whitespace +# T7: title-match-regex (disabled) +# B1: body-max-line-length +# B2: body-trailing-whitespace +# B3: body-hard-tab +# B4: body-first-line-empty +# B5: body-min-length (disabled) +# B6: body-is-missing (disabled) +# B7: body-changed-file-mention (disabled) +# +# See http://jorisroovers.github.io/gitlint/rules/ for a full description. + +# Ignore some default rules and enable regex style searching +[general] +ignore=T3,T5,B1,B5,B7 +regex-style-search=true + +# Maximum length of the title +[title-max-length] +line-length=72 + +[title-match-regex] +regex=^[a-z_-]+: .+$ + +# First line of the commit message body must be empty. (second line of the commit message) +[body-first-line-empty] + +# Body must contain a reference to an issue +# 'see' will act as a form of reference from commits to issues without closing them. +[body-match-regex] +regex=Issue-ref: (see|close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #(\d+) + +#Ignores the title if it starts with Revert or Merge +[ignore-by-title] +regex=(^Revert |^Merge ) diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..946c504 --- /dev/null +++ b/BUILD @@ -0,0 +1,48 @@ +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +test_suite( + name = "format.check", + tests = ["//tools/format:format.check"], +) + +alias( + name = "format.fix", + actual = "//tools/format:format.fix", +) + +alias( + name = "copyright.check", + actual = "//tools/cr_checker:copyright.check", +) + +alias( + name = "copyright.fix", + actual = "//tools/cr_checker:copyright.fix", +) + +filegroup( + name = "repo_directories", + srcs = [ + "docs", + "tools", + ], + visibility = [ + "//tools/cr_checker:__subpackages__", + ], +) + +exports_files([ + "MODULE.bazel", + "BUILD", +]) diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md new file mode 100644 index 0000000..4ad0d06 --- /dev/null +++ b/CONTRIBUTION.md @@ -0,0 +1,35 @@ +# Eclipse Safe Open Vehicle Core (SCORE) +The [Eclipse Safe Open Vehicle Core](https://projects.eclipse.org/projects/automotive.score) project aims to develop an open-source core stack for Software Defined Vehicles (SDVs), specifically targeting embedded high-performance Electronic Control Units (ECUs). +Please check the [documentation](https://eclipse-score.github.io) for more information. +The source code is hosted at [GitHub](https://github.com/eclipse-score). + +The communication mainly takes place via the [`score-dev` mailing list](https://accounts.eclipse.org/mailing-list/score-dev) and GitHub issues & pull requests (PR). And we have a chatroom for community discussions here [Eclipse SCORE chatroom](https://chat.eclipse.org/#/room/#automotive.score:matrix.eclipse.org). + +Please note that for the project the [Eclipse Foundation’s Terms of Use](https://www.eclipse.org/legal/terms-of-use/) apply. +In addition, you need to sign the [ECA](https://www.eclipse.org/legal/ECA.php) and the [DCO](https://www.eclipse.org/legal/dco/) to contribute to the project. + +## Contributing +### Getting the source code & building the project +Please refer to the [README.md](README.md) for further information. + +### Getting involved + +#### Setup Phase +This phase is part of the eclipse Incubation Phase and shall establish all the processes needed for a safe development of functions. Only after this phase it will be possible to contribute code to the project. As the development in this project is driven by requirements, the processes and needed infrastructure incl. tooling will be established based on non-functional Stakeholder_Requirements. During setup phase the contributions are Bug Fixes and Improvements (both on processes and infrastructure). + +#### Bug Fixes and Improvements +Improvements are adding/changing processes and infrastructure, bug fixes can be also on development work products like code. +In case you want to fix a bug or contribute an improvement, please perform the following steps: +1) Create a PR by using the corresponding template ([Bugfix PR template](.github/PULL_REQUEST_TEMPLATE/bug_fix.md) or [Improvement PR template](.github/PULL_REQUEST_TEMPLATE/improvement.md)). Please mark your PR as draft until it's ready for review by the Committers (see the [Eclipse Foundation Project Handbook](https://www.eclipse.org/projects/handbook/#contributing-committers) for more information on the role definitions). Improvements are requested by the definition or modification of [Stakeholder Requirements](docs/stakeholder_requirements) or [Tool Requirements](docs/tool_requirements) and may be implemented after acceptance/merge of the request by a second Improvement PR. The needed reviews are automatically triggered via the [CODEOWNERS](.github/CODEOWNERS) file in the repository. +2) Initiate content review by opening a corresponding issue for the PR when it is ready for review. Review of the PR and final merge into the project repository is in responsibility of the Committers. Use the [Bugfix Issue template](.github/ISSUE_TEMPLATE/bug_fix.md) or [Improvement Issue template](.github/ISSUE_TEMPLATE/improvement.md) for this. + +Please check here for our Git Commit Rules [Configuration_Tool_Guidelines](docs/process_description/guidelines). + +Please use the [Stakeholder and Tool Requirements Template](docs/process_description/templates) when defining these requirements. + +![Contribution guide workflow](./docs/_assets/contribution_guide.svg "Contribution guide workflow") + +#### Additional Information +Please note, that all Git commit messages must adhere the rules described in the [Eclipse Foundation Project Handbook](https://www.eclipse.org/projects/handbook/#resources-commit). + +Please refer for process descriptions to the folder: [process_description](docs/process_description). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5278bc9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2024 Contributors to the Eclipse Foundation + +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. diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..4d9f2cc --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,56 @@ +module( + name = "score_platform", + version = "0.1", + compatibility_level = 0, +) + +############################################################################### +# +# Python version +# +############################################################################### +bazel_dep(name = "rules_python", version = "0.37.2") + +PYTHON_VERSION = "3.12" + +python = use_extension("@rules_python//python/extensions:python.bzl", "python") +python.toolchain( + is_default = True, + python_version = PYTHON_VERSION, +) +use_repo(python) + +############################################################################### +# +# pip dependencies +# +############################################################################### +pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") +pip.parse( + hub_name = "pip_sphinx", + python_version = PYTHON_VERSION, + requirements_lock = "//docs:requirements_lock.txt", +) +use_repo(pip, "pip_sphinx") + +############################################################################### +# +# Packaging dependencies +# +############################################################################### +bazel_dep(name = "rules_pkg", version = "1.0.1") + +############################################################################### +# +# Buildifier dependency +# Provides formatting and linting of Bazel files. +# +############################################################################### +bazel_dep(name = "buildifier_prebuilt", version = "7.3.1") + +############################################################################### +# +# Generic linting and formatting rules +# +############################################################################### +bazel_dep(name = "aspect_rules_lint", version = "1.0.3") diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..9ba2a49 --- /dev/null +++ b/NOTICE @@ -0,0 +1,35 @@ +# Notices for Eclipse Score + +This content is produced and maintained by the Eclipse Score project. + + * Project home: https://projects.eclipse.org/projects/automotive.score + +## Trademarks + +Eclipse Score and Score are trademarks of the Eclipse Foundation. +Eclipse, and the Eclipse Logo are registered trademarks of +the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. +For more information regarding authorship of content, please consult the +listed source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Apache License Version 2.0 which is available at +https://www.apache.org/licenses/LICENSE-2.0. + +SPDX-License-Identifier: Apache-2.0 + +## Source Code + +The project maintains the following source code repositories: + + * TBD + +## Third party Content + +TBD diff --git a/README.md b/README.md index b06dcd9..d8a3298 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,29 @@ -# score -Score project main repository +# Score Platform + +## Building + +### Supported environment +The build currently supports Linux environments. + +### Use bazelisk for bazel version management +Follow [instructions](https://github.com/bazelbuild/bazelisk) and setup bazelisk to manage your bazel version based on the .bazelversion file. + +### Check and fix formatting +``` +$ bazel test //:format.check +$ bazel run //:format.fix +``` + +## Documentation + +Use //docs:docs target to build the documentation. +``` +$ bazel build //docs:docs +``` + +The output directory can be found under ```bazel-bin/docs/docs/_build/html```. + +If you need to update pip dependencies, after modifying the requirements file, regenerate the lock file: +``` +bazel run //docs:requirements.update +``` diff --git a/docs/BUILD b/docs/BUILD new file mode 100644 index 0000000..d793fee --- /dev/null +++ b/docs/BUILD @@ -0,0 +1,84 @@ +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@pip_sphinx//:requirements.bzl", "requirement") +load("@rules_pkg//pkg:mappings.bzl", "pkg_files") +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("@rules_python//python:defs.bzl", "py_library") +load("@rules_python//python:pip.bzl", "compile_pip_requirements") +load("@rules_python//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs") + +sphinx_docs( + name = "docs", + srcs = glob([ + "**/*.png", + "**/*.svg", + "**/*.rst", + "**/*.html", + ]), + config = ":conf.py", + extra_opts = [ + "-W", + "--keep-going", + ], + formats = [ + "html", + ], + sphinx = ":sphinx_build", + tags = [ + "manual", + ], +) + +sphinx_build_binary( + name = "sphinx_build", + deps = [ + ":extensions", + requirement("sphinx"), + requirement("sphinx-needs"), + ], +) + +py_library( + name = "extensions", + srcs = [ + "_extensions/metamodel.py", + ], + imports = ["."], +) + +compile_pip_requirements( + name = "requirements", + src = "requirements.txt", + requirements_txt = "requirements_lock.txt", + tags = [ + "manual", + ], +) + +filegroup( + name = "html", + srcs = [":docs"], + output_group = "html", +) + +pkg_files( + name = "html_files", + srcs = [":html"], + renames = {"html": ""}, +) + +pkg_tar( + name = "github-pages", + srcs = [":html_files"], +) diff --git a/docs/_assets/contribution_guide.svg b/docs/_assets/contribution_guide.svg new file mode 100644 index 0000000..1f1a3d5 --- /dev/null +++ b/docs/_assets/contribution_guide.svg @@ -0,0 +1,4 @@ + + + +


Contribution during
setup phase























Contribution during...
Contributor
Contr...
Committer
Commi...
Contribution
for bug fixes/
improvements
Contribution...
Contributor creates Issue/PR
with filled out Template
Contributor creates Issue/PR...
Issue/PR
Bug Fix/Improvement
Template
Issue/PR...
Contributor requests review and
discussion of his PR 
Contributor requests review and...
Contribution
accepted ?
Contribution...
Acceptance Criteria
not met
Acceptance Criteria...
YES
YES
NO
NO
Issue closed
PR Not
merged
Issue closed...
Issue closed
PR merged
Issue closed...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/_extensions/metamodel.py b/docs/_extensions/metamodel.py new file mode 100644 index 0000000..c8d2988 --- /dev/null +++ b/docs/_extensions/metamodel.py @@ -0,0 +1,58 @@ +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +# Define project specific needs directives + +needs_types = [ + # Requirements + dict( + directive="stkh_req", + title="Stakeholder requirements", + prefix="STKH_REQ__", + color="#BFD8D2", + style="node", + ), + dict( + directive="tool_req", + title="Tool Requirements", + prefix="TOOL_REQ__", + color="#BFD8D2", + style="node", + ), +] + +# Define extra options for needs object +needs_extra_options = [ + "security", + "safety", + "level", + "rationale", + "mitigated_by", + "reqtype", + "codelink", + "testlink", + "reqcovered", + "testcovered", +] + +needs_extra_links = [ + # TODO: Refer process document for the usage of links + { + "option": "satisfies", + "incoming": "is satisfied by", + "outgoing": "satisfies", + "style_start": "-up", + "style_end": "->", + }, + {"option": "implements", "incoming": "implements by", "outgoing": "implements"}, +] diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html new file mode 100644 index 0000000..c6794ac --- /dev/null +++ b/docs/_templates/layout.html @@ -0,0 +1,8 @@ +{% extends "!layout.html" %} + {% block footer %} {{ super() }} + + + +{% endblock %} diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..f61fd63 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,57 @@ +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# from process.process_model_configuration import * +from _extensions import metamodel + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "Score" +copyright = "2024, Score" +author = "Score" +release = "0.1" + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx_needs", +] + +templates_path = ["_templates"] + +suppress_warnings = ["config.cache"] + +# Enable numref +numfig = True + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "alabaster" + +# -- sphinx-needs configuration -------------------------------------------- + +needs_types = metamodel.needs_types +needs_extra_options = metamodel.needs_extra_options +needs_extra_links = metamodel.needs_extra_links + +# sphinx_needs configuration +needs_id_required = True +needs_id_regex = "^[A-Za-z0-9_-]{6,}" diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..688ed51 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,24 @@ +.. + # ******************************************************************************* + # Copyright (c) 2024 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +Documentation +============= + +.. toctree:: + :maxdepth: 1 + :glob: + + stakeholder_requirements/index.rst + tool_requirements/index.rst + process_description/index.rst diff --git a/docs/process_description/guidelines/branch/index.rst b/docs/process_description/guidelines/branch/index.rst new file mode 100644 index 0000000..b5219ca --- /dev/null +++ b/docs/process_description/guidelines/branch/index.rst @@ -0,0 +1,37 @@ +.. + # ******************************************************************************* + # Copyright (c) 2024 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +########## + Branches +########## + +******************* + Naming Convention +******************* + +In order to keep an overview which branch belongs to whom the branch +name also should be descriptive. The following rules shall apply: + +#. The branch name shall start with your github username. This will make + it easier for everybody to identify the owner of the branch. +#. Branch names must be lower case. +#. Concatenation is done by underscores _. + +An example could look like this: + +Mustermann, GitHub Name: maximuster + +.. code:: + + maximuster_my_awesome_branch_name diff --git a/docs/process_description/guidelines/git/index.rst b/docs/process_description/guidelines/git/index.rst new file mode 100644 index 0000000..4f75c42 --- /dev/null +++ b/docs/process_description/guidelines/git/index.rst @@ -0,0 +1,170 @@ +.. + # ******************************************************************************* + # Copyright (c) 2024 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +################ + Git Guidelines +################ + +*********** + Motivation +*********** + +The commit history and especially the commit messages are part of a +project's documentation. Therefore, the same rules that are valid for +documentation are also valid for commits and commit messages. A commit +message is written once, but read many times (especially when hunting +bugs). Git supports powerful tools to find out which commit introduced a +bug (e.g., git bisect, git blame). Their level of usefulness depends on +the quality of the commits and their respective commit messages. + +****************** + Git Configuration +****************** + +Since name and e-mail address are part of the commit (and thus be part +of the commit history) they shall be specified via the .gitconfig file. +So this file must at least include the following lines: + +.. code-block:: + + [user] + email = (e.g. max.mustermann@something.com) + name = Max Mustermann + +*************** + Commit History +*************** + +Before merging a PR all commits shall be squashed into few (desired only +one) logical commits. + +.. note:: + + Keep in mind that upon merge the commit history of your branch will + be preserved in the main branch of the repo as well. + +********************** + Commit Message Format +********************** + +In Score it is checked if git commit messages are written according +to guidelines. However, it cannot enforce the meaningfulness of the +message (and its parts). + +.. note:: + + Remember that this information is shown in git log and other tools. + +Wording +======= + +Proper English language and full sentences are to be used in the commit +message. For both the subject and the body a singular imperative form is +required. E.g. **"Add unit test for class XY"** and not "I added unit +tests", "Adding unit tests" or "Various minor changes". + +Additionally, the following specification for the content shall apply for +commit messages (according to [Eclipse Git Commit Records](https://www.eclipse.org/projects/handbook/#resources-commit)): + +Summary +======= + +.. code-block:: + + : Summary + +The Subject shall describe what was changed in a single line max 72 +characters long. It shall include a prefix for the module, component or +feature which was changed e.g. "doc:" or "bazel:" It shall start with a +capital letter and should not be ended by a trailing period in the +subject line. + +Good and bad examples for a subject are: + +- **mw: Show colorful output** not Add file +- **bazel: Test Requirement SWS_CM_00001** not Add test +- **osal: Split responsibilities of job handling and execution** not Refactor code + +Description +=========== + +The description must contain a brief summary of the content of the +commit and why this is necessary. Furthermore it must be consistent and +logically complete. + +If feasible, the commit message body should be extended with quoted +material such as compiler warnings, debugger stack traces or measurement +data for performance optimizations. + +Footer +====== + +At the end of the commit message a footer shall be specified +in the following format: + +.. code-block:: + + Also-by: Some Bodyelse + Issue-ref: # + + is specified by: + +- see +- close / closes / closed +- fix / fixes / fixed +- resolve / resolves / resolved + +The Reference can contain links to multiple tickets. A detailed +description of linking issues to code is available on `GitHub +`__. +Be aware that keywords like (close | fix | resolve) will also close the referenced issue if the pull request is merged. + +An additional check is implemented to suppress false positives: if a +commit message has revert/merge in the first line, the linting rules +will not be applied to it. Thereby headaches when performing reverts or +merges are reduced. + +Layout Summary +============== + +In short the commit message shall consist of: + +- Summary +- Empty line +- Description +- Empty line +- Footer + +Example +======= +.. code-block:: + + component: Short one line summary of change + + More detailed explanatory text, if necessary. Wrap it to about 72 + characters or less. The first line is treated as the subject and the + rest of the text as the body. The blank line separating the summary from + the body is critical (unless you omit the body entirely); + + - Bullet points are okay, too + - Typically a hyphen or asterisk is used for the bullet, followed by a + space, using a hanging indent + + Comment how the change was tested. + + Notes about dependencies to other tools or commits in other + repositories. + + Also-by: Some Bodyelse |br| + Issue-Ref: , , ... diff --git a/docs/process_description/guidelines/index.rst b/docs/process_description/guidelines/index.rst new file mode 100644 index 0000000..5cca3fe --- /dev/null +++ b/docs/process_description/guidelines/index.rst @@ -0,0 +1,26 @@ +.. + # ******************************************************************************* + # Copyright (c) 2024 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _Configuration_Tool_Guidelines: + +############################# +Configuration/Tool Guidelines +############################# + +.. toctree:: + :maxdepth: 1 + :glob: + + git/index.rst + branch/index.rst diff --git a/docs/process_description/index.rst b/docs/process_description/index.rst new file mode 100644 index 0000000..5608c2a --- /dev/null +++ b/docs/process_description/index.rst @@ -0,0 +1,47 @@ +.. + # ******************************************************************************* + # Copyright (c) 2024 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _Process_description: + +Process description +=================== + +Processes are the basis to describe the way of working within the SCORE project. + +Requirements engineering +------------------------ +A key process is the Requirements engineering, which is for defining, documenting, and maintaining requirements within our SCORE project. + +Requirements templates +~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + :glob: + + templates/index.rst + +Configuration/Tool management +----------------------------- + +Important from the begin are version control topics, like commit rules and naming conventions for branches. + +Configuration/Tool guidelines +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + :glob: + + guidelines/index.rst diff --git a/docs/process_description/templates/index.rst b/docs/process_description/templates/index.rst new file mode 100644 index 0000000..7252cd5 --- /dev/null +++ b/docs/process_description/templates/index.rst @@ -0,0 +1,60 @@ +.. + # ******************************************************************************* + # Copyright (c) 2024 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _Stakeholder_Requirements_Template: + +Stakeholder Requirements Template +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + | .. stkh_req:: + | :id: STHK_REQ__<Title> + | :reqtype: <Functional|Interface|Process|Legal|Non-Functional> + | :security: <YES|NO> + | :safety: <QM|ASIL_B|ASIL_D> + | :rational: <The rationale provides the reason that the requirement is needed.> + | :status: <valid|invalid> + + | <The SW Platform|Feature|Component> shall <main verb> <object> <parameter> <temporal/logical conjunction> + | <Note: (optional, not to be verified)> + + | Sentence template: + + +----------------------------------------+-------+-----------------------+---------------------------+-------------------------------+-------------------------------------+ + | Addressee of the requirement (subject) | shall | main verb | object of the requirement | parameter of the requirement | temporal/logical conjunction | + +========================================+=======+=======================+===========================+===============================+=====================================+ + | The development object (who/what) | shall | do someting | for whom or what | which target value/condition | when, under which conditions | + +----------------------------------------+-------+-----------------------+---------------------------+-------------------------------+-------------------------------------+ + | The parking brake | shall | hold | the vehicle | up to a inclination of 20 deg | under all conditions (weather, ...) | + | (general example) | | | | | | + +----------------------------------------+-------+-----------------------+---------------------------+-------------------------------+-------------------------------------+ + | The software platform | shall | enable | users | to ensure the compatibility | across vehicle variants and | + | (from our stakeholder requirements) | | | | of application software | vehicle software releases. | + +----------------------------------------+-------+-----------------------+---------------------------+-------------------------------+-------------------------------------+ + + .. note:: + Of the last three columns of the above sentence template table, filling one is mandatory the others are optional. + +Tool Requirements Template +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + | .. tool_req:: <Title> + | :id: TOOL_REQ__<Tool>__<Title> + | :reqtype: <Functional|Interface|Process|Legal|Non-Functional> + | :security: <YES|NO> + | :safety: <QM|ASIL_B|ASIL_D> + | :satisfies: <link to stakeholder id> + | :status: <valid|invalid> + + | <The Tool> shall <main verb> <object> <parameter> <temporal/logical conjunction> + | <Note: (optional, not to be verified)> diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..91fbf5d --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +--extra-index-url https://pypi.org/simple/ + +Sphinx==8.1.3 +sphinx-needs==4.1.0 diff --git a/docs/requirements_lock.txt b/docs/requirements_lock.txt new file mode 100644 index 0000000..7d8cb87 --- /dev/null +++ b/docs/requirements_lock.txt @@ -0,0 +1,375 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# bazel run //docs:requirements.update +# +--extra-index-url https://pypi.org/simple/ + +alabaster==0.7.16 \ + --hash=sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65 \ + --hash=sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92 + # via sphinx +attrs==24.2.0 \ + --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ + --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 + # via + # jsonschema + # referencing +babel==2.15.0 \ + --hash=sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb \ + --hash=sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413 + # via sphinx +certifi==2024.7.4 \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 + # via requests +charset-normalizer==3.3.2 \ + --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ + --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ + --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ + --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ + --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ + --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ + --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ + --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ + --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ + --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ + --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ + --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ + --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ + --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ + --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ + --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ + --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ + --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ + --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ + --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ + --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ + --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ + --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ + --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ + --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ + --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ + --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ + --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ + --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ + --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ + --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ + --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ + --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ + --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ + --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ + --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ + --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ + --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ + --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ + --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ + --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ + --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ + --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ + --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ + --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ + --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ + --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ + --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ + --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ + --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ + --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ + --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ + --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ + --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ + --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ + --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ + --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ + --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ + --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ + --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ + --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ + --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ + --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ + --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ + --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ + --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ + --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ + --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ + --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ + --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ + --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ + --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ + --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ + --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ + --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ + --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ + --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ + --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ + --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ + --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ + --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ + --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ + --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ + --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ + --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ + --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ + --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ + --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ + --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ + --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 + # via requests +docutils==0.20.1 \ + --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \ + --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b + # via sphinx +idna==3.7 \ + --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ + --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 + # via requests +imagesize==1.4.1 \ + --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \ + --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a + # via sphinx +jinja2==3.1.4 \ + --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ + --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d + # via sphinx +jsonschema==4.23.0 \ + --hash=sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4 \ + --hash=sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566 + # via sphinx-needs +jsonschema-specifications==2024.10.1 \ + --hash=sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272 \ + --hash=sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf + # via jsonschema +markupsafe==2.1.5 \ + --hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \ + --hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \ + --hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \ + --hash=sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3 \ + --hash=sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532 \ + --hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \ + --hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \ + --hash=sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df \ + --hash=sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4 \ + --hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \ + --hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \ + --hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \ + --hash=sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8 \ + --hash=sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371 \ + --hash=sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2 \ + --hash=sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465 \ + --hash=sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52 \ + --hash=sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6 \ + --hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \ + --hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \ + --hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \ + --hash=sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0 \ + --hash=sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029 \ + --hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \ + --hash=sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a \ + --hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \ + --hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \ + --hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \ + --hash=sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf \ + --hash=sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9 \ + --hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \ + --hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \ + --hash=sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3 \ + --hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \ + --hash=sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46 \ + --hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \ + --hash=sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a \ + --hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \ + --hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \ + --hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \ + --hash=sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea \ + --hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \ + --hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \ + --hash=sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e \ + --hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \ + --hash=sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f \ + --hash=sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50 \ + --hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \ + --hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \ + --hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \ + --hash=sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff \ + --hash=sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2 \ + --hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \ + --hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \ + --hash=sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf \ + --hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \ + --hash=sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5 \ + --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ + --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ + --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 + # via jinja2 +packaging==24.1 \ + --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ + --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 + # via sphinx +pygments==2.18.0 \ + --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ + --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a + # via sphinx +referencing==0.35.1 \ + --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \ + --hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de + # via + # jsonschema + # jsonschema-specifications +requests==2.32.3 \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 + # via + # requests-file + # sphinx + # sphinx-needs +requests-file==2.1.0 \ + --hash=sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658 \ + --hash=sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c + # via sphinx-needs +rpds-py==0.21.0 \ + --hash=sha256:031819f906bb146561af051c7cef4ba2003d28cff07efacef59da973ff7969ba \ + --hash=sha256:0626238a43152918f9e72ede9a3b6ccc9e299adc8ade0d67c5e142d564c9a83d \ + --hash=sha256:085ed25baac88953d4283e5b5bd094b155075bb40d07c29c4f073e10623f9f2e \ + --hash=sha256:0a9e0759e7be10109645a9fddaaad0619d58c9bf30a3f248a2ea57a7c417173a \ + --hash=sha256:0c025820b78817db6a76413fff6866790786c38f95ea3f3d3c93dbb73b632202 \ + --hash=sha256:1ff2eba7f6c0cb523d7e9cff0903f2fe1feff8f0b2ceb6bd71c0e20a4dcee271 \ + --hash=sha256:20cc1ed0bcc86d8e1a7e968cce15be45178fd16e2ff656a243145e0b439bd250 \ + --hash=sha256:241e6c125568493f553c3d0fdbb38c74babf54b45cef86439d4cd97ff8feb34d \ + --hash=sha256:2c51d99c30091f72a3c5d126fad26236c3f75716b8b5e5cf8effb18889ced928 \ + --hash=sha256:2d6129137f43f7fa02d41542ffff4871d4aefa724a5fe38e2c31a4e0fd343fb0 \ + --hash=sha256:30b912c965b2aa76ba5168fd610087bad7fcde47f0a8367ee8f1876086ee6d1d \ + --hash=sha256:30bdc973f10d28e0337f71d202ff29345320f8bc49a31c90e6c257e1ccef4333 \ + --hash=sha256:320c808df533695326610a1b6a0a6e98f033e49de55d7dc36a13c8a30cfa756e \ + --hash=sha256:32eb88c30b6a4f0605508023b7141d043a79b14acb3b969aa0b4f99b25bc7d4a \ + --hash=sha256:3b766a9f57663396e4f34f5140b3595b233a7b146e94777b97a8413a1da1be18 \ + --hash=sha256:3b929c2bb6e29ab31f12a1117c39f7e6d6450419ab7464a4ea9b0b417174f044 \ + --hash=sha256:3e30a69a706e8ea20444b98a49f386c17b26f860aa9245329bab0851ed100677 \ + --hash=sha256:3e53861b29a13d5b70116ea4230b5f0f3547b2c222c5daa090eb7c9c82d7f664 \ + --hash=sha256:40c91c6e34cf016fa8e6b59d75e3dbe354830777fcfd74c58b279dceb7975b75 \ + --hash=sha256:4991ca61656e3160cdaca4851151fd3f4a92e9eba5c7a530ab030d6aee96ec89 \ + --hash=sha256:4ab2c2a26d2f69cdf833174f4d9d86118edc781ad9a8fa13970b527bf8236027 \ + --hash=sha256:4e8921a259f54bfbc755c5bbd60c82bb2339ae0324163f32868f63f0ebb873d9 \ + --hash=sha256:4eb2de8a147ffe0626bfdc275fc6563aa7bf4b6db59cf0d44f0ccd6ca625a24e \ + --hash=sha256:5145282a7cd2ac16ea0dc46b82167754d5e103a05614b724457cffe614f25bd8 \ + --hash=sha256:520ed8b99b0bf86a176271f6fe23024323862ac674b1ce5b02a72bfeff3fff44 \ + --hash=sha256:52c041802a6efa625ea18027a0723676a778869481d16803481ef6cc02ea8cb3 \ + --hash=sha256:5555db3e618a77034954b9dc547eae94166391a98eb867905ec8fcbce1308d95 \ + --hash=sha256:58a0e345be4b18e6b8501d3b0aa540dad90caeed814c515e5206bb2ec26736fd \ + --hash=sha256:590ef88db231c9c1eece44dcfefd7515d8bf0d986d64d0caf06a81998a9e8cab \ + --hash=sha256:5afb5efde74c54724e1a01118c6e5c15e54e642c42a1ba588ab1f03544ac8c7a \ + --hash=sha256:688c93b77e468d72579351a84b95f976bd7b3e84aa6686be6497045ba84be560 \ + --hash=sha256:6b4ef7725386dc0762857097f6b7266a6cdd62bfd209664da6712cb26acef035 \ + --hash=sha256:6bc0e697d4d79ab1aacbf20ee5f0df80359ecf55db33ff41481cf3e24f206919 \ + --hash=sha256:6dcc4949be728ede49e6244eabd04064336012b37f5c2200e8ec8eb2988b209c \ + --hash=sha256:6f54e7106f0001244a5f4cf810ba8d3f9c542e2730821b16e969d6887b664266 \ + --hash=sha256:808f1ac7cf3b44f81c9475475ceb221f982ef548e44e024ad5f9e7060649540e \ + --hash=sha256:8404b3717da03cbf773a1d275d01fec84ea007754ed380f63dfc24fb76ce4592 \ + --hash=sha256:878f6fea96621fda5303a2867887686d7a198d9e0f8a40be100a63f5d60c88c9 \ + --hash=sha256:8a7ff941004d74d55a47f916afc38494bd1cfd4b53c482b77c03147c91ac0ac3 \ + --hash=sha256:95a5bad1ac8a5c77b4e658671642e4af3707f095d2b78a1fdd08af0dfb647624 \ + --hash=sha256:97ef67d9bbc3e15584c2f3c74bcf064af36336c10d2e21a2131e123ce0f924c9 \ + --hash=sha256:98486337f7b4f3c324ab402e83453e25bb844f44418c066623db88e4c56b7c7b \ + --hash=sha256:98e4fe5db40db87ce1c65031463a760ec7906ab230ad2249b4572c2fc3ef1f9f \ + --hash=sha256:998a8080c4495e4f72132f3d66ff91f5997d799e86cec6ee05342f8f3cda7dca \ + --hash=sha256:9afe42102b40007f588666bc7de82451e10c6788f6f70984629db193849dced1 \ + --hash=sha256:9e20da3957bdf7824afdd4b6eeb29510e83e026473e04952dca565170cd1ecc8 \ + --hash=sha256:a017f813f24b9df929674d0332a374d40d7f0162b326562daae8066b502d0590 \ + --hash=sha256:a429b99337062877d7875e4ff1a51fe788424d522bd64a8c0a20ef3021fdb6ed \ + --hash=sha256:a58ce66847711c4aa2ecfcfaff04cb0327f907fead8945ffc47d9407f41ff952 \ + --hash=sha256:a78d8b634c9df7f8d175451cfeac3810a702ccb85f98ec95797fa98b942cea11 \ + --hash=sha256:a89a8ce9e4e75aeb7fa5d8ad0f3fecdee813802592f4f46a15754dcb2fd6b061 \ + --hash=sha256:a8eeec67590e94189f434c6d11c426892e396ae59e4801d17a93ac96b8c02a6c \ + --hash=sha256:aaeb25ccfb9b9014a10eaf70904ebf3f79faaa8e60e99e19eef9f478651b9b74 \ + --hash=sha256:ad116dda078d0bc4886cb7840e19811562acdc7a8e296ea6ec37e70326c1b41c \ + --hash=sha256:af04ac89c738e0f0f1b913918024c3eab6e3ace989518ea838807177d38a2e94 \ + --hash=sha256:af4a644bf890f56e41e74be7d34e9511e4954894d544ec6b8efe1e21a1a8da6c \ + --hash=sha256:b21747f79f360e790525e6f6438c7569ddbfb1b3197b9e65043f25c3c9b489d8 \ + --hash=sha256:b229ce052ddf1a01c67d68166c19cb004fb3612424921b81c46e7ea7ccf7c3bf \ + --hash=sha256:b4de1da871b5c0fd5537b26a6fc6814c3cc05cabe0c941db6e9044ffbb12f04a \ + --hash=sha256:b80b4690bbff51a034bfde9c9f6bf9357f0a8c61f548942b80f7b66356508bf5 \ + --hash=sha256:b876f2bc27ab5954e2fd88890c071bd0ed18b9c50f6ec3de3c50a5ece612f7a6 \ + --hash=sha256:b8f107395f2f1d151181880b69a2869c69e87ec079c49c0016ab96860b6acbe5 \ + --hash=sha256:b9b76e2afd585803c53c5b29e992ecd183f68285b62fe2668383a18e74abe7a3 \ + --hash=sha256:c2b2f71c6ad6c2e4fc9ed9401080badd1469fa9889657ec3abea42a3d6b2e1ed \ + --hash=sha256:c3761f62fcfccf0864cc4665b6e7c3f0c626f0380b41b8bd1ce322103fa3ef87 \ + --hash=sha256:c38dbf31c57032667dd5a2f0568ccde66e868e8f78d5a0d27dcc56d70f3fcd3b \ + --hash=sha256:ca9989d5d9b1b300bc18e1801c67b9f6d2c66b8fd9621b36072ed1df2c977f72 \ + --hash=sha256:cbd7504a10b0955ea287114f003b7ad62330c9e65ba012c6223dba646f6ffd05 \ + --hash=sha256:d167e4dbbdac48bd58893c7e446684ad5d425b407f9336e04ab52e8b9194e2ed \ + --hash=sha256:d2132377f9deef0c4db89e65e8bb28644ff75a18df5293e132a8d67748397b9f \ + --hash=sha256:da52d62a96e61c1c444f3998c434e8b263c384f6d68aca8274d2e08d1906325c \ + --hash=sha256:daa8efac2a1273eed2354397a51216ae1e198ecbce9036fba4e7610b308b6153 \ + --hash=sha256:dc5695c321e518d9f03b7ea6abb5ea3af4567766f9852ad1560f501b17588c7b \ + --hash=sha256:de552f4a1916e520f2703ec474d2b4d3f86d41f353e7680b597512ffe7eac5d0 \ + --hash=sha256:de609a6f1b682f70bb7163da745ee815d8f230d97276db049ab447767466a09d \ + --hash=sha256:e12bb09678f38b7597b8346983d2323a6482dcd59e423d9448108c1be37cac9d \ + --hash=sha256:e168afe6bf6ab7ab46c8c375606298784ecbe3ba31c0980b7dcbb9631dcba97e \ + --hash=sha256:e78868e98f34f34a88e23ee9ccaeeec460e4eaf6db16d51d7a9b883e5e785a5e \ + --hash=sha256:e860f065cc4ea6f256d6f411aba4b1251255366e48e972f8a347cf88077b24fd \ + --hash=sha256:ea3a6ac4d74820c98fcc9da4a57847ad2cc36475a8bd9683f32ab6d47a2bd682 \ + --hash=sha256:ebf64e281a06c904a7636781d2e973d1f0926a5b8b480ac658dc0f556e7779f4 \ + --hash=sha256:ed6378c9d66d0de903763e7706383d60c33829581f0adff47b6535f1802fa6db \ + --hash=sha256:ee1e4fc267b437bb89990b2f2abf6c25765b89b72dd4a11e21934df449e0c976 \ + --hash=sha256:ee4eafd77cc98d355a0d02f263efc0d3ae3ce4a7c24740010a8b4012bbb24937 \ + --hash=sha256:efec946f331349dfc4ae9d0e034c263ddde19414fe5128580f512619abed05f1 \ + --hash=sha256:f414da5c51bf350e4b7960644617c130140423882305f7574b6cf65a3081cecb \ + --hash=sha256:f71009b0d5e94c0e86533c0b27ed7cacc1239cb51c178fd239c3cfefefb0400a \ + --hash=sha256:f983e4c2f603c95dde63df633eec42955508eefd8d0f0e6d236d31a044c882d7 \ + --hash=sha256:faa5e8496c530f9c71f2b4e1c49758b06e5f4055e17144906245c99fa6d45356 \ + --hash=sha256:fed5dfefdf384d6fe975cc026886aece4f292feaf69d0eeb716cfd3c5a4dd8be + # via + # jsonschema + # referencing +snowballstemmer==2.2.0 \ + --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \ + --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a + # via sphinx +sphinx==8.1.3 \ + --hash=sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2 \ + --hash=sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927 + # via + # -r docs/requirements.txt + # sphinx-data-viewer + # sphinx-needs + # sphinxcontrib-jquery +sphinx-data-viewer==0.1.5 \ + --hash=sha256:a7d5e58613562bb745380bfe61ca8b69997998167fd6fa9aea55606c9a4b17e4 \ + --hash=sha256:b74b1d304c505c464d07c7b225ed0d84ea02dcc88bc1c49cdad7c2275fbbdad4 + # via sphinx-needs +sphinx-needs==4.1.0 \ + --hash=sha256:7d40e9c29353d9784f469b2093412846060cda4f3b55127ac58a2692c3381ef9 \ + --hash=sha256:8ae21e10515249aaba3dabd7fd66afdedd1160ecbc5816337fb6ed82aca293b7 + # via -r docs/requirements.txt +sphinxcontrib-applehelp==1.0.8 \ + --hash=sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619 \ + --hash=sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4 + # via sphinx +sphinxcontrib-devhelp==1.0.6 \ + --hash=sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f \ + --hash=sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3 + # via sphinx +sphinxcontrib-htmlhelp==2.1.0 \ + --hash=sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8 \ + --hash=sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9 + # via sphinx +sphinxcontrib-jquery==4.1 \ + --hash=sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a \ + --hash=sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae + # via sphinx-needs +sphinxcontrib-jsmath==1.0.1 \ + --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \ + --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8 + # via sphinx +sphinxcontrib-qthelp==1.0.7 \ + --hash=sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6 \ + --hash=sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182 + # via sphinx +sphinxcontrib-serializinghtml==1.1.10 \ + --hash=sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7 \ + --hash=sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f + # via sphinx +urllib3==2.2.2 \ + --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ + --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 + # via requests diff --git a/docs/stakeholder_requirements/index.rst b/docs/stakeholder_requirements/index.rst new file mode 100644 index 0000000..e93c5e3 --- /dev/null +++ b/docs/stakeholder_requirements/index.rst @@ -0,0 +1,56 @@ +.. + # ******************************************************************************* + # Copyright (c) 2024 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _Stakeholder_Requirements: + +Stakeholder Requirements +======================== + + +Quality +------- + +.. stkh_req:: Document assumptions and design decisions + :id: STKH_REQ__QLY_document_assumptions_and_design_decisions + :reqtype: Non-Functional + :security: NO + :safety: QM + :rationale: This is a usability constraint needed for long term maintenance support + :status: valid + + All assumptions and design decisions made shall be specified as requirements and agreed within the SCORE community. + + +Requirements Engineering +------------------------ + +.. stkh_req:: Requirements traceability + :id: STKH_REQ__RE_requirements_traceability + :reqtype: Non-Functional + :security: NO + :safety: QM + :rationale: This is a usability constraint needed for long term maintenance support + :status: valid + + All requirements shall be linked from lower to upper level, whereby the top-level are the stakeholder requirements. + +.. stkh_req:: Document requirements as code + :id: STKH_REQ__RE_requirements_as_code + :reqtype: Non-Functional + :security: NO + :safety: QM + :rationale: In this project no external tool or service is used. Therefore as-code is the selected option. + :status: valid + + Requirements shall be documented as code (Docs-as-code). diff --git a/docs/tool_requirements/index.rst b/docs/tool_requirements/index.rst new file mode 100644 index 0000000..a6618b6 --- /dev/null +++ b/docs/tool_requirements/index.rst @@ -0,0 +1,33 @@ +.. + # ******************************************************************************* + # Copyright (c) 2024 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _Tool_Requirements: + +Tool Requirements +================= + + +Process tools +------------- + + +.. tool_req:: Sphinx-needs for process modelling + :id: TOOL_REQ__Sphinx-needs__Process_Modelling + :reqtype: Non-Functional + :security: NO + :safety: QM + :satisfies: STKH_REQ__RE_requirements_as_code + :status: valid + + Spinx-needs shall be used to model all processes within SCORE. diff --git a/tools/cr_checker/BUILD b/tools/cr_checker/BUILD new file mode 100644 index 0000000..ac13f73 --- /dev/null +++ b/tools/cr_checker/BUILD @@ -0,0 +1,35 @@ +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("//tools/cr_checker:cr_checker.bzl", "check", "fix") + +check( + name = "copyright.check", + srcs = [ + "//:BUILD", + "//:MODULE.bazel", + "//:repo_directories", + ], + offset = 24, + visibility = ["//visibility:public"], +) + +fix( + name = "copyright.fix", + srcs = [ + "//:BUILD", + "//:MODULE.bazel", + "//:repo_directories", + ], + visibility = ["//visibility:public"], +) diff --git a/tools/cr_checker/cr_checker.bzl b/tools/cr_checker/cr_checker.bzl new file mode 100644 index 0000000..cdc1fb3 --- /dev/null +++ b/tools/cr_checker/cr_checker.bzl @@ -0,0 +1,132 @@ +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Defines Bazel rules for running copyright checks and fixes.""" + +load("@bazel_skylib//lib:paths.bzl", "paths") + +def _cr_impl(ctx): + """ + Implementation function for the copyright rule. This function sets up the + necessary command to execute the Python script with the specified mode and source files. + Args: + ctx (RuleContext): The rule context containing attributes and configuration. + Returns: + DefaultInfo: Bazel default information provider with the output log file. + """ + script = ctx.attr._script + files = [] + + files = ctx.files.srcs + extensions = ctx.attr.extensions + + text_exts = "" + if len(extensions): + text_exts = "-e {exts}".format( + exts = " ".join([exts for exts in ctx.attr.extensions]), + ) + + ctx.actions.write( + output = ctx.outputs.executable, + content = "{tool}.py -t {template} {extensions} {fix} {use_mmap} {debug} {log_file} {offset} {srcs}".format( + tool = script.files_to_run.executable.short_path, + template = ctx.file.template.path, + extensions = text_exts, + fix = "--fix" if ctx.attr.fix else "", + debug = "--verbose" if ctx.attr.debug else "", + use_mmap = "--use_memory_map" if ctx.attr.use_memory_map else "", + log_file = "--log-file log.txt" if ctx.attr.log_file else "", + offset = "--offset %s" % ctx.attr.offset if ctx.attr.offset else "", + srcs = " ".join([f.path for f in files]), + ), + ) + + runfiles = ctx.runfiles( + files = files + [ctx.file.template], + ).merge( + script.default_runfiles, + ) + return [DefaultInfo(runfiles = runfiles)] + +_cr_rule = rule( + implementation = _cr_impl, + executable = True, + attrs = { + "srcs": attr.label_list(allow_files = True, mandatory = False, default = []), + "template": attr.label(allow_single_file = True), + "extensions": attr.string_list(mandatory = False, default = []), + "debug": attr.bool(mandatory = False, default = False), + "fix": attr.bool(mandatory = False, default = False), + "offset": attr.int(mandatory = False, default = 0), + "log_file": attr.bool(mandatory = False, default = False), + "use_memory_map": attr.bool(mandatory = False, default = False), + "_script": attr.label( + default = Label("//tools/cr_checker/tool:cr_checker"), + ), + }, +) + +def check( + name, + srcs, + visibility, + template = "//tools/cr_checker/resources:templates", + extensions = [], + offset = 0, + debug = False, + log_file = False, + use_memory_map = False): + """ + Defines a Bazel target for checking files without modifying them. + Args: + name (str): The name of the target. + srcs (list of labels): The source files to check. + """ + _cr_rule( + name = name, + srcs = srcs, + template = template, + offset = offset, + debug = debug, + log_file = log_file, + use_memory_map = use_memory_map, + visibility = visibility, + ) + +def fix( + name, + srcs, + visibility, + template = "//tools/cr_checker/resources:templates", + extensions = [], + offset = 0, + debug = False, + log_file = False, + use_memory_map = False): + """ + Defines a Bazel target for fixing files by adding missing copyright text. + Args: + name (str): The name of the target. + srcs (list of labels): The source files to fix. + """ + _cr_rule( + name = name, + srcs = srcs, + template = template, + offset = offset, + debug = debug, + log_file = log_file, + use_memory_map = use_memory_map, + fix = True, + visibility = visibility, + ) diff --git a/tools/cr_checker/resources/BUILD b/tools/cr_checker/resources/BUILD new file mode 100644 index 0000000..b4b9ed7 --- /dev/null +++ b/tools/cr_checker/resources/BUILD @@ -0,0 +1,20 @@ +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +filegroup( + name = "templates", + srcs = [ + "templates.ini", + ], + visibility = ["//visibility:public"], +) diff --git a/tools/cr_checker/resources/templates.ini b/tools/cr_checker/resources/templates.ini new file mode 100644 index 0000000..fc0a711 --- /dev/null +++ b/tools/cr_checker/resources/templates.ini @@ -0,0 +1,56 @@ +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +[cpp,c,h,hpp] +/******************************************************************************** +* Copyright (c) 2024 Contributors to the Eclipse Foundation +* +* See the NOTICE file(s) distributed with this work for additional +* information regarding copyright ownership. +* +* This program and the accompanying materials are made available under the +* terms of the Apache License Version 2.0 which is available at +* https://www.apache.org/licenses/LICENSE-2.0 +* +* SPDX-License-Identifier: Apache-2.0 +********************************************************************************/ + +[py,sh,bzl,ini,BUILD] +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +[rst] +.. + # ******************************************************************************* + # Copyright (c) 2024 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + diff --git a/tools/cr_checker/tool/BUILD b/tools/cr_checker/tool/BUILD new file mode 100644 index 0000000..39ef814 --- /dev/null +++ b/tools/cr_checker/tool/BUILD @@ -0,0 +1,20 @@ +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +py_binary( + name = "cr_checker", + srcs = [ + "cr_checker.py", + ], + visibility = ["//visibility:public"], +) diff --git a/tools/cr_checker/tool/README.md b/tools/cr_checker/tool/README.md new file mode 100644 index 0000000..6c7ee01 --- /dev/null +++ b/tools/cr_checker/tool/README.md @@ -0,0 +1,83 @@ +# CopyRight Checker + +`cr_checker.py` is a tool designed to check if files contain a specified copyright header. It provides configurable logging, color-coded console output, and can handle large file sets efficiently. The script supports reading configuration files for custom copyright templates and can utilize memory-mapped file reading for better performance with large files. Tool itself can also appened copyright header at the beggining of file if flag `--fix` is used. + +## Features + +- Checks files for specified copyright headers based on file extensions. +- Configurable logging, including color-coded output for easy visibility of log levels. +- Supports parameter files for flexible input handling. +- Can use memory mapping for large file handling. +- Customizable file encoding and offset adjustments for header text positioning. +- Can append copyright headers. + +## Requirements + +- Python 3.6+ +- `argparse`, `logging`, `os`, `sys`, `mmap`, `tempfile`, and `pathlib` (standard library modules) + +## Installation + +To use `cr_checker.py`, simply clone this repository. + +## Usage + +The script can be run from the command line with various options to customize its behavior: + +```bash +python cr_checker.py -t <template_file> [options] <inputs> +``` + +### Arguments + +- **-t**, **--template-file**: (Required) Path to the template file that defines the copyright text for each file extension. +- **-v**, **--verbose**: Enable debug-level logging. +- **-l**, **--log-file**: Path to a log file where logs will be saved. If not provided, logs will print to the console. +- **-e**, **--extensions**: List of file extensions to filter, e.g., -e .py .cpp. +- **--use_memory_map**: Use memory-mapped file reading for large files. +- **--encoding**: File encoding (default is utf-8). +- **--offset**: Additional offset for the header length to account for lines like a shebang. +- **--fix**: Setting script into fix mode where copyright header will be added to the files if it's missing from same. +- **inputs**: (Required) Directories or files to parse, or a parameter file prefixed with @ that lists files or directories. + +### Examples + +```sh +python cr_checker.py -t templates.ini -e py cpp -v -l logs.txt my_random_file.cpp my_random_file.py + +python cr_checker.py -t templates.ini -e py cpp --offset 24 --use_memory_map @files_to_check.txt + +python cr_checker.py -t templates.ini -e py cpp --fix --offset 24 --use_memory_map @files_to_check.txt + +``` + +### Template File Format + +The template file should be in INI format, with each section representing a file extension and a template key specifying the copyright text. + +Example templates.ini: + +```ini +[py,sh] +template = # Copyright (c) 2024 Score Project + +[cpp,c,hpp, h] +template = // Copyright (c) 2024 Score Project +``` + +## Exit Codes + +- 0: All files contain the required copyright text. +- 1: Some files are missing the required copyright text. +- Other: Error encountered during file processing. + +### Logging and Color-Coded Output + +By default, logs are printed to the console in color-coded format to indicate log levels. You can redirect logs to a file using the -l option. + +#### Log Colors + +- DEBUG: Blue +- INFO: Green +- WARNING: Yellow +- ERROR: Red diff --git a/tools/cr_checker/tool/cr_checker.py b/tools/cr_checker/tool/cr_checker.py new file mode 100755 index 0000000..be3a380 --- /dev/null +++ b/tools/cr_checker/tool/cr_checker.py @@ -0,0 +1,555 @@ +#!/usr/bin/env python3 + +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""The tool for checking if artifacts have proper copyright.""" + +import argparse +import os +import logging +import sys +import tempfile +import mmap +from pathlib import Path + +LOGGER = logging.getLogger() + +COLORS = { + "BLUE": "\033[34m", + "GREEN": "\033[32m", + "YELLOW": "\033[33m", + "RED": "\033[31m", + "DARK_RED": "\033[35;1m", + "ENDC": "\033[0m", +} + +LOGGER_COLORS = { + "DEBUG": COLORS["BLUE"], + "INFO": COLORS["GREEN"], + "WARNING": COLORS["YELLOW"], + "ERROR": COLORS["RED"], + "CRITICAL": COLORS["DARK_RED"], +} + + +class ColoredFormatter(logging.Formatter): + """ + A custom logging formatter to add color to log level names based on the logging level. + + The `ColoredFormatter` class extends `logging.Formatter` and overrides the `format` + method to add color codes to the log level name (e.g., `INFO`, `WARNING`, `ERROR`) + based on a predefined color mapping in `LOGGER_COLORS`. This color coding helps in + visually distinguishing log messages by severity. + + Attributes: + LOGGER_COLORS (dict): A dictionary mapping log level names (e.g., "INFO", "ERROR") + to their respective color codes. + COLORS (dict): A dictionary of terminal color codes, including an "ENDC" key to reset + colors after the level name. + + Methods: + format(record): Adds color to the `levelname` attribute of the log record and then + formats the record as per the superclass `Formatter`. + """ + + def format(self, record): + log_color = LOGGER_COLORS.get(record.levelname, "") + record.levelname = f"{log_color}{record.levelname}:{COLORS['ENDC']}" + return super().format(record) + + +class ParamFileAction(argparse.Action): # pylint: disable=too-few-public-methods + """ + A custom argparse action to support exclusive parameter files for command-line arguments. + + The `ParamFileAction` class allows users to specify a parameter file (prefixed with '@') + containing file paths or other inputs, which will override any additional inputs provided + in the command line. If a parameter file is found, its contents are used exclusively, + and all other inputs are ignored. If no parameter file is provided, standard inputs are used. + + Attributes: + parser (argparse.ArgumentParser): The argument parser instance. + namespace (argparse.Namespace): The namespace where arguments are stored. + values (list): The list of argument values passed from the command line. + option_string (str, optional): The option string that triggered this action, if any. + + Methods: + __call__(parser, namespace, values, option_string=None): Processes the arguments. + - If any value starts with '@', it reads the parameter file and sets `file_paths` + in `namespace`. + - If no parameter file is detected, it directly assigns `values` to `namespace`. + """ + + def __call__(self, parser, namespace, values, option_string=None): + paramfile = next((v[1:] for v in values if v.startswith("@")), None) + if paramfile: + with open(paramfile, "r", encoding="utf-8") as handle: + file_paths = [line.strip() for line in handle if line.strip()] + setattr(namespace, self.dest, file_paths) + else: + setattr(namespace, self.dest, values) + + +def load_templates(path): + """ + Loads the copyright templates from a configuration file. + + Args: + path (str): Path to the template file. + + Returns: + dict: A dictionary where each key is a file extension (e.g., ".cpp") + and the value is the template string from the config. + """ + templates = {} + current_extensions = [] + + with open(path, "r", encoding="utf-8") as file: + lines = file.readlines() + templates_for_extensions = "" + + for line in lines: + stripped_line = line.strip() + + if stripped_line.startswith("[") and stripped_line.endswith("]"): + if current_extensions: + for ext in current_extensions: + templates[ext] = templates_for_extensions + templates_for_extensions = "" + current_extensions = [] + + extensions = stripped_line[1:-1].split(",") + current_extensions = [ext.strip() for ext in extensions] + LOGGER.debug(current_extensions) + elif current_extensions: + templates_for_extensions += line + + if line.strip() == "": + for ext in current_extensions: + templates[ext] = templates_for_extensions + templates_for_extensions = "" + current_extensions = [] + + if current_extensions: + for ext in current_extensions: + templates[ext] = templates_for_extensions + + LOGGER.debug(templates) + return templates + + +def configure_logging(log_file_path=None, verbose=False): + """ + Configures logging to write messages to the specified log file. + + Args: + log_file_path (str, optional): Path to the log file. + verbose (bool, optional): If True, sets log level to DEBUG. Otherwise, sets it to INFO. + """ + log_level = logging.DEBUG if verbose else logging.INFO + LOGGER.setLevel(log_level) + LOGGER.handlers.clear() + + if log_file_path is not None: + handler = logging.FileHandler(log_file_path) + formatter = logging.Formatter("%(levelname)s: %(message)s") + else: + handler = logging.StreamHandler() + formatter = ColoredFormatter("%(levelname)s %(message)s") + + handler.setLevel(log_level) + handler.setFormatter(formatter) + LOGGER.addHandler(handler) + + +def load_text_from_file(path, header_length, encoding, offset): + """ + Reads the first portion of a file, up to `header_length` characters + plus an additional offset if provided. + + Args: + path (Path): A `pathlib.Path` object pointing to the file. + header_length (int): Number of characters to read for the header. + encoding (str): Encoding type to use when reading the file. + offset (int): Additional number of characters to read beyond + `header_length`, typically used to account for extra + lines (such as a shebang) before the header. + + Returns: + str: The portion of the file read, which should contain the header if present, + including any extra characters specified by `offset`. + """ + total_length = header_length + offset + LOGGER.debug( + "Reading first %d characters from file: %s [%s]", total_length, path, encoding + ) + with open(path, "r", encoding=encoding) as handle: + return handle.read(total_length) + + +def load_text_from_file_with_mmap(path, header_length, encoding, offset): + """ + Maps the file and reads only the first `header_length` bytes plus + an additional offset if provided. + + Args: + path (Path): A `pathlib.Path` object pointing to the file. + header_length (int): Length of the header text to check. + encoding (str): String for setting decoding type. + offset (int): Additional number of characters to read beyond + `header_length`, typically used to account for extra + lines (such as a shebang) before the header. + + Returns: + str: The portion of the file read, which should contain the header if present. + """ + + file_size = os.path.getsize(path) + total_length = header_length + offset + length = min(total_length, file_size) + + if not length: + LOGGER.warning( + "File %s is empty [length: %d]. Return empty string.", path, length + ) + return "" + + LOGGER.debug("Memory mapping first %d bytes from file: %s", header_length, path) + with open(path, "r", encoding=encoding) as handle: + with mmap.mmap(handle.fileno(), length=length, access=mmap.ACCESS_READ) as fmap: + return fmap[:header_length].decode(encoding) + + +def has_copyright(path, copyright_text, use_mmap, encoding, offset): + """ + Checks if the specified copyright text is present in the beginning of a file. + + Args: + path (Path): A `pathlib.Path` object pointing to the file to check. + copyright_text (str): The copyright text to search for at the beginning + of the file. + use_mmap (bool): If True, uses memory-mapped file reading for efficient + large file handling. + encoding (str): Encoding type to use when reading the file. + offset (int): Additional number of characters to read beyond the length + of `copyright_text`, used to account for extra content + (such as a shebang) before the copyright text. + + Returns: + bool: True if the file contains the copyright text, False if it is missing. + + Raises: + IOError: If there is an error opening or reading the file. + """ + + load_text = load_text_from_file + if use_mmap: + load_text = load_text_from_file_with_mmap + + if copyright_text not in load_text(path, len(copyright_text), encoding, offset): + return False + LOGGER.debug("File %s has copyright.", path) + return True + + +def get_files_from_dir(directory, exts=None): + """ + Finds files in the specified directories. Filters by extensions if provided. + + Args: + dirs (list of str): List of directories to search for files. + exts (list of str, optional): List of extensions to filter files. + If None, all files are returned. + + Returns: + list of str: List of file paths found in the directories. + """ + collected_files = [] + LOGGER.debug("Getting files from directory: %s", directory) + for path in directory.rglob("*"): + if path.is_file(): + if exts is None or path.suffix[1:] in exts: + collected_files.append(path) + return collected_files + + +def collect_inputs(inputs, exts=None): + """ + Collects files from a list of input paths, optionally filtering by file extensions. + + Args: + inputs (list): A list of paths to files or directories. + If a directory is provided, all files within it are added to the output. + exts (list, optional): A list of file extensions to filter by (e.g., ['.py', '.txt']). + Only files with these extensions will be included if specified. + + Returns: + list: A list of file paths collected from the input paths, filtered by the given extensions. + If an input is neither a file nor a directory, it is skipped with a warning. + + Logs: + Logs messages at the DEBUG level, detailing processing of directories and files, + and warns if an invalid input path is encountered. + """ + all_files = [] + LOGGER.debug("Extensions: %s", exts) + for i in inputs: + item = Path(i) + if item.is_dir(): + LOGGER.debug("Processing directory: %s", item) + all_files.extend(get_files_from_dir(item, exts)) + elif item.is_file() and (exts is None or item.suffix[1:] in exts): + LOGGER.debug("Processing file: %s", item) + all_files.append(item) + else: + LOGGER.warning("Skipped (input is not a valid file or directory): %s", item) + return all_files + + +def create_temp_file(path, encoding): + """ + Creates a temporary file with the provided content. + + Args: + path (str): The path of file to write the content to the temporary file. + encoding (str, optional): Encoding type to use when writing the file. + + Returns: + str: The path to the temporary file created. + """ + with tempfile.NamedTemporaryFile(mode="w", encoding=encoding, delete=False) as temp: + with open(path, "r", encoding=encoding) as handle: + for chunk in iter(lambda: handle.read(4096), ""): + temp.write(chunk) + return temp.name + + +def fix_copyright(path, copyright_text, encoding, offset): + """ + Inserts a copyright header into the specified file, ensuring that existing + content is preserved according to the provided offset. + + Args: + path (str): The path to the file that needs the copyright header. + copyright_text (str): The copyright text to be added. + encoding (str): The character encoding used to read and write the file. + offset (int): The number of bytes to preserve at the top of the file. + If 0, the first line is overwritten unless it's empty. + For non-zero offsets, ensures the correct number of bytes + are preserved. + """ + + temporary_file = create_temp_file(path, encoding) + + with open(temporary_file, "r", encoding=encoding) as temp: + # Read the first bytes of first line to check if it is equal to the offset + first_line = temp.readline() + byte_array = len(first_line.encode(encoding)) + + if offset > 0 and offset != byte_array: + LOGGER.error("Invalid offset value: %d, expected: %d", offset, byte_array) + return + + with open(path, "w", encoding=encoding) as handle: + if offset > 0: + handle.write(first_line + "\n") + handle.write(copyright_text) + # Reset the file pointer to the beginning of the temporary file + temp.seek(0) + for chunk in iter(lambda: temp.read(4096), ""): + handle.write(chunk) + LOGGER.info("Fixed missing header in: %s", path) + + +def process_files(files, templates, fix, use_mmap=False, encoding="utf-8", offset=0): # pylint: disable=too-many-arguments + """ + Processes a list of files to check for the presence of copyright text. + + Args: + files (list): A list of file paths to check. + templates (dict): A dictionary where keys are file extensions + (e.g., '.py', '.txt') and values are strings or patterns + representing the required copyright text. + use_mmap (bool): Flag for using mmap function for reading files + (instead of standard option). + encoding (str): Encoding type to use when reading the file. + offset (int): Additional number of characters to read beyond the length + of `copyright_text`, used to account for extra content + (such as a shebang) before the copyright text. + + Returns: + int: The number of files that do not contain the required copyright text. + """ + results = {"no_copyright": 0, "fixed": 0} + for item in files: + name = Path(item).name + key = name if name == "BUILD" else Path(item).suffix[1:] + if key not in templates.keys(): + logging.debug( + "Skipped (no configuration for selected file extension): %s", item + ) + continue + if not has_copyright(item, templates[key], use_mmap, encoding, offset): + if fix: + fix_copyright(item, templates[key], encoding, offset) + results["no_copyright"] += 1 + results["fixed"] += 1 + else: + LOGGER.error( + "Missing copyright header in: %s, use --fix to introduce it", item + ) + results["no_copyright"] += 1 + return results + + +def parse_arguments(argv): + """ + Parses command-line arguments. + + Args: + argv (list of str): List of command-line arguments. + + Returns: + argparse.Namespace: Parsed arguments containing files, directories, + copyright_file, extensions and log_file. + """ + parser = argparse.ArgumentParser( + description="A script to check for copyright in files with specific extensions." + ) + + parser.add_argument( + "-t", + "--template-file", + type=Path, + required=True, + help="Path to the template file", + ) + + parser.add_argument( + "-v", "--verbose", action="store_true", help="Enable debug logging level" + ) + + parser.add_argument( + "-l", + "--log-file", + type=Path, + default=None, + help="Redirect logs from STDOUT to this file", + ) + + parser.add_argument( + "-e", + "--extensions", + type=str, + nargs="+", + default=None, + help="List of extensions to filter when searching for files, e.g., '.h .cpp'", + ) + + parser.add_argument( + "--use_memory_map", + action="store_true", + help="Use memory map for reading conent of files \ + (should be used reading gigabyte ranged files).", + ) + + parser.add_argument( + "-f", + "--fix", + action="store_true", + help="Fix missing copyright headers by inserting them", + ) + + parser.add_argument( + "--encoding", default="utf-8", help="File encoding (default: utf-8)." + ) + + parser.add_argument( + "--offset", + dest="offset", + type=int, + default=0, + help="Additional length offset to account for characters like a shebang (default is 0)", + ) + + parser.add_argument( + "inputs", + nargs="+", + action=ParamFileAction, + help="Directories and/or files to parse.", + ) + + return parser.parse_args(argv) + + +def main(argv=None): + """ + Entry point for processing files to check for the presence of required copyright text. + + This function parses command-line arguments, configures logging, loads copyright templates, + collects input files based on provided criteria, and checks each file for the required + copyright text. + + Args: + argv (list, optional): List of command-line arguments. + If `None`, defaults to `sys.argv[1:]`. + + Returns: + int: Error code if an IOError occurs during loading templates or collecting input files; + otherwise, returns 0 as success. + """ + args = parse_arguments(argv if argv is not None else sys.argv[1:]) + configure_logging(args.log_file, args.verbose) + + try: + templates = load_templates(args.template_file) + except IOError as err: + LOGGER.error("Failed to load copyright text: %s", err) + return err.errno + + try: + files = collect_inputs(args.inputs, args.extensions) + except IOError as err: + LOGGER.error("Failed to prcess file %s with error", err.filename) + return err.errno + + LOGGER.debug("Running check on files: %s", files) + + results = process_files( + files, templates, args.fix, args.use_memory_map, args.encoding, args.offset + ) + total_no = results["no_copyright"] + total_fixes = results["fixed"] + + LOGGER.info("=" * 64) + LOGGER.info("Process completed.") + LOGGER.info( + "Total files without copyright: %s%d%s", + COLORS["GREEN"], + total_no, + COLORS["ENDC"], + ) + LOGGER.info( + "Total files that were fixed: %s%d%s", + COLORS["RED"] if total_fixes > 0 else COLORS["GREEN"], + total_fixes, + COLORS["ENDC"], + ) + LOGGER.info("=" * 64) + + return 0 if total_no == 0 else 1 + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) diff --git a/tools/format/BUILD b/tools/format/BUILD new file mode 100644 index 0000000..3bf7c6d --- /dev/null +++ b/tools/format/BUILD @@ -0,0 +1,36 @@ +# ******************************************************************************* +# Copyright (c) 2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@aspect_rules_lint//format:defs.bzl", "format_multirun", "format_test") + +format_multirun( + name = "format.fix", + python = "@aspect_rules_lint//format:ruff", + starlark = "@buildifier_prebuilt//:buildifier", + visibility = [ + "//visibility:public", + ], + yaml = "@aspect_rules_lint//format:yamlfmt", +) + +format_test( + name = "format.check", + no_sandbox = True, + python = "@aspect_rules_lint//format:ruff", + starlark = "@buildifier_prebuilt//:buildifier", + visibility = [ + "//visibility:public", + ], + workspace = "//:MODULE.bazel", + yaml = "@aspect_rules_lint//format:yamlfmt", +)