Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b538d80f6 | ||
|
|
7a4e6b7a5d | ||
|
|
fd37b04813 | ||
|
|
bd442d5d07 | ||
|
|
eae3c8217b | ||
|
|
960c234cc6 | ||
|
|
b6e24d19a9 |
No files matched your search
@@ -154,6 +154,11 @@ and each page's title (H1) and declaration by
|
||||
[`docs/docset/generate_docset.py`](https://github.com/nlohmann/json/blob/develop/docs/docset/generate_docset.py);
|
||||
`make build` reports API pages that cannot be classified.
|
||||
|
||||
A pull request that changes only the documentation, Markdown files, GitHub metadata, or license files skips the
|
||||
compiler workflows (Ubuntu, macOS, Windows); the documentation and license checks still run. See
|
||||
[`tools/check_path_filters`](https://github.com/nlohmann/json/tree/develop/tools/check_path_filters) for the list of
|
||||
skipped files and what to do when a compiler job starts reading one of them.
|
||||
|
||||
### Amalgamate the source code
|
||||
|
||||
The single-header files
|
||||
|
||||
@@ -7,6 +7,25 @@ on:
|
||||
- master
|
||||
- release/*
|
||||
pull_request:
|
||||
# Skip pull requests that change only files no job here reads. The list is checked by
|
||||
# tools/check_path_filters/check_path_filters.py (repository_checks.yml); change both together.
|
||||
paths:
|
||||
- '**'
|
||||
- '!docs/**'
|
||||
- '!**.md'
|
||||
- '!.github/*'
|
||||
- '!.github/ISSUE_TEMPLATE/**'
|
||||
- '!.github/external_ci/**'
|
||||
- '!.github/workflows/**'
|
||||
- '!.reuse/**'
|
||||
- '!LICENSES/**'
|
||||
- '!CITATION.cff'
|
||||
- '!REUSE.toml'
|
||||
# read by tools/check_build_options in the ci_meson_install job (ubuntu.yml)
|
||||
- 'docs/mkdocs/docs/integration/package_managers.md'
|
||||
# built by the swiftpm job (macos.yml)
|
||||
- 'docs/mkdocs/docs/integration/swift/**'
|
||||
- '.github/workflows/macos.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
name: Repository checks
|
||||
|
||||
# Checks that concern files the compiler workflows (ubuntu.yml, macos.yml,
|
||||
# windows.yml) skip with their path filter: the documentation, the license
|
||||
# information, and the path filter itself. This workflow has no path filter.
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- master
|
||||
- release/*
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check_path_filters:
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check the path filters of the compiler workflows
|
||||
run: python3 tools/check_path_filters/check_path_filters.py
|
||||
|
||||
ci_reuse_compliance:
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@a89e43e22a96abafcd7a62db652a65ecd33052c9 # v4.4.4
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
run: cmake --build build --target ci_reuse_compliance
|
||||
|
||||
ci_test_documentation:
|
||||
runs-on: ubuntu-26.04
|
||||
strategy:
|
||||
matrix:
|
||||
target: [ci_test_examples, ci_test_build_documentation, ci_test_documentation_mermaid]
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
# the git-revision-date-localized plugin needs the history; a shallow clone makes the strict build fail
|
||||
fetch-depth: ${{ matrix.target == 'ci_test_build_documentation' && '0' || '1' }}
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
||||
if: matrix.target == 'ci_test_documentation_mermaid'
|
||||
with:
|
||||
node-version: 24
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
run: cmake --build build --target ${{ matrix.target }}
|
||||
@@ -7,6 +7,25 @@ on:
|
||||
- master
|
||||
- release/*
|
||||
pull_request:
|
||||
# Skip pull requests that change only files no job here reads. The list is checked by
|
||||
# tools/check_path_filters/check_path_filters.py (repository_checks.yml); change both together.
|
||||
paths:
|
||||
- '**'
|
||||
- '!docs/**'
|
||||
- '!**.md'
|
||||
- '!.github/*'
|
||||
- '!.github/ISSUE_TEMPLATE/**'
|
||||
- '!.github/external_ci/**'
|
||||
- '!.github/workflows/**'
|
||||
- '!.reuse/**'
|
||||
- '!LICENSES/**'
|
||||
- '!CITATION.cff'
|
||||
- '!REUSE.toml'
|
||||
# read by tools/check_build_options in the ci_meson_install job (ubuntu.yml)
|
||||
- 'docs/mkdocs/docs/integration/package_managers.md'
|
||||
# built by the swiftpm job (macos.yml)
|
||||
- 'docs/mkdocs/docs/integration/swift/**'
|
||||
- '.github/workflows/ubuntu.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -109,7 +128,7 @@ jobs:
|
||||
runs-on: ubuntu-26.04
|
||||
strategy:
|
||||
matrix:
|
||||
target: [ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind]
|
||||
target: [ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_test_valgrind]
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
|
||||
@@ -449,31 +468,6 @@ jobs:
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
|
||||
ci_test_documentation:
|
||||
runs-on: ubuntu-26.04
|
||||
strategy:
|
||||
matrix:
|
||||
target: [ci_test_examples, ci_test_build_documentation, ci_test_documentation_mermaid]
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
# the git-revision-date-localized plugin needs the history; a shallow clone makes the strict build fail
|
||||
fetch-depth: ${{ matrix.target == 'ci_test_build_documentation' && '0' || '1' }}
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
||||
if: matrix.target == 'ci_test_documentation_mermaid'
|
||||
with:
|
||||
node-version: 24
|
||||
- name: Run CMake
|
||||
run: cmake -S . -B build -DJSON_CI=On
|
||||
- name: Build
|
||||
run: cmake --build build --target ${{ matrix.target }}
|
||||
|
||||
# Native Linux ARM64 runner with the latest GCC. The ubuntu-24.04-arm label is
|
||||
# only available for public repositories.
|
||||
ci_test_arm64:
|
||||
|
||||
@@ -7,6 +7,25 @@ on:
|
||||
- master
|
||||
- release/*
|
||||
pull_request:
|
||||
# Skip pull requests that change only files no job here reads. The list is checked by
|
||||
# tools/check_path_filters/check_path_filters.py (repository_checks.yml); change both together.
|
||||
paths:
|
||||
- '**'
|
||||
- '!docs/**'
|
||||
- '!**.md'
|
||||
- '!.github/*'
|
||||
- '!.github/ISSUE_TEMPLATE/**'
|
||||
- '!.github/external_ci/**'
|
||||
- '!.github/workflows/**'
|
||||
- '!.reuse/**'
|
||||
- '!LICENSES/**'
|
||||
- '!CITATION.cff'
|
||||
- '!REUSE.toml'
|
||||
# read by tools/check_build_options in the ci_meson_install job (ubuntu.yml)
|
||||
- 'docs/mkdocs/docs/integration/package_managers.md'
|
||||
# built by the swiftpm job (macos.yml)
|
||||
- 'docs/mkdocs/docs/integration/swift/**'
|
||||
- '.github/workflows/windows.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
|
||||
@@ -10,13 +10,6 @@ at its root, a [Natvis](https://learn.microsoft.com/en-us/visualstudio/debugger/
|
||||
file that gives `json`/`ordered_json` values a friendly, key/value debugger view instead of showing raw internal
|
||||
fields, when debugging with the MSVC debug engine (`cppvsdbg`) in Visual Studio or VS Code.
|
||||
|
||||
The file also has visualizers for `json_document` and `json_view` (and their `ordered_json`/editable variants). They
|
||||
show the value of the document or view, and its elements as an expandable list. Because a document is only a flat index
|
||||
into the source text, the strings of the direct elements are shown, but the elements of nested arrays and objects are
|
||||
shown as index nodes (their kind, size, and numbers; strings only by length). Arrays and objects that have been edited
|
||||
in a `json_editable_document` are not expanded. The visualizers read the internal layout of the MSVC STL (`std::array`,
|
||||
`std::unique_ptr`).
|
||||
|
||||
The checked-in visualizers cover namespace variants with zero, one, or two ABI tags. Configurations with three or more
|
||||
ABI tags are not covered and may show raw internal fields instead. To generate a Natvis file for such a configuration:
|
||||
|
||||
@@ -36,7 +29,7 @@ ABI tags are not covered and may show raw internal fields instead. To generate a
|
||||
|
||||
4. Use the generated file instead of `nlohmann_json.natvis`.
|
||||
|
||||
`--abi-tags` can be repeated for several configurations, and `--all` generates every combination (about 60 MB for 11
|
||||
`--abi-tags` can be repeated for several configurations, and `--all` generates every combination (about 60 MB for 12
|
||||
ABI tags, doubling with each further tag). See
|
||||
[`tools/generate_natvis`](https://github.com/nlohmann/json/tree/develop/tools/generate_natvis) for all options.
|
||||
|
||||
|
||||
@@ -766,6 +766,9 @@ class basic_json_view
|
||||
template<typename, typename> friend class detail::view::view_side;
|
||||
friend iterator;
|
||||
|
||||
/// whether the view is one of an editable document
|
||||
static constexpr bool is_editable = Editable;
|
||||
|
||||
basic_json_view(const document_data* d, const node* n) noexcept
|
||||
: m_doc(d), m_node(n)
|
||||
{}
|
||||
|
||||
Generated
-11880
File diff suppressed because it is too large.
Load diff
Generated
+3
@@ -9807,6 +9807,9 @@ class basic_json_view
|
||||
template<typename, typename> friend class detail::view::view_side;
|
||||
friend iterator;
|
||||
|
||||
/// whether the view is one of an editable document
|
||||
static constexpr bool is_editable = Editable;
|
||||
|
||||
basic_json_view(const document_data* d, const node* n) noexcept
|
||||
: m_doc(d), m_node(n)
|
||||
{}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# check_path_filters
|
||||
|
||||
The compiler workflows [`ubuntu.yml`](../../.github/workflows/ubuntu.yml),
|
||||
[`macos.yml`](../../.github/workflows/macos.yml), and [`windows.yml`](../../.github/workflows/windows.yml) skip pull
|
||||
requests that change only files no compiler job reads: the documentation, Markdown files, GitHub metadata, other
|
||||
workflows, and the license files. Pushes to `develop`, `master`, and `release/*` always run them. The documentation,
|
||||
license, and path-filter checks run in [`repository_checks.yml`](../../.github/workflows/repository_checks.yml), which
|
||||
has no path filter.
|
||||
|
||||
The filter starts with `'**'` and excludes these files explicitly, so a new file runs the compiler workflows unless it
|
||||
is excluded on purpose. [`check_path_filters.py`](check_path_filters.py) holds the filter (`PATHS`) and checks that
|
||||
|
||||
- each of the three workflows has exactly this filter, with its own workflow file included,
|
||||
- the CI targets that read excluded files (`UNFILTERED_TARGETS`) do not run in these workflows, and
|
||||
- no file the filter keeps (sources, tests, build files, tools, workflows) mentions an excluded file or directory
|
||||
outside a comment line, unless the mention is listed in `KNOWN_REFERENCES` with a reason.
|
||||
|
||||
When the check reports a mention, decide whether a compiler job reads that file:
|
||||
|
||||
- If it does, include the file in `PATHS` after the exclusions (as `package_managers.md` and the Swift example are) and
|
||||
copy the new filter into the three workflows.
|
||||
- If it does not, add the mention to `KNOWN_REFERENCES` with the reason.
|
||||
|
||||
Run the check with
|
||||
|
||||
```shell
|
||||
python3 tools/check_path_filters/check_path_filters.py
|
||||
```
|
||||
|
||||
To see which workflows a pull request would run, pass the changed files:
|
||||
|
||||
```shell
|
||||
python3 tools/check_path_filters/check_path_filters.py --changed $(git diff --name-only origin/develop)
|
||||
```
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Check the path filters of the compiler workflows.
|
||||
|
||||
ubuntu.yml, macos.yml and windows.yml skip pull requests that change only files
|
||||
no compiler job reads (documentation, Markdown files, GitHub metadata, license
|
||||
files). The filter starts with '**' and excludes these files explicitly, so a
|
||||
new file runs the workflows unless it is excluded on purpose.
|
||||
|
||||
The script checks that
|
||||
|
||||
- each of the three workflows has exactly the filter defined in PATHS below,
|
||||
with its own workflow file included, and
|
||||
- no tracked file that the filter keeps (sources, tests, build files, tools,
|
||||
workflows) mentions a file the filter excludes, unless the mention is listed
|
||||
in KNOWN_REFERENCES with the reason why it does not matter.
|
||||
|
||||
A mention found this way must either be added to PATHS as an included path
|
||||
(the file is read by a compiler job) or to KNOWN_REFERENCES (it is not).
|
||||
|
||||
With --changed FILE..., the script prints instead which workflows a pull
|
||||
request changing these files would run.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess # nosec B404
|
||||
import sys
|
||||
|
||||
REPO_ROOT = os.path.normpath(os.path.join(sys.path[0], '..', '..'))
|
||||
SELF = 'tools/check_path_filters/check_path_filters.py'
|
||||
|
||||
WORKFLOWS = ['.github/workflows/ubuntu.yml', '.github/workflows/macos.yml', '.github/workflows/windows.yml']
|
||||
|
||||
# The pull_request paths filter of the workflows above; '{workflow}' is replaced
|
||||
# with the workflow's own file. GitHub applies the patterns in order: a file
|
||||
# matching a later pattern is included ('pattern') or excluded ('!pattern').
|
||||
PATHS = [
|
||||
'**',
|
||||
'!docs/**',
|
||||
'!**.md',
|
||||
'!.github/*',
|
||||
'!.github/ISSUE_TEMPLATE/**',
|
||||
'!.github/external_ci/**',
|
||||
'!.github/workflows/**',
|
||||
'!.reuse/**',
|
||||
'!LICENSES/**',
|
||||
'!CITATION.cff',
|
||||
'!REUSE.toml',
|
||||
# read by tools/check_build_options in the ci_meson_install job (ubuntu.yml)
|
||||
'docs/mkdocs/docs/integration/package_managers.md',
|
||||
# built by the swiftpm job (macos.yml)
|
||||
'docs/mkdocs/docs/integration/swift/**',
|
||||
'{workflow}',
|
||||
]
|
||||
|
||||
# Mentions of excluded files that no job of the three workflows depends on:
|
||||
# (file that mentions it, the mention, reason)
|
||||
KNOWN_REFERENCES = [
|
||||
('cmake/ci.cmake', 'docs/', 'ci_test_examples; runs in repository_checks.yml, which has no path filter'),
|
||||
('cmake/ci.cmake', 'docs/mkdocs/', 'ci_test_build_documentation and ci_test_documentation_mermaid; they run in '
|
||||
'repository_checks.yml, which has no path filter'),
|
||||
('cmake/ci.cmake', 'docs/mkdocs/docs/examples/', 'indentation check of ci_test_amalgamation; the same check runs in '
|
||||
'check_amalgamation.yml, which has no path filter'),
|
||||
('Makefile', 'docs/mkdocs/docs/examples/', 'make pretty; runs in check_amalgamation.yml, which has no path filter'),
|
||||
('Makefile', 'ChangeLog.md', 'make ChangeLog.md writes the file; no CI job runs it'),
|
||||
('Makefile', 'tests/fuzzing.md', 'help text'),
|
||||
('Makefile', 'tools/generate_natvis/README.md', 'help text'),
|
||||
('tests/src/make_test_data_available.hpp', 'README.md', 'a file of the external test data repository'),
|
||||
('tools/check_build_options/check_build_options.py', 'docs/', 'builds the path of package_managers.md, which '
|
||||
'PATHS includes'),
|
||||
]
|
||||
|
||||
|
||||
# CI targets that read excluded files; they must run in a workflow without a path filter
|
||||
UNFILTERED_TARGETS = ['ci_test_examples', 'ci_test_build_documentation', 'ci_test_documentation_mermaid',
|
||||
'ci_test_amalgamation', 'ci_reuse_compliance']
|
||||
|
||||
|
||||
def git_files(root):
|
||||
# fixed command, no user input; includes new files not yet added, so a local run
|
||||
# sees what CI sees after the commit
|
||||
out = subprocess.check_output(['git', 'ls-files', '-z', '--cached', '--others', '--exclude-standard'], cwd=root) # nosec B603, B607
|
||||
return [f for f in out.decode('utf-8').split('\0') if f]
|
||||
|
||||
|
||||
def glob_to_regex(pattern):
|
||||
"""Translate a GitHub Actions path pattern to a regular expression."""
|
||||
regex = ''
|
||||
i = 0
|
||||
while i < len(pattern):
|
||||
if pattern.startswith('**', i):
|
||||
regex += '.*'
|
||||
i += 2
|
||||
elif pattern[i] == '*':
|
||||
regex += '[^/]*'
|
||||
i += 1
|
||||
elif pattern[i] == '?':
|
||||
regex += '[^/]'
|
||||
i += 1
|
||||
else:
|
||||
regex += re.escape(pattern[i])
|
||||
i += 1
|
||||
return re.compile(regex + r'\Z')
|
||||
|
||||
|
||||
def compile_filter(paths, workflow):
|
||||
return [(p.startswith('!'), glob_to_regex(p.lstrip('!').replace('{workflow}', workflow))) for p in paths]
|
||||
|
||||
|
||||
def included(compiled, path):
|
||||
result = False
|
||||
for negated, regex in compiled:
|
||||
if regex.match(path):
|
||||
result = not negated
|
||||
return result
|
||||
|
||||
|
||||
def read_filter(root, workflow):
|
||||
"""Return the pull_request paths list of a workflow file."""
|
||||
with open(os.path.join(root, workflow), encoding='utf-8') as f:
|
||||
lines = f.read().splitlines()
|
||||
paths = None
|
||||
in_pull_request = False
|
||||
for line in lines:
|
||||
if re.match(r'^ pull_request:', line):
|
||||
in_pull_request = True
|
||||
continue
|
||||
if in_pull_request:
|
||||
if re.match(r'^ \S', line) or re.match(r'^\S', line):
|
||||
break
|
||||
if re.match(r'^ paths:\s*$', line):
|
||||
paths = []
|
||||
continue
|
||||
m = re.match(r"^ - '(.*)'\s*(#.*)?$", line)
|
||||
if paths is not None and m:
|
||||
paths.append(m.group(1))
|
||||
elif paths is not None and line.strip() and not line.strip().startswith('#'):
|
||||
break
|
||||
return paths
|
||||
|
||||
|
||||
TOKEN = re.compile(r'(["\'/]?)([\w.-]+(?:/[\w.-]+)*)')
|
||||
|
||||
|
||||
COMMENT_LINE = re.compile(r'^[ \t]*(//|#|/?\*|--).*$', re.MULTILINE)
|
||||
|
||||
|
||||
class Mentions:
|
||||
"""Finds the words and paths in a text that name an excluded file or directory."""
|
||||
|
||||
def __init__(self, files, excluded, is_excluded):
|
||||
self.files = set(files)
|
||||
self.excluded = excluded
|
||||
self.dirs = {'/'.join(f.split('/')[:n]) for f in files for n in range(1, f.count('/') + 1)}
|
||||
# an excluded directory: a new file in it would be excluded
|
||||
self.excluded_dirs = {d for d in self.dirs if is_excluded(d + '/new_file')}
|
||||
# base names that only excluded files have, e.g. 'ChangeLog.md' but not 'CMakeLists.txt'
|
||||
self.names = {os.path.basename(f) for f in excluded} - {os.path.basename(f) for f in files if f not in excluded}
|
||||
|
||||
def find(self, text):
|
||||
"""Yield (offset, mention) for every word or path in text that names an excluded file or directory."""
|
||||
for m in TOKEN.finditer(text):
|
||||
parts = m.group(2).rstrip('/').split('/')
|
||||
# a single word names a directory only in a path context, e.g. 'docs' in os.path.join('docs', ...)
|
||||
path_context = len(parts) > 1 or m.group(1)
|
||||
for i in range(len(parts)):
|
||||
path = '/'.join(parts[i:])
|
||||
if path in self.files:
|
||||
if path in self.excluded:
|
||||
yield m.start(2), path
|
||||
break
|
||||
if path in self.dirs and path_context:
|
||||
if path in self.excluded_dirs:
|
||||
yield m.start(2), path + '/'
|
||||
break
|
||||
else:
|
||||
if parts[-1] in self.names and '.' in parts[-1]:
|
||||
yield m.start(2), parts[-1]
|
||||
|
||||
|
||||
def known(path, mention):
|
||||
return any(path == file and mention == known_mention for file, known_mention, _ in KNOWN_REFERENCES)
|
||||
|
||||
|
||||
def check_workflows(root):
|
||||
"""Return the errors in the filters of the workflows and in the targets they run."""
|
||||
errors = []
|
||||
for workflow in WORKFLOWS:
|
||||
expected = [p.replace('{workflow}', workflow) for p in PATHS]
|
||||
actual = read_filter(root, workflow)
|
||||
if actual != expected:
|
||||
errors.append('{}: the pull_request paths filter differs from tools/check_path_filters/check_path_filters.py\n'
|
||||
' expected: {}\n actual: {}'.format(workflow, expected, actual))
|
||||
with open(os.path.join(root, workflow), encoding='utf-8') as f:
|
||||
text = f.read()
|
||||
errors += ['{}: runs {}, which reads excluded files; run it in repository_checks.yml'.format(workflow, target)
|
||||
for target in UNFILTERED_TARGETS if re.search(r'\b' + target + r'\b', text)]
|
||||
return errors
|
||||
|
||||
|
||||
def scanned_text(root, path):
|
||||
"""Return the text of a kept file without comment lines and without the filter itself, or None to skip it."""
|
||||
# third-party code and Markdown files read nothing; this script lists the excluded files
|
||||
if path.startswith('tests/thirdparty/') or path.endswith('.md') or path == SELF:
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(root, path), encoding='utf-8') as f:
|
||||
# a mention in a comment line reads nothing; keep the line numbers
|
||||
text = COMMENT_LINE.sub('', f.read())
|
||||
except (UnicodeDecodeError, OSError):
|
||||
return None
|
||||
if path in WORKFLOWS:
|
||||
# the filter itself lists the excluded files
|
||||
for p in PATHS:
|
||||
text = text.replace(" - '{}'".format(p.replace('{workflow}', path)), '')
|
||||
return text
|
||||
|
||||
|
||||
def check_mentions(root, files, excluded, finder):
|
||||
"""Return an error for every mention of an excluded file in a kept file that KNOWN_REFERENCES does not list."""
|
||||
errors = []
|
||||
for path in sorted(set(files) - excluded):
|
||||
text = scanned_text(root, path)
|
||||
reported = set()
|
||||
for offset, mention in finder.find(text or ''):
|
||||
if mention not in reported and not known(path, mention):
|
||||
reported.add(mention)
|
||||
line = text.count('\n', 0, offset) + 1
|
||||
errors.append('{}:{}: mentions excluded {}; include it in PATHS if a compiler job reads it, '
|
||||
'or add it to KNOWN_REFERENCES'.format(path, line, mention))
|
||||
return errors
|
||||
|
||||
|
||||
def check(root):
|
||||
files = git_files(root)
|
||||
union = [compile_filter(PATHS, w) for w in WORKFLOWS]
|
||||
|
||||
def is_excluded(path):
|
||||
return not any(included(c, path) for c in union)
|
||||
|
||||
excluded = {f for f in files if is_excluded(f)}
|
||||
errors = check_workflows(root) + check_mentions(root, files, excluded, Mentions(files, excluded, is_excluded))
|
||||
for e in errors:
|
||||
print(e)
|
||||
if not errors:
|
||||
print('path filters OK: {} of {} tracked files skip the compiler workflows'.format(len(excluded), len(files)))
|
||||
return 1 if errors else 0
|
||||
|
||||
|
||||
def explain(changed):
|
||||
for workflow in WORKFLOWS:
|
||||
compiled = compile_filter(PATHS, workflow)
|
||||
hits = [f for f in changed if included(compiled, f)]
|
||||
print('{}: {}'.format(workflow, 'runs ({})'.format(', '.join(hits[:3]) + (' ...' if len(hits) > 3 else ''))
|
||||
if hits else 'skipped'))
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||
parser.add_argument('--root', default=REPO_ROOT, help='repository root')
|
||||
parser.add_argument('--changed', nargs='+', metavar='FILE', help='show which workflows these changed files run')
|
||||
args = parser.parse_args()
|
||||
return explain(args.changed) if args.changed else check(args.root)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -6,11 +6,6 @@ The checked-in `nlohmann_json.natvis` covers the default namespace (no ABI tags)
|
||||
of ABI tags, with both versioned and unversioned namespace variants. Configurations that enable three or more ABI tags
|
||||
are not covered by this reduced file; use `--abi-tags` or `--all` (see below) to generate a file for them.
|
||||
|
||||
The visualizers of `basic_json_document` and `basic_json_view` live in the same inline namespaces as `basic_json`, so the
|
||||
ABI tags apply to them in the same way, and the `view_mode` template argument is covered by a wildcard: it does not
|
||||
multiply the namespaces. Each namespace gets three more types (`basic_json_view<*,*>`, `basic_json_document<*,*>`, and
|
||||
`detail::view::node`), which roughly doubles the size of the file.
|
||||
|
||||
The ABI tag list and the library version are parsed from
|
||||
`include/nlohmann/detail/abi_macros.hpp`, so this script must be re-run (via
|
||||
`make natvis`) whenever an `NLOHMANN_JSON_ABI_TAG_*` macro is added to that
|
||||
@@ -40,7 +35,7 @@ version other than the one in `abi_macros.hpp`.
|
||||
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `--list-tags` | Print every ABI tag (in namespace order) with the macro that enables it and the `NLOHMANN_JSON_ABI_TAG_*` identifier, then exit. |
|
||||
| `--abi-tags TAGS` | Add the namespaces of one configuration, given as a comma-separated list of ABI tags (`_diag,_dp,_ns`; the leading underscore is optional, and the order does not matter). Can be repeated for several configurations. Unknown tags are an error. |
|
||||
| `--all` | Generate the namespaces for every combination of ABI tags. The file size doubles with each tag (about 60 MB for 11 tags). Cannot be combined with `--abi-tags`. |
|
||||
| `--all` | Generate the namespaces for every combination of ABI tags. The file size doubles with each tag (about 60 MB for 12 tags). Cannot be combined with `--abi-tags`. |
|
||||
| `--output FILE` | Write the Natvis file to `FILE` instead of `nlohmann_json.natvis` in the repository root. |
|
||||
|
||||
Each configuration gets both the versioned (`json_abi_diag_dp_ns_v3_12_0`) and the unversioned (`json_abi_diag_dp_ns`,
|
||||
|
||||
@@ -95,7 +95,7 @@ if __name__ == '__main__':
|
||||
'optional) of one configuration to add to the default namespaces; can be repeated')
|
||||
selection.add_argument('--all', action='store_true',
|
||||
help='Generate the namespaces for every combination of ABI tags; the file size doubles '
|
||||
'with each ABI tag (about 60 MB for 11 tags)')
|
||||
'with each ABI tag (about 60 MB for 12 tags)')
|
||||
parser.add_argument('--list-tags', action='store_true',
|
||||
help='List the ABI tags with the macros that enable them, and exit')
|
||||
parser.add_argument('--output', metavar='FILE',
|
||||
|
||||
@@ -5,39 +5,6 @@
|
||||
<!-- * * * * * * * * AUTO-GENERATED FILE * * * * * * * * -->
|
||||
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
{# The children of the container node `node` (a pointer expression) of the document `doc` (a document_data pointer
|
||||
expression). A node is only an index into the source text: strings are read from `doc`, so the strings of the
|
||||
direct children are readable here, but the children of a nested container are shown as nodes (see the node
|
||||
visualizer below). Containers with edits (flag 8, "moved") are not expanded. The node kinds are the numbers of
|
||||
node_kind: 1 object, 2 array, 3 string; the float token is shown only by the node visualizer. #}
|
||||
{% macro children(node, doc=none) %}
|
||||
<CustomListItems MaxItemsPerView="1000">
|
||||
<Variable Name="nd" InitialValue="{{ node }}" />
|
||||
<Variable Name="obj" InitialValue="nd != 0 && (int)nd->kind == 1" />
|
||||
<Variable Name="n" InitialValue="(nd != 0 && ((int)nd->kind == 1 || (int)nd->kind == 2) && (nd->flags & 8) == 0) ? (int)nd->len : 0" />
|
||||
<Variable Name="p" InitialValue="nd + 1" />
|
||||
<Variable Name="i" InitialValue="0" />
|
||||
<Size>obj ? 2 * n : n</Size>
|
||||
<Loop Condition="i < n">
|
||||
{% if doc %}
|
||||
<Item Name="key" Condition="obj">{{ doc }}->base._Elems[p->flags & 3] + p->off,[p->len]s8</Item>
|
||||
{% else %}
|
||||
<Item Name="key" Condition="obj">*p</Item>
|
||||
{% endif %}
|
||||
<Exec Condition="obj">p = p + 1</Exec>
|
||||
{% if doc %}
|
||||
<Item Name="value" Condition="obj && (int)p->kind == 3">{{ doc }}->base._Elems[p->flags & 3] + p->off,[p->len]s8</Item>
|
||||
{% endif %}
|
||||
<Item Name="value" Condition="obj{% if doc %} && (int)p->kind != 3{% endif %}">*p</Item>
|
||||
{% if doc %}
|
||||
<Item Condition="!obj && (int)p->kind == 3">{{ doc }}->base._Elems[p->flags & 3] + p->off,[p->len]s8</Item>
|
||||
{% endif %}
|
||||
<Item Condition="!obj{% if doc %} && (int)p->kind != 3{% endif %}">*p</Item>
|
||||
<Exec>p = p + (((int)p->kind == 1 || (int)p->kind == 2) ? p->next : 1)</Exec>
|
||||
<Exec>i = i + 1</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
{%- endmacro %}
|
||||
{% for ns in namespaces %}
|
||||
<!-- Namespace {{ ns }} -->
|
||||
<Type Name="{{ ns }}::basic_json<*>">
|
||||
@@ -95,44 +62,5 @@
|
||||
</Type>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
<!-- json_view / json_document (include/nlohmann/json_view.hpp). They live in the same inline namespaces as
|
||||
basic_json, so the ABI tags need no extra entries; the view_mode is a template argument that the wildcard
|
||||
covers. A view is a pointer to the document's data and a pointer to a node of its flat index; the
|
||||
strings of the source are found through document_data::base (std::array of the MSVC STL: _Elems). -->
|
||||
<Type Name="{{ ns }}::detail::view::node">
|
||||
<DisplayString Condition="(int)kind == 0">null</DisplayString>
|
||||
<DisplayString Condition="(int)kind == 1">object, size={len}</DisplayString>
|
||||
<DisplayString Condition="(int)kind == 2">array, size={len}</DisplayString>
|
||||
<DisplayString Condition="(int)kind == 3">string, length={len}</DisplayString>
|
||||
<DisplayString Condition="(int)kind == 4">boolean: {(flags & 4) != 0}</DisplayString>
|
||||
<DisplayString Condition="(int)kind == 5">int64: {(__int64)((unsigned __int64)len | ((unsigned __int64)next << 32))}</DisplayString>
|
||||
<DisplayString Condition="(int)kind == 6">uint64: {(unsigned __int64)len | ((unsigned __int64)next << 32)}</DisplayString>
|
||||
<DisplayString Condition="(int)kind == 7">float, length={len}</DisplayString>
|
||||
<DisplayString>link</DisplayString>
|
||||
<Expand>
|
||||
{{ children('this') }}
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="{{ ns }}::basic_json_view<*,*>">
|
||||
<DisplayString Condition="m_node == 0">discarded</DisplayString>
|
||||
<DisplayString Condition="(int)m_node->kind == 3">{m_doc->base._Elems[m_node->flags & 3] + m_node->off,[m_node->len]s8}</DisplayString>
|
||||
<DisplayString Condition="(int)m_node->kind == 7">{m_doc->base._Elems[m_node->flags & 3] + m_node->off,[m_node->len]s8b}</DisplayString>
|
||||
<DisplayString>{*m_node}</DisplayString>
|
||||
<Expand>
|
||||
{{ children('m_node', 'm_doc') }}
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="{{ ns }}::basic_json_document<*,*>">
|
||||
<DisplayString Condition="m_data._Mypair._Myval2 == 0 || m_data._Mypair._Myval2->discarded">discarded</DisplayString>
|
||||
<DisplayString>{*m_data._Mypair._Myval2->nodes}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[source]" Condition="m_data._Mypair._Myval2 != 0">m_data._Mypair._Myval2->src,[m_data._Mypair._Myval2->size]s8b</Item>
|
||||
<Item Name="[nodes]" Condition="m_data._Mypair._Myval2 != 0">m_data._Mypair._Myval2->node_count</Item>
|
||||
{{ children('m_data._Mypair._Myval2->nodes', 'm_data._Mypair._Myval2') }}
|
||||
</Expand>
|
||||
</Type>
|
||||
{% endfor %}
|
||||
</AutoVisualizer>
|
||||
Reference in new issue
Block a user