cfengine 0.17.0__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.17.0 → cfengine-0.18.0}/.github/workflows/update-syntax-description.yml +2 -1
- {cfengine-0.17.0 → cfengine-0.18.0}/PKG-INFO +1 -1
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine.egg-info/PKG-INFO +1 -1
- cfengine-0.18.0/src/cfengine.egg-info/scm_version.json +8 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/commands.py +5 -5
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/docs.py +21 -9
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/format.py +59 -30
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/lint.py +11 -5
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/main.py +10 -1
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/syntax-description.json +1 -1
- cfengine-0.17.0/src/cfengine.egg-info/scm_version.json +0 -8
- {cfengine-0.17.0 → cfengine-0.18.0}/.github/dependabot.yml +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/.github/workflows/lint-policy-in-other-repos.yml +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/.github/workflows/make-check.yml +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/.github/workflows/pypi-publish.yml +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/.github/workflows/stale.yml +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/.gitignore +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/.python-version +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/CLAUDE.md +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/HACKING.md +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/LICENSE +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/Makefile +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/README.md +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/ci/01-install.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/ci/02-safe-tests.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/ci/03-unsafe-tests.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/pyproject.toml +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/setup.cfg +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine.egg-info/SOURCES.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine.egg-info/dependency_links.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine.egg-info/entry_points.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine.egg-info/requires.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine.egg-info/scm_file_list.json +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine.egg-info/top_level.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/__init__.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/__main__.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/changelog.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/deptool-README.md +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/deptool.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/dev.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/lint_csv.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/lint_yml.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/__init__.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/analyze.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/check_download_matches_git.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/download.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/generate_git_tags.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/generate_release_information.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/generate_vcf_download.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/paths.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/profile.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/shell.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/syntax_tree.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/up.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/utils.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/validate.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/version.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/README.md +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/001_hello_world.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/001_hello_world.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/002_basics.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/002_basics.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/003_wrapping.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/003_wrapping.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/004_comments.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/004_comments.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/005_bundle_comments.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/005_bundle_comments.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/006_remove_empty_comments.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/006_remove_empty_comments.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/007_class_guarded_empty_lines.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/007_class_guarded_empty_lines.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/008_long_string.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/008_long_string.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/009_single_line.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/009_single_line.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/010_stakeholder.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/010_stakeholder.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/011_macros.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/011_macros.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/011_promises.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/011_promises.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/012_sameline_comments.expected.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/format/012_sameline_comments.input.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/001_hello_world.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/002_deprecations.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/002_deprecations.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/003_name_lowercase.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/003_name_lowercase.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/003_name_lowercase.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/004_block_type.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/004_block_type.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/004_block_type.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/005_syntax_error.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/005_syntax_error.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/005_syntax_error.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/006_empty_file.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/006_empty_file.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/007_namespace.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/007_namespace.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/007_namespace.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/008_bundle_shadows_function.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/008_bundle_shadows_function.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/008_bundle_shadows_function.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/009_unknown_function_inside_vars.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/009_unknown_function_inside_vars.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/009_unknown_function_inside_vars.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/010_mutually_exclusive_types_vars.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/010_mutually_exclusive_types_vars.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/010_mutually_exclusive_types_vars.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/011_invalid_attributes.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/011_invalid_attributes.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/012_function_call_arg_count.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/012_function_call_arg_count.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/012_function_call_arg_count.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/013_num_args_body.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/013_num_args_body.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/013_num_args_bundle.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/013_num_args_bundle.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/013_num_args_bundle_body.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/014_variadic_func_arg_count.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/014_variadic_func_arg_count.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/014_variadic_func_arg_count.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/015_macro_multi_def_bundle.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/015_macro_multi_def_bundle.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/015_macro_multi_def_bundle.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/016_half_promises.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/016_half_promises.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/016_half_promises.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/017_implies_body.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/017_implies_body.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/017_implies_body.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/018_nested_calls.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/018_nested_calls.expected.txt +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/018_nested_calls.x.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/019_bundle_name_expansion.cf +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/run-format-tests.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/run-lint-tests.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/run-shell-tests.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/run-up-validate-tests.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/shell/001-help.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/shell/002-version.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/shell/003-format.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/shell/004-format-check.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/shell/005-lint.sh +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/unit/__init__.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/unit/test_changelog.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/unit/test_deps.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/unit/test_format.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/unit/test_lint_csv.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/unit/test_lint_yml.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/unit/test_paths.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/unit/test_utils.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/unit/test_version.py +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/up-validate/001_complex_config.yaml +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/up-validate/002_version.x.yaml +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/up-validate/003_box.x.yaml +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/up-validate/004_count.x.yaml +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/up-validate/mocks/cloud_config.json +0 -0
- {cfengine-0.17.0 → cfengine-0.18.0}/tests/up-validate/mocks/vagrant +0 -0
- {cfengine-0.17.0 → 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: |
|
|
@@ -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
|
|
@@ -38,6 +39,14 @@ PROMISER_PARTS = {"promiser", "->", "stakeholder"}
|
|
|
38
39
|
SAMELINE_COMMENT_SEPARATOR = " "
|
|
39
40
|
|
|
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
|
+
|
|
49
|
+
|
|
41
50
|
def _has_direct_macro(node: Node) -> bool:
|
|
42
51
|
"""Check if any direct child of a node is a macro (non-recursive)."""
|
|
43
52
|
return any(child.type == "macro" for child in node.children)
|
|
@@ -64,12 +73,8 @@ def _contains_list_with_comment(nodes: Node | list[Node]) -> bool:
|
|
|
64
73
|
return _contains_list_with_comment(nodes.children)
|
|
65
74
|
|
|
66
75
|
|
|
67
|
-
def format_json_file(filename: str, check: bool) ->
|
|
68
|
-
"""Reformat a JSON file in place using cfbs pretty-printer.
|
|
69
|
-
|
|
70
|
-
Returns 0 in case of successful reformat or no reformat needed.
|
|
71
|
-
Returns 1 when check is True and reformat is needed.
|
|
72
|
-
"""
|
|
76
|
+
def format_json_file(filename: str, check: bool) -> FormatResult:
|
|
77
|
+
"""Reformat a JSON file in place using cfbs pretty-printer."""
|
|
73
78
|
assert filename.endswith(".json")
|
|
74
79
|
|
|
75
80
|
if check:
|
|
@@ -78,16 +83,17 @@ def format_json_file(filename: str, check: bool) -> int:
|
|
|
78
83
|
assert type(success) is bool
|
|
79
84
|
if not success:
|
|
80
85
|
print(f"JSON file '{filename}' needs reformatting")
|
|
81
|
-
|
|
86
|
+
return FormatResult.NEEDS_FORMAT
|
|
87
|
+
return FormatResult.NO_CHANGE
|
|
82
88
|
|
|
83
89
|
try:
|
|
84
90
|
reformatted = pretty_file(filename)
|
|
85
91
|
if reformatted:
|
|
86
92
|
print(f"JSON file '{filename}' was reformatted")
|
|
87
|
-
|
|
93
|
+
return FormatResult.REFORMATTED
|
|
94
|
+
return FormatResult.NO_CHANGE
|
|
88
95
|
except json.decoder.JSONDecodeError as e:
|
|
89
|
-
|
|
90
|
-
return 1
|
|
96
|
+
raise UserError(f"JSON file '{filename}' invalid ({str(e)})")
|
|
91
97
|
|
|
92
98
|
|
|
93
99
|
def text(node: Node) -> str:
|
|
@@ -1008,11 +1014,9 @@ def _autoformat(
|
|
|
1008
1014
|
# ---------------------------------------------------------------------------
|
|
1009
1015
|
|
|
1010
1016
|
|
|
1011
|
-
def format_policy_file(filename: str, line_length: int, check: bool) ->
|
|
1017
|
+
def format_policy_file(filename: str, line_length: int, check: bool) -> FormatResult:
|
|
1012
1018
|
"""Format a .cf policy file in place, writing only if content changed.
|
|
1013
1019
|
|
|
1014
|
-
Returns 0 in case of successful reformat or no reformat needed.
|
|
1015
|
-
Returns 1 when check is True and reformat is needed.
|
|
1016
1020
|
Raises PolicySyntaxError when the file has syntax errors."""
|
|
1017
1021
|
assert filename.endswith(".cf")
|
|
1018
1022
|
|
|
@@ -1031,21 +1035,28 @@ def format_policy_file(filename: str, line_length: int, check: bool) -> int:
|
|
|
1031
1035
|
fmt = Formatter()
|
|
1032
1036
|
_autoformat(root_node, fmt, line_length)
|
|
1033
1037
|
|
|
1034
|
-
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
|
+
|
|
1035
1045
|
if new_data != original_data.decode("utf-8"):
|
|
1036
1046
|
if check:
|
|
1037
1047
|
print(f"Policy file '{filename}' needs reformatting")
|
|
1038
|
-
return
|
|
1048
|
+
return FormatResult.NEEDS_FORMAT
|
|
1039
1049
|
|
|
1040
1050
|
with open(filename, "w") as f:
|
|
1041
1051
|
f.write(new_data)
|
|
1042
1052
|
print(f"Policy file '{filename}' was reformatted")
|
|
1043
|
-
|
|
1053
|
+
return FormatResult.REFORMATTED
|
|
1054
|
+
return FormatResult.NO_CHANGE
|
|
1044
1055
|
|
|
1045
1056
|
|
|
1046
1057
|
def format_policy_fin_fout(
|
|
1047
1058
|
fin: IO[str], fout: IO[str], line_length: int, check: bool
|
|
1048
|
-
) ->
|
|
1059
|
+
) -> FormatResult:
|
|
1049
1060
|
"""Format CFEngine policy read from fin, writing the result to fout.
|
|
1050
1061
|
|
|
1051
1062
|
Raises PolicySyntaxError when the input has syntax errors."""
|
|
@@ -1065,10 +1076,12 @@ def format_policy_fin_fout(
|
|
|
1065
1076
|
|
|
1066
1077
|
new_data = fmt.buffer + "\n"
|
|
1067
1078
|
fout.write(new_data)
|
|
1068
|
-
|
|
1079
|
+
if new_data != original_data.decode("utf-8"):
|
|
1080
|
+
return FormatResult.REFORMATTED
|
|
1081
|
+
return FormatResult.NO_CHANGE
|
|
1069
1082
|
|
|
1070
1083
|
|
|
1071
|
-
def _format_filename(filename: str, line_length: int, check: bool) ->
|
|
1084
|
+
def _format_filename(filename: str, line_length: int, check: bool) -> FormatResult:
|
|
1072
1085
|
"""Format a single file.
|
|
1073
1086
|
|
|
1074
1087
|
Raises PolicySyntaxError for .cf files with syntax errors."""
|
|
@@ -1079,8 +1092,17 @@ def _format_filename(filename: str, line_length: int, check: bool) -> int:
|
|
|
1079
1092
|
raise UserError(f"Unrecognized file format: {filename}")
|
|
1080
1093
|
|
|
1081
1094
|
|
|
1082
|
-
def
|
|
1083
|
-
|
|
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
|
|
1084
1106
|
for root, dirs, files in os.walk(directory):
|
|
1085
1107
|
# Don't recurse into hidden folders
|
|
1086
1108
|
dirs[:] = [d for d in dirs if not d.startswith(".")]
|
|
@@ -1100,18 +1122,20 @@ def _format_dirname(directory: str, line_length: int, check: bool) -> int:
|
|
|
1100
1122
|
continue # Test files skipped during directory traversal
|
|
1101
1123
|
filepath = os.path.join(root, name)
|
|
1102
1124
|
if name.endswith(".json") or name.endswith(".cf"):
|
|
1103
|
-
ret
|
|
1125
|
+
ret = _combine_results(
|
|
1126
|
+
ret, _format_filename(filepath, line_length, check)
|
|
1127
|
+
)
|
|
1104
1128
|
return ret
|
|
1105
1129
|
|
|
1106
1130
|
|
|
1107
|
-
def _format_paths_inner(names, line_length, check) ->
|
|
1131
|
+
def _format_paths_inner(names, line_length, check) -> FormatResult:
|
|
1108
1132
|
if not names:
|
|
1109
1133
|
return _format_dirname(".", line_length, check)
|
|
1110
1134
|
if len(names) == 1 and names[0] == "-":
|
|
1111
1135
|
# Special case, format policy file from stdin to stdout
|
|
1112
1136
|
return format_policy_fin_fout(sys.stdin, sys.stdout, line_length, check)
|
|
1113
1137
|
|
|
1114
|
-
ret =
|
|
1138
|
+
ret = FormatResult.NO_CHANGE
|
|
1115
1139
|
for name in names:
|
|
1116
1140
|
if name == "-":
|
|
1117
1141
|
raise UserError(
|
|
@@ -1120,14 +1144,12 @@ def _format_paths_inner(names, line_length, check) -> int:
|
|
|
1120
1144
|
if not os.path.exists(name):
|
|
1121
1145
|
raise UserError(f"{name} does not exist")
|
|
1122
1146
|
if os.path.isfile(name):
|
|
1123
|
-
ret
|
|
1147
|
+
ret = _combine_results(ret, _format_filename(name, line_length, check))
|
|
1124
1148
|
continue
|
|
1125
1149
|
if os.path.isdir(name):
|
|
1126
|
-
ret
|
|
1150
|
+
ret = _combine_results(ret, _format_dirname(name, line_length, check))
|
|
1127
1151
|
continue
|
|
1128
|
-
|
|
1129
|
-
return ret
|
|
1130
|
-
return 0
|
|
1152
|
+
return ret
|
|
1131
1153
|
|
|
1132
1154
|
|
|
1133
1155
|
def format_paths(names, line_length, check) -> int:
|
|
@@ -1138,7 +1160,14 @@ def format_paths(names, line_length, check) -> int:
|
|
|
1138
1160
|
needed), 1 when reformatting is needed in check mode or a policy file
|
|
1139
1161
|
has syntax errors."""
|
|
1140
1162
|
try:
|
|
1141
|
-
|
|
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
|
|
1142
1171
|
except PolicySyntaxError as e:
|
|
1143
1172
|
print(f"Error: {e}")
|
|
1144
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":
|
|
@@ -9409,7 +9409,7 @@
|
|
|
9409
9409
|
},
|
|
9410
9410
|
"signals": {
|
|
9411
9411
|
"attribute": "signals",
|
|
9412
|
-
"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?)",
|
|
9413
9413
|
"status": "normal",
|
|
9414
9414
|
"type": "slist",
|
|
9415
9415
|
"visibility": "promiseType"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/check_download_matches_git.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/generate_release_information.py
RENAMED
|
File without changes
|
|
File without changes
|
{cfengine-0.17.0 → cfengine-0.18.0}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/009_unknown_function_inside_vars.expected.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cfengine-0.17.0 → cfengine-0.18.0}/tests/lint/010_mutually_exclusive_types_vars.expected.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|