cfengine 0.16.7__tar.gz → 0.18.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cfengine-0.16.7 → cfengine-0.18.0}/.github/workflows/update-syntax-description.yml +2 -1
- {cfengine-0.16.7 → cfengine-0.18.0}/PKG-INFO +1 -1
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine.egg-info/PKG-INFO +1 -1
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine.egg-info/SOURCES.txt +2 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine.egg-info/scm_file_list.json +2 -0
- cfengine-0.18.0/src/cfengine.egg-info/scm_version.json +8 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/commands.py +5 -5
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/docs.py +21 -9
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/format.py +126 -34
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/lint.py +11 -5
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/main.py +10 -1
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/syntax-description.json +17 -3
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/004_comments.expected.cf +3 -6
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/005_bundle_comments.expected.cf +1 -2
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/010_stakeholder.expected.cf +2 -4
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/011_promises.expected.cf +5 -14
- cfengine-0.18.0/tests/format/012_sameline_comments.expected.cf +25 -0
- cfengine-0.18.0/tests/format/012_sameline_comments.input.cf +23 -0
- cfengine-0.16.7/src/cfengine.egg-info/scm_version.json +0 -8
- {cfengine-0.16.7 → cfengine-0.18.0}/.github/dependabot.yml +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/.github/workflows/lint-policy-in-other-repos.yml +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/.github/workflows/make-check.yml +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/.github/workflows/pypi-publish.yml +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/.github/workflows/stale.yml +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/.gitignore +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/.python-version +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/CLAUDE.md +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/HACKING.md +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/LICENSE +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/Makefile +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/README.md +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/ci/01-install.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/ci/02-safe-tests.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/ci/03-unsafe-tests.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/pyproject.toml +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/setup.cfg +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine.egg-info/dependency_links.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine.egg-info/entry_points.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine.egg-info/requires.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine.egg-info/top_level.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/__init__.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/__main__.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/changelog.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/deptool-README.md +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/deptool.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/dev.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/lint_csv.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/lint_yml.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/__init__.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/analyze.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/check_download_matches_git.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/download.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/generate_git_tags.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/generate_release_information.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/generate_vcf_download.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/paths.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/profile.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/shell.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/syntax_tree.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/up.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/utils.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/validate.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/src/cfengine_cli/version.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/README.md +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/001_hello_world.expected.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/001_hello_world.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/002_basics.expected.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/002_basics.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/003_wrapping.expected.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/003_wrapping.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/004_comments.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/005_bundle_comments.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/006_remove_empty_comments.expected.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/006_remove_empty_comments.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/007_class_guarded_empty_lines.expected.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/007_class_guarded_empty_lines.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/008_long_string.expected.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/008_long_string.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/009_single_line.expected.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/009_single_line.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/010_stakeholder.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/011_macros.expected.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/011_macros.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/format/011_promises.input.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/001_hello_world.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/002_deprecations.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/002_deprecations.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/003_name_lowercase.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/003_name_lowercase.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/003_name_lowercase.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/004_block_type.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/004_block_type.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/004_block_type.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/005_syntax_error.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/005_syntax_error.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/005_syntax_error.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/006_empty_file.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/006_empty_file.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/007_namespace.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/007_namespace.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/007_namespace.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/008_bundle_shadows_function.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/008_bundle_shadows_function.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/008_bundle_shadows_function.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/009_unknown_function_inside_vars.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/009_unknown_function_inside_vars.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/009_unknown_function_inside_vars.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/010_mutually_exclusive_types_vars.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/010_mutually_exclusive_types_vars.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/010_mutually_exclusive_types_vars.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/011_invalid_attributes.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/011_invalid_attributes.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/012_function_call_arg_count.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/012_function_call_arg_count.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/012_function_call_arg_count.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/013_num_args_body.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/013_num_args_body.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/013_num_args_bundle.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/013_num_args_bundle.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/013_num_args_bundle_body.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/014_variadic_func_arg_count.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/014_variadic_func_arg_count.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/014_variadic_func_arg_count.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/015_macro_multi_def_bundle.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/015_macro_multi_def_bundle.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/015_macro_multi_def_bundle.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/016_half_promises.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/016_half_promises.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/016_half_promises.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/017_implies_body.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/017_implies_body.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/017_implies_body.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/018_nested_calls.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/018_nested_calls.expected.txt +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/018_nested_calls.x.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/lint/019_bundle_name_expansion.cf +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/run-format-tests.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/run-lint-tests.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/run-shell-tests.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/run-up-validate-tests.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/shell/001-help.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/shell/002-version.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/shell/003-format.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/shell/004-format-check.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/shell/005-lint.sh +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/unit/__init__.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/unit/test_changelog.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/unit/test_deps.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/unit/test_format.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/unit/test_lint_csv.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/unit/test_lint_yml.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/unit/test_paths.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/unit/test_utils.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/unit/test_version.py +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/up-validate/001_complex_config.yaml +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/up-validate/002_version.x.yaml +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/up-validate/003_box.x.yaml +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/up-validate/004_count.x.yaml +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/up-validate/mocks/cloud_config.json +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/tests/up-validate/mocks/vagrant +0 -0
- {cfengine-0.16.7 → cfengine-0.18.0}/uv.lock +0 -0
|
@@ -55,8 +55,9 @@ jobs:
|
|
|
55
55
|
fi
|
|
56
56
|
- name: Create Pull Request
|
|
57
57
|
if: env.CHANGES_DETECTED == 'true'
|
|
58
|
-
uses: cfengine/create-pull-request@
|
|
58
|
+
uses: cfengine/create-pull-request@v7
|
|
59
59
|
with:
|
|
60
|
+
sign-commits: true
|
|
60
61
|
title: Updated syntax-description.json
|
|
61
62
|
body: Automated update to syntax-description.json [the `update-syntax-description` workflow](https://github.com/cfengine/cfengine-cli/tree/main/.github/workflows/update-syntax-description.yml).
|
|
62
63
|
reviewers: |
|
|
@@ -83,6 +83,8 @@ tests/format/011_macros.expected.cf
|
|
|
83
83
|
tests/format/011_macros.input.cf
|
|
84
84
|
tests/format/011_promises.expected.cf
|
|
85
85
|
tests/format/011_promises.input.cf
|
|
86
|
+
tests/format/012_sameline_comments.expected.cf
|
|
87
|
+
tests/format/012_sameline_comments.input.cf
|
|
86
88
|
tests/lint/001_hello_world.cf
|
|
87
89
|
tests/lint/002_deprecations.expected.txt
|
|
88
90
|
tests/lint/002_deprecations.x.cf
|
|
@@ -130,9 +130,11 @@
|
|
|
130
130
|
"tests/format/004_comments.input.cf",
|
|
131
131
|
"tests/format/001_hello_world.expected.cf",
|
|
132
132
|
"tests/format/011_promises.input.cf",
|
|
133
|
+
"tests/format/012_sameline_comments.expected.cf",
|
|
133
134
|
"tests/format/008_long_string.expected.cf",
|
|
134
135
|
"tests/format/008_long_string.input.cf",
|
|
135
136
|
"tests/format/002_basics.input.cf",
|
|
137
|
+
"tests/format/012_sameline_comments.input.cf",
|
|
136
138
|
"tests/format/011_macros.input.cf",
|
|
137
139
|
"tests/unit/__init__.py",
|
|
138
140
|
"tests/unit/test_version.py",
|
|
@@ -52,14 +52,14 @@ def format(names, line_length, check) -> int:
|
|
|
52
52
|
return format_paths(names, line_length, check)
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
def _lint(files, strict) -> int:
|
|
55
|
+
def _lint(files, strict, syntax_path) -> int:
|
|
56
56
|
if not files:
|
|
57
|
-
return lint_args(["."], strict)
|
|
58
|
-
return lint_args(files, strict)
|
|
57
|
+
return lint_args(["."], strict, syntax_path)
|
|
58
|
+
return lint_args(files, strict, syntax_path)
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
def lint(files, strict) -> int:
|
|
62
|
-
errors = _lint(files, strict)
|
|
61
|
+
def lint(files, strict, syntax_path) -> int:
|
|
62
|
+
errors = _lint(files, strict, syntax_path)
|
|
63
63
|
if errors == 0:
|
|
64
64
|
print("Success, no errors found.")
|
|
65
65
|
elif errors == 1:
|
|
@@ -61,15 +61,16 @@ def extract_inline_code(path, languages):
|
|
|
61
61
|
indent = count_indent(lines[first_line])
|
|
62
62
|
# Index of first line to NOT include, the line after closing triple backtick:
|
|
63
63
|
last_line = child.map[1]
|
|
64
|
+
lines_to_extract = lines[first_line:last_line]
|
|
65
|
+
_remove_indentation(lines_to_extract, indent)
|
|
64
66
|
yield {
|
|
65
67
|
"language": language,
|
|
66
68
|
"flags": flags,
|
|
67
69
|
"first_line": child.map[0],
|
|
68
70
|
"last_line": child.map[1],
|
|
69
71
|
"indent": indent,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
], # Includes backtick fences on both sides
|
|
72
|
+
# TODO: Dead code, the actual lines are extracted "twice" (2 places in the codebase)
|
|
73
|
+
"lines": lines_to_extract, # Includes backtick fences on both sides
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
|
|
@@ -97,12 +98,24 @@ def get_markdown_files(start, languages):
|
|
|
97
98
|
return return_dict
|
|
98
99
|
|
|
99
100
|
|
|
101
|
+
def _remove_indentation(snippet_lines, indent):
|
|
102
|
+
for i, line in enumerate(snippet_lines):
|
|
103
|
+
if line == "":
|
|
104
|
+
continue
|
|
105
|
+
assert line.startswith(" " * indent)
|
|
106
|
+
snippet_lines[i] = line[indent:]
|
|
107
|
+
|
|
108
|
+
|
|
100
109
|
def fn_extract(origin_path, snippet_path, _language, first_line, last_line):
|
|
101
110
|
try:
|
|
102
111
|
with open(origin_path, "r") as f:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
112
|
+
lines = f.readlines()
|
|
113
|
+
lines = [x[0:-1] for x in lines] # Remove newlines
|
|
114
|
+
fence = lines[first_line]
|
|
115
|
+
indent = count_indent(fence)
|
|
116
|
+
snippet_lines = lines[first_line + 1 : last_line - 1]
|
|
117
|
+
_remove_indentation(snippet_lines, indent)
|
|
118
|
+
code_snippet = "\n".join(snippet_lines)
|
|
106
119
|
|
|
107
120
|
with open(snippet_path, "w") as f:
|
|
108
121
|
f.write(code_snippet + "\n")
|
|
@@ -174,7 +187,7 @@ def fn_replace(origin_path, snippet_path, _language, first_line, last_line, inde
|
|
|
174
187
|
origin_lines = f.read().split("\n")
|
|
175
188
|
pretty_lines = pretty_content.split("\n")
|
|
176
189
|
|
|
177
|
-
pretty_lines = [" " * indent + x for x in pretty_lines]
|
|
190
|
+
pretty_lines = ["" if x == "" else " " * indent + x for x in pretty_lines]
|
|
178
191
|
|
|
179
192
|
offset = len(pretty_lines) - len(
|
|
180
193
|
origin_lines[first_line + 1 : last_line - 1]
|
|
@@ -213,7 +226,6 @@ def fn_autoformat(
|
|
|
213
226
|
except json.decoder.JSONDecodeError:
|
|
214
227
|
raise UserError(f"Invalid json in '{snippet_path}'")
|
|
215
228
|
case "cf":
|
|
216
|
-
# Note: Dead code - Not used for CFEngine policy yet
|
|
217
229
|
format_policy_file(snippet_path, 80, False)
|
|
218
230
|
return False
|
|
219
231
|
|
|
@@ -434,7 +446,7 @@ def _format_docs_single_arg(path):
|
|
|
434
446
|
formatted = True
|
|
435
447
|
_process_markdown_code_blocks(
|
|
436
448
|
path=path,
|
|
437
|
-
languages=["json"
|
|
449
|
+
languages=["json", "cfengine3"],
|
|
438
450
|
extract=True,
|
|
439
451
|
syntax_check=False,
|
|
440
452
|
output_check=False,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from enum import IntEnum
|
|
3
4
|
from typing import IO
|
|
4
5
|
|
|
5
6
|
import json
|
|
@@ -35,6 +36,16 @@ BLOCK_BODY_TYPES = {"bundle_block_body", "promise_block_body", "body_block_body"
|
|
|
35
36
|
|
|
36
37
|
PROMISER_PARTS = {"promiser", "->", "stakeholder"}
|
|
37
38
|
|
|
39
|
+
SAMELINE_COMMENT_SEPARATOR = " "
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class FormatResult(IntEnum):
|
|
43
|
+
"""Outcome of a formatting operation."""
|
|
44
|
+
|
|
45
|
+
NO_CHANGE = 0 # File was already formatted, no reformat needed
|
|
46
|
+
NEEDS_FORMAT = 1 # Reformat needed (reported in check mode)
|
|
47
|
+
REFORMATTED = 2 # File was reformatted successfully
|
|
48
|
+
|
|
38
49
|
|
|
39
50
|
def _has_direct_macro(node: Node) -> bool:
|
|
40
51
|
"""Check if any direct child of a node is a macro (non-recursive)."""
|
|
@@ -62,12 +73,8 @@ def _contains_list_with_comment(nodes: Node | list[Node]) -> bool:
|
|
|
62
73
|
return _contains_list_with_comment(nodes.children)
|
|
63
74
|
|
|
64
75
|
|
|
65
|
-
def format_json_file(filename: str, check: bool) ->
|
|
66
|
-
"""Reformat a JSON file in place using cfbs pretty-printer.
|
|
67
|
-
|
|
68
|
-
Returns 0 in case of successful reformat or no reformat needed.
|
|
69
|
-
Returns 1 when check is True and reformat is needed.
|
|
70
|
-
"""
|
|
76
|
+
def format_json_file(filename: str, check: bool) -> FormatResult:
|
|
77
|
+
"""Reformat a JSON file in place using cfbs pretty-printer."""
|
|
71
78
|
assert filename.endswith(".json")
|
|
72
79
|
|
|
73
80
|
if check:
|
|
@@ -76,16 +83,17 @@ def format_json_file(filename: str, check: bool) -> int:
|
|
|
76
83
|
assert type(success) is bool
|
|
77
84
|
if not success:
|
|
78
85
|
print(f"JSON file '{filename}' needs reformatting")
|
|
79
|
-
|
|
86
|
+
return FormatResult.NEEDS_FORMAT
|
|
87
|
+
return FormatResult.NO_CHANGE
|
|
80
88
|
|
|
81
89
|
try:
|
|
82
90
|
reformatted = pretty_file(filename)
|
|
83
91
|
if reformatted:
|
|
84
92
|
print(f"JSON file '{filename}' was reformatted")
|
|
85
|
-
|
|
93
|
+
return FormatResult.REFORMATTED
|
|
94
|
+
return FormatResult.NO_CHANGE
|
|
86
95
|
except json.decoder.JSONDecodeError as e:
|
|
87
|
-
|
|
88
|
-
return 1
|
|
96
|
+
raise UserError(f"JSON file '{filename}' invalid ({str(e)})")
|
|
89
97
|
|
|
90
98
|
|
|
91
99
|
def text(node: Node) -> str:
|
|
@@ -241,6 +249,9 @@ def split_generic_list(
|
|
|
241
249
|
# outside the function call, so we do not add trailing commas into function
|
|
242
250
|
# call argument lists.
|
|
243
251
|
value_end_indices: list[int] = []
|
|
252
|
+
# Same-line (trailing) comments are attached only after trailing commas are
|
|
253
|
+
# placed, so the comma lands before the comment instead of after it.
|
|
254
|
+
sameline_comments: dict[int, str] = {}
|
|
244
255
|
for element in middle:
|
|
245
256
|
if elements and element.type == ",":
|
|
246
257
|
elements[-1] = elements[-1] + ","
|
|
@@ -249,7 +260,10 @@ def split_generic_list(
|
|
|
249
260
|
elements.append(text(element))
|
|
250
261
|
continue
|
|
251
262
|
if element.type == "comment":
|
|
252
|
-
|
|
263
|
+
if _is_sameline_comment(element) and elements:
|
|
264
|
+
sameline_comments[len(elements) - 1] = text(element)
|
|
265
|
+
else:
|
|
266
|
+
elements.append(" " * indent + text(element))
|
|
253
267
|
continue
|
|
254
268
|
line = " " * indent + stringify_single_line_node(element)
|
|
255
269
|
# Strict < reserves 1 char for the comma appended after this check
|
|
@@ -275,6 +289,10 @@ def split_generic_list(
|
|
|
275
289
|
if not elements[i].lstrip().startswith("#"):
|
|
276
290
|
elements[i] = _set_trailing_comma(elements[i], trailing_comma)
|
|
277
291
|
break
|
|
292
|
+
|
|
293
|
+
# Attach same-line comments to the end of their value lines
|
|
294
|
+
for i, comment in sameline_comments.items():
|
|
295
|
+
elements[i] = elements[i] + SAMELINE_COMMENT_SEPARATOR + comment
|
|
278
296
|
return elements
|
|
279
297
|
|
|
280
298
|
|
|
@@ -354,7 +372,10 @@ def _format_attribute_with_macros(node: Node, indent: int) -> list[str]:
|
|
|
354
372
|
if child.type == "macro":
|
|
355
373
|
lines.append(text(child))
|
|
356
374
|
elif child.type == "comment":
|
|
357
|
-
|
|
375
|
+
if _is_sameline_comment(child) and lines:
|
|
376
|
+
lines[-1] = lines[-1] + SAMELINE_COMMENT_SEPARATOR + text(child)
|
|
377
|
+
else:
|
|
378
|
+
lines.append(" " * (indent + 2) + text(child))
|
|
358
379
|
else:
|
|
359
380
|
lines.append(" " * (indent + 2) + stringify_single_line_node(child))
|
|
360
381
|
|
|
@@ -505,13 +526,19 @@ def _format_stakeholder_elements(
|
|
|
505
526
|
return maybe_split_generic_list(middle, indent, line_length)
|
|
506
527
|
# Comments present — format element-by-element to preserve them
|
|
507
528
|
elements: list[str] = []
|
|
529
|
+
# Same-line (trailing) comments are attached only after the trailing comma is
|
|
530
|
+
# placed, so the comma lands before the comment instead of after it.
|
|
531
|
+
sameline_comments: dict[int, str] = {}
|
|
508
532
|
for node in middle:
|
|
509
533
|
if node.type == ",":
|
|
510
534
|
if elements:
|
|
511
535
|
elements[-1] = elements[-1] + ","
|
|
512
536
|
continue
|
|
513
537
|
if node.type == "comment":
|
|
514
|
-
|
|
538
|
+
if _is_sameline_comment(node) and elements:
|
|
539
|
+
sameline_comments[len(elements) - 1] = text(node)
|
|
540
|
+
else:
|
|
541
|
+
elements.append(" " * indent + text(node))
|
|
515
542
|
else:
|
|
516
543
|
line = " " * indent + stringify_single_line_node(node)
|
|
517
544
|
# Strict < reserves 1 char for the comma appended after this check
|
|
@@ -528,6 +555,10 @@ def _format_stakeholder_elements(
|
|
|
528
555
|
if not elements[i].endswith(","):
|
|
529
556
|
elements[i] = elements[i] + ","
|
|
530
557
|
break
|
|
558
|
+
|
|
559
|
+
# Attach inline comments to the end of their value lines
|
|
560
|
+
for i, comment in sameline_comments.items():
|
|
561
|
+
elements[i] = elements[i] + SAMELINE_COMMENT_SEPARATOR + comment
|
|
531
562
|
return elements
|
|
532
563
|
|
|
533
564
|
|
|
@@ -682,9 +713,13 @@ def _format_block_header(node: Node, fmt: Formatter) -> list[Node]:
|
|
|
682
713
|
"""Format a block header line and return the body's children for further processing."""
|
|
683
714
|
header_parts: list[str] = []
|
|
684
715
|
header_comments: list[str] = []
|
|
716
|
+
# Direct comment children of the block (excludes comments inside a
|
|
717
|
+
# parameter list) — candidates for being kept on the header line.
|
|
718
|
+
direct_comments: list[Node] = []
|
|
685
719
|
for x in node.children[0:-1]:
|
|
686
720
|
if x.type == "comment":
|
|
687
721
|
header_comments.append(text(x))
|
|
722
|
+
direct_comments.append(x)
|
|
688
723
|
elif x.type == "parameter_list":
|
|
689
724
|
parts: list[str] = []
|
|
690
725
|
for p in x.children:
|
|
@@ -696,6 +731,16 @@ def _format_block_header(node: Node, fmt: Formatter) -> list[Node]:
|
|
|
696
731
|
else:
|
|
697
732
|
header_parts.append(text(x))
|
|
698
733
|
line = " ".join(header_parts)
|
|
734
|
+
# A lone same-line comment stays on the header line. When the header has
|
|
735
|
+
# more than one comment, keep them together on their own lines below the
|
|
736
|
+
# header instead of splitting one off onto the header line.
|
|
737
|
+
if (
|
|
738
|
+
len(header_comments) == 1
|
|
739
|
+
and len(direct_comments) == 1
|
|
740
|
+
and _is_sameline_comment(direct_comments[0])
|
|
741
|
+
):
|
|
742
|
+
line += SAMELINE_COMMENT_SEPARATOR + header_comments[0]
|
|
743
|
+
header_comments = []
|
|
699
744
|
if not fmt.empty:
|
|
700
745
|
prev_sib = node.prev_named_sibling
|
|
701
746
|
# Skip over preceding empty comments since they will be removed
|
|
@@ -725,6 +770,11 @@ def _format_block_header(node: Node, fmt: Formatter) -> list[Node]:
|
|
|
725
770
|
|
|
726
771
|
def _needs_blank_line_before(child: Node, indent: int, line_length: int) -> bool:
|
|
727
772
|
"""Check if a blank separator line should precede this child node."""
|
|
773
|
+
# Inline (trailing) comments are appended to the preceding line, so they
|
|
774
|
+
# must never be preceded by a blank separator line.
|
|
775
|
+
if child.type == "comment" and _is_sameline_comment(child):
|
|
776
|
+
return False
|
|
777
|
+
|
|
728
778
|
prev = child.prev_named_sibling
|
|
729
779
|
# Empty comments preceding this child will be dropped — look past them
|
|
730
780
|
# so we evaluate against the real prior content.
|
|
@@ -798,6 +848,21 @@ def _needs_blank_line_before(child: Node, indent: int, line_length: int) -> bool
|
|
|
798
848
|
# ---------------------------------------------------------------------------
|
|
799
849
|
|
|
800
850
|
|
|
851
|
+
def _is_sameline_comment(node: Node) -> bool:
|
|
852
|
+
"""Check if a comment sits on the same source line as the element before it.
|
|
853
|
+
|
|
854
|
+
A trailing comment shares the row of the preceding sibling (which may be
|
|
855
|
+
a leaf like ',' or ';', or a whole promise/attribute). Such comments are
|
|
856
|
+
kept on the same output line as that element rather than moved to their
|
|
857
|
+
own line."""
|
|
858
|
+
if node.type != "comment":
|
|
859
|
+
return False
|
|
860
|
+
prev = node.prev_sibling
|
|
861
|
+
if prev is None:
|
|
862
|
+
return False
|
|
863
|
+
return prev.end_point[0] == node.start_point[0]
|
|
864
|
+
|
|
865
|
+
|
|
801
866
|
def _is_empty_comment(node: Node) -> bool:
|
|
802
867
|
"""Check if a bare '#' comment should be dropped.
|
|
803
868
|
|
|
@@ -934,7 +999,11 @@ def _autoformat(
|
|
|
934
999
|
else:
|
|
935
1000
|
fmt.print_same_line(node)
|
|
936
1001
|
elif node.type == "comment":
|
|
937
|
-
if
|
|
1002
|
+
if _is_empty_comment(node):
|
|
1003
|
+
pass
|
|
1004
|
+
elif _is_sameline_comment(node) and not fmt.empty:
|
|
1005
|
+
fmt.print_same_line(SAMELINE_COMMENT_SEPARATOR + text(node))
|
|
1006
|
+
else:
|
|
938
1007
|
fmt.print(node, _comment_indent(node, indent))
|
|
939
1008
|
else:
|
|
940
1009
|
fmt.print(node, indent)
|
|
@@ -945,11 +1014,9 @@ def _autoformat(
|
|
|
945
1014
|
# ---------------------------------------------------------------------------
|
|
946
1015
|
|
|
947
1016
|
|
|
948
|
-
def format_policy_file(filename: str, line_length: int, check: bool) ->
|
|
1017
|
+
def format_policy_file(filename: str, line_length: int, check: bool) -> FormatResult:
|
|
949
1018
|
"""Format a .cf policy file in place, writing only if content changed.
|
|
950
1019
|
|
|
951
|
-
Returns 0 in case of successful reformat or no reformat needed.
|
|
952
|
-
Returns 1 when check is True and reformat is needed.
|
|
953
1020
|
Raises PolicySyntaxError when the file has syntax errors."""
|
|
954
1021
|
assert filename.endswith(".cf")
|
|
955
1022
|
|
|
@@ -968,21 +1035,28 @@ def format_policy_file(filename: str, line_length: int, check: bool) -> int:
|
|
|
968
1035
|
fmt = Formatter()
|
|
969
1036
|
_autoformat(root_node, fmt, line_length)
|
|
970
1037
|
|
|
971
|
-
new_data = fmt.buffer
|
|
1038
|
+
new_data = fmt.buffer
|
|
1039
|
+
if not new_data.endswith("\n"):
|
|
1040
|
+
# TODO: Look into why formatter sometimes outputs
|
|
1041
|
+
# trailing newline and other times not.
|
|
1042
|
+
new_data += "\n"
|
|
1043
|
+
assert new_data.endswith("\n") and not new_data.endswith("\n\n")
|
|
1044
|
+
|
|
972
1045
|
if new_data != original_data.decode("utf-8"):
|
|
973
1046
|
if check:
|
|
974
1047
|
print(f"Policy file '{filename}' needs reformatting")
|
|
975
|
-
return
|
|
1048
|
+
return FormatResult.NEEDS_FORMAT
|
|
976
1049
|
|
|
977
1050
|
with open(filename, "w") as f:
|
|
978
1051
|
f.write(new_data)
|
|
979
1052
|
print(f"Policy file '{filename}' was reformatted")
|
|
980
|
-
|
|
1053
|
+
return FormatResult.REFORMATTED
|
|
1054
|
+
return FormatResult.NO_CHANGE
|
|
981
1055
|
|
|
982
1056
|
|
|
983
1057
|
def format_policy_fin_fout(
|
|
984
1058
|
fin: IO[str], fout: IO[str], line_length: int, check: bool
|
|
985
|
-
) ->
|
|
1059
|
+
) -> FormatResult:
|
|
986
1060
|
"""Format CFEngine policy read from fin, writing the result to fout.
|
|
987
1061
|
|
|
988
1062
|
Raises PolicySyntaxError when the input has syntax errors."""
|
|
@@ -1002,10 +1076,12 @@ def format_policy_fin_fout(
|
|
|
1002
1076
|
|
|
1003
1077
|
new_data = fmt.buffer + "\n"
|
|
1004
1078
|
fout.write(new_data)
|
|
1005
|
-
|
|
1079
|
+
if new_data != original_data.decode("utf-8"):
|
|
1080
|
+
return FormatResult.REFORMATTED
|
|
1081
|
+
return FormatResult.NO_CHANGE
|
|
1006
1082
|
|
|
1007
1083
|
|
|
1008
|
-
def _format_filename(filename: str, line_length: int, check: bool) ->
|
|
1084
|
+
def _format_filename(filename: str, line_length: int, check: bool) -> FormatResult:
|
|
1009
1085
|
"""Format a single file.
|
|
1010
1086
|
|
|
1011
1087
|
Raises PolicySyntaxError for .cf files with syntax errors."""
|
|
@@ -1016,8 +1092,17 @@ def _format_filename(filename: str, line_length: int, check: bool) -> int:
|
|
|
1016
1092
|
raise UserError(f"Unrecognized file format: {filename}")
|
|
1017
1093
|
|
|
1018
1094
|
|
|
1019
|
-
def
|
|
1020
|
-
|
|
1095
|
+
def _combine_results(a: FormatResult, b: FormatResult) -> FormatResult:
|
|
1096
|
+
"""Combine two format results. A non-NO_CHANGE result takes precedence.
|
|
1097
|
+
|
|
1098
|
+
Within a single format run, `check` is fixed, so NEEDS_FORMAT and
|
|
1099
|
+
REFORMATTED never occur together — one always dominates NO_CHANGE."""
|
|
1100
|
+
return b if b != FormatResult.NO_CHANGE else a
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
def _format_dirname(directory: str, line_length: int, check: bool) -> FormatResult:
|
|
1104
|
+
"""Format files in directory recursively."""
|
|
1105
|
+
ret = FormatResult.NO_CHANGE
|
|
1021
1106
|
for root, dirs, files in os.walk(directory):
|
|
1022
1107
|
# Don't recurse into hidden folders
|
|
1023
1108
|
dirs[:] = [d for d in dirs if not d.startswith(".")]
|
|
@@ -1037,18 +1122,20 @@ def _format_dirname(directory: str, line_length: int, check: bool) -> int:
|
|
|
1037
1122
|
continue # Test files skipped during directory traversal
|
|
1038
1123
|
filepath = os.path.join(root, name)
|
|
1039
1124
|
if name.endswith(".json") or name.endswith(".cf"):
|
|
1040
|
-
ret
|
|
1125
|
+
ret = _combine_results(
|
|
1126
|
+
ret, _format_filename(filepath, line_length, check)
|
|
1127
|
+
)
|
|
1041
1128
|
return ret
|
|
1042
1129
|
|
|
1043
1130
|
|
|
1044
|
-
def _format_paths_inner(names, line_length, check) ->
|
|
1131
|
+
def _format_paths_inner(names, line_length, check) -> FormatResult:
|
|
1045
1132
|
if not names:
|
|
1046
1133
|
return _format_dirname(".", line_length, check)
|
|
1047
1134
|
if len(names) == 1 and names[0] == "-":
|
|
1048
1135
|
# Special case, format policy file from stdin to stdout
|
|
1049
1136
|
return format_policy_fin_fout(sys.stdin, sys.stdout, line_length, check)
|
|
1050
1137
|
|
|
1051
|
-
ret =
|
|
1138
|
+
ret = FormatResult.NO_CHANGE
|
|
1052
1139
|
for name in names:
|
|
1053
1140
|
if name == "-":
|
|
1054
1141
|
raise UserError(
|
|
@@ -1057,14 +1144,12 @@ def _format_paths_inner(names, line_length, check) -> int:
|
|
|
1057
1144
|
if not os.path.exists(name):
|
|
1058
1145
|
raise UserError(f"{name} does not exist")
|
|
1059
1146
|
if os.path.isfile(name):
|
|
1060
|
-
ret
|
|
1147
|
+
ret = _combine_results(ret, _format_filename(name, line_length, check))
|
|
1061
1148
|
continue
|
|
1062
1149
|
if os.path.isdir(name):
|
|
1063
|
-
ret
|
|
1150
|
+
ret = _combine_results(ret, _format_dirname(name, line_length, check))
|
|
1064
1151
|
continue
|
|
1065
|
-
|
|
1066
|
-
return ret
|
|
1067
|
-
return 0
|
|
1152
|
+
return ret
|
|
1068
1153
|
|
|
1069
1154
|
|
|
1070
1155
|
def format_paths(names, line_length, check) -> int:
|
|
@@ -1075,7 +1160,14 @@ def format_paths(names, line_length, check) -> int:
|
|
|
1075
1160
|
needed), 1 when reformatting is needed in check mode or a policy file
|
|
1076
1161
|
has syntax errors."""
|
|
1077
1162
|
try:
|
|
1078
|
-
|
|
1163
|
+
r = _format_paths_inner(names, line_length, check)
|
|
1164
|
+
if r == FormatResult.NEEDS_FORMAT:
|
|
1165
|
+
assert check
|
|
1166
|
+
# File needs reformatting
|
|
1167
|
+
return 1
|
|
1168
|
+
assert r in (FormatResult.NO_CHANGE, FormatResult.REFORMATTED)
|
|
1169
|
+
# Success - no format needed or successfully reformatted
|
|
1170
|
+
return 0
|
|
1079
1171
|
except PolicySyntaxError as e:
|
|
1080
1172
|
print(f"Error: {e}")
|
|
1081
1173
|
return 1
|
|
@@ -81,9 +81,9 @@ class SyntaxData:
|
|
|
81
81
|
BUILTIN_PROMISE_TYPES = {}
|
|
82
82
|
BUILTIN_FUNCTIONS = {}
|
|
83
83
|
|
|
84
|
-
def __init__(self):
|
|
84
|
+
def __init__(self, syntax_path=None):
|
|
85
85
|
"""Load the bundled syntax-description.json and derive lookup dicts."""
|
|
86
|
-
self._data_dict = self._load_syntax_description()
|
|
86
|
+
self._data_dict = self._load_syntax_description(path=syntax_path)
|
|
87
87
|
self._derive_syntax_dicts(self._data_dict)
|
|
88
88
|
|
|
89
89
|
assert self.BUILTIN_BODY_TYPES
|
|
@@ -1100,6 +1100,7 @@ def _lint_main(
|
|
|
1100
1100
|
state=None,
|
|
1101
1101
|
snippet: Snippet | None = None,
|
|
1102
1102
|
syntax_data=None,
|
|
1103
|
+
syntax_path: str | None = None,
|
|
1103
1104
|
) -> int:
|
|
1104
1105
|
"""This is the main function used for linting, it does all the steps on all
|
|
1105
1106
|
the arguments (files / folders).
|
|
@@ -1127,7 +1128,10 @@ def _lint_main(
|
|
|
1127
1128
|
state.mode = Mode.SYNTAX
|
|
1128
1129
|
|
|
1129
1130
|
if syntax_data is None:
|
|
1130
|
-
|
|
1131
|
+
try:
|
|
1132
|
+
syntax_data = SyntaxData(syntax_path)
|
|
1133
|
+
except FileNotFoundError:
|
|
1134
|
+
raise UserError(f"'{syntax_path}' does not exist")
|
|
1131
1135
|
|
|
1132
1136
|
filenames = _args_to_filenames(args)
|
|
1133
1137
|
|
|
@@ -1379,9 +1383,11 @@ def lint_single_file(file: str, strict: bool = True) -> int:
|
|
|
1379
1383
|
return _lint_main([file], strict)
|
|
1380
1384
|
|
|
1381
1385
|
|
|
1382
|
-
def lint_args(
|
|
1386
|
+
def lint_args(
|
|
1387
|
+
args: Iterable[str], strict: bool = True, syntax_path: str | None = None
|
|
1388
|
+
) -> int:
|
|
1383
1389
|
"""Lint a list of args (files / folders)"""
|
|
1384
|
-
return _lint_main(list(args), strict)
|
|
1390
|
+
return _lint_main(list(args), strict, syntax_path=syntax_path)
|
|
1385
1391
|
|
|
1386
1392
|
|
|
1387
1393
|
def lint_policy_file_snippet(
|
|
@@ -59,6 +59,11 @@ def _get_arg_parser():
|
|
|
59
59
|
default="yes",
|
|
60
60
|
help="Strict mode. Default=yes, checks for undefined promise types, bundles, bodies, functions",
|
|
61
61
|
)
|
|
62
|
+
lnt.add_argument(
|
|
63
|
+
"--syntax-description",
|
|
64
|
+
type=str,
|
|
65
|
+
help="Lint based on a user given syntax description",
|
|
66
|
+
)
|
|
62
67
|
lnt.add_argument("files", nargs="*", help="Files to lint")
|
|
63
68
|
subp.add_parser(
|
|
64
69
|
"report",
|
|
@@ -188,7 +193,11 @@ def run_command_with_args(args) -> int:
|
|
|
188
193
|
if args.command == "format":
|
|
189
194
|
return commands.format(args.files, args.line_length, args.check)
|
|
190
195
|
if args.command == "lint":
|
|
191
|
-
return commands.lint(
|
|
196
|
+
return commands.lint(
|
|
197
|
+
args.files,
|
|
198
|
+
(args.strict.lower() in ("y", "ye", "yes")),
|
|
199
|
+
args.syntax_description,
|
|
200
|
+
)
|
|
192
201
|
if args.command == "report":
|
|
193
202
|
return commands.report()
|
|
194
203
|
if args.command == "run":
|
|
@@ -753,7 +753,7 @@
|
|
|
753
753
|
},
|
|
754
754
|
"protocol_version": {
|
|
755
755
|
"attribute": "protocol_version",
|
|
756
|
-
"range": "1,classic,2,tls,3,cookie,4,filestream,latest",
|
|
756
|
+
"range": "1,classic,2,tls,3,cookie,4,filestream,5,leech2,latest",
|
|
757
757
|
"status": "normal",
|
|
758
758
|
"type": "option",
|
|
759
759
|
"visibility": "body"
|
|
@@ -1020,7 +1020,7 @@
|
|
|
1020
1020
|
},
|
|
1021
1021
|
"protocol_version": {
|
|
1022
1022
|
"attribute": "protocol_version",
|
|
1023
|
-
"range": "1,classic,2,tls,3,cookie,4,filestream,latest",
|
|
1023
|
+
"range": "1,classic,2,tls,3,cookie,4,filestream,5,leech2,latest",
|
|
1024
1024
|
"status": "normal",
|
|
1025
1025
|
"type": "option",
|
|
1026
1026
|
"visibility": "body"
|
|
@@ -7368,6 +7368,13 @@
|
|
|
7368
7368
|
"type": "clist",
|
|
7369
7369
|
"visibility": "promiseType"
|
|
7370
7370
|
},
|
|
7371
|
+
"cancel": {
|
|
7372
|
+
"attribute": "cancel",
|
|
7373
|
+
"range": "true,false,yes,no,on,off",
|
|
7374
|
+
"status": "normal",
|
|
7375
|
+
"type": "option",
|
|
7376
|
+
"visibility": "promiseType"
|
|
7377
|
+
},
|
|
7371
7378
|
"classes": {
|
|
7372
7379
|
"attribute": "classes",
|
|
7373
7380
|
"status": "normal",
|
|
@@ -7465,6 +7472,13 @@
|
|
|
7465
7472
|
"type": "clist",
|
|
7466
7473
|
"visibility": "promiseType"
|
|
7467
7474
|
},
|
|
7475
|
+
"timer_policy": {
|
|
7476
|
+
"attribute": "timer_policy",
|
|
7477
|
+
"range": "absolute,reset",
|
|
7478
|
+
"status": "normal",
|
|
7479
|
+
"type": "option",
|
|
7480
|
+
"visibility": "promiseType"
|
|
7481
|
+
},
|
|
7468
7482
|
"unless": {
|
|
7469
7483
|
"attribute": "unless",
|
|
7470
7484
|
"range": "",
|
|
@@ -9395,7 +9409,7 @@
|
|
|
9395
9409
|
},
|
|
9396
9410
|
"signals": {
|
|
9397
9411
|
"attribute": "signals",
|
|
9398
|
-
"range": "(hup|int|trap|kill|pipe|cont|abrt|stop|quit|term|child|usr1|usr2|bus|segv|[0-9]+s?)",
|
|
9412
|
+
"range": "((?i:hup|int|trap|kill|pipe|cont|abrt|stop|quit|term|child|usr1|usr2|bus|segv)|[0-9]+s?)",
|
|
9399
9413
|
"status": "normal",
|
|
9400
9414
|
"type": "slist",
|
|
9401
9415
|
"visibility": "promiseType"
|
|
@@ -52,17 +52,14 @@ bundle agent win_services
|
|
|
52
52
|
"autostart_services"
|
|
53
53
|
slist => {
|
|
54
54
|
"Alerter",
|
|
55
|
-
"W32Time",
|
|
56
|
-
# Windows Time
|
|
55
|
+
"W32Time", # Windows Time
|
|
57
56
|
};
|
|
58
57
|
|
|
59
58
|
some_class::
|
|
60
59
|
"autostart_services"
|
|
61
60
|
slist => {
|
|
62
|
-
"MpsSvc",
|
|
63
|
-
# Windows
|
|
64
|
-
"W32Time",
|
|
65
|
-
# Windows Time
|
|
61
|
+
"MpsSvc", # Windows Firewall
|
|
62
|
+
"W32Time", # Windows Time
|
|
66
63
|
};
|
|
67
64
|
|
|
68
65
|
some_class::
|