cfengine 0.11.2__tar.gz → 0.12.1__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.11.2 → cfengine-0.12.1}/PKG-INFO +1 -1
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine.egg-info/PKG-INFO +1 -1
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine.egg-info/SOURCES.txt +1 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/commands.py +6 -7
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/docs.py +1 -1
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/lint.py +165 -33
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/main.py +7 -1
- cfengine-0.12.1/src/cfengine_cli/policy_language.py +239 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/uv.lock +3 -3
- {cfengine-0.11.2 → cfengine-0.12.1}/.github/dependabot.yml +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/.github/workflows/format.yml +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/.github/workflows/lint.yml +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/.github/workflows/pypi-publish.yml +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/.github/workflows/test.yml +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/.gitignore +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/.python-version +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/HACKING.md +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/LICENSE +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/README.md +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/ci/01-install.sh +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/ci/02-safe-tests.sh +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/ci/03-unsafe-tests.sh +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/pyproject.toml +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/setup.cfg +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine.egg-info/dependency_links.txt +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine.egg-info/entry_points.txt +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine.egg-info/requires.txt +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine.egg-info/top_level.txt +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/__init__.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/__main__.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/deptool-README.md +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/deptool.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/dev.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/format.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/masterfiles/__init__.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/masterfiles/analyze.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/masterfiles/check_download_matches_git.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/masterfiles/download.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/masterfiles/generate_git_tags.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/masterfiles/generate_release_information.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/masterfiles/generate_vcf_download.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/paths.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/profile.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/shell.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/utils.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/version.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/__init__.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/format/001_hello_world.expected.cf +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/format/001_hello_world.input.cf +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/format/002_basics.expected.cf +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/format/002_basics.input.cf +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/format/003_wrapping.expected.cf +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/format/003_wrapping.input.cf +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/format/004_comments.expected.cf +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/format/004_comments.input.cf +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/run-format-tests.sh +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/run-shell-tests.sh +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/shell/001-help.sh +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/shell/002-version.sh +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/shell/003-format.sh +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/test_deps.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/test_paths.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/test_utils.py +0 -0
- {cfengine-0.11.2 → cfengine-0.12.1}/tests/test_version.py +0 -0
|
@@ -4,7 +4,7 @@ import re
|
|
|
4
4
|
import json
|
|
5
5
|
from cfengine_cli.profile import profile_cfengine, generate_callstack
|
|
6
6
|
from cfengine_cli.dev import dispatch_dev_subcommand
|
|
7
|
-
from cfengine_cli.lint import
|
|
7
|
+
from cfengine_cli.lint import lint_folder, lint_single_arg
|
|
8
8
|
from cfengine_cli.shell import user_command
|
|
9
9
|
from cfengine_cli.paths import bin
|
|
10
10
|
from cfengine_cli.version import cfengine_cli_version_string
|
|
@@ -94,21 +94,20 @@ def format(names, line_length) -> int:
|
|
|
94
94
|
return 0
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
def _lint(files) -> int:
|
|
98
|
-
|
|
97
|
+
def _lint(files, strict) -> int:
|
|
99
98
|
if not files:
|
|
100
|
-
return lint_folder(".")
|
|
99
|
+
return lint_folder(".", strict)
|
|
101
100
|
|
|
102
101
|
errors = 0
|
|
103
102
|
|
|
104
103
|
for file in files:
|
|
105
|
-
errors += lint_single_arg(file)
|
|
104
|
+
errors += lint_single_arg(file, strict)
|
|
106
105
|
|
|
107
106
|
return errors
|
|
108
107
|
|
|
109
108
|
|
|
110
|
-
def lint(files) -> int:
|
|
111
|
-
errors = _lint(files)
|
|
109
|
+
def lint(files, strict) -> int:
|
|
110
|
+
errors = _lint(files, strict)
|
|
112
111
|
if errors == 0:
|
|
113
112
|
print("Success, no errors found.")
|
|
114
113
|
else:
|
|
@@ -14,13 +14,50 @@ import os
|
|
|
14
14
|
import json
|
|
15
15
|
import itertools
|
|
16
16
|
import tree_sitter_cfengine as tscfengine
|
|
17
|
+
from dataclasses import dataclass
|
|
17
18
|
from tree_sitter import Language, Parser
|
|
18
19
|
from cfbs.validate import validate_config
|
|
19
20
|
from cfbs.cfbs_config import CFBSConfig
|
|
20
21
|
from cfbs.utils import find
|
|
21
|
-
|
|
22
|
-
DEPRECATED_PROMISE_TYPES
|
|
23
|
-
ALLOWED_BUNDLE_TYPES
|
|
22
|
+
from cfengine_cli.policy_language import (
|
|
23
|
+
DEPRECATED_PROMISE_TYPES,
|
|
24
|
+
ALLOWED_BUNDLE_TYPES,
|
|
25
|
+
BUILTIN_PROMISE_TYPES,
|
|
26
|
+
BUILTIN_FUNCTIONS,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class _State:
|
|
32
|
+
block_type: str | None = None # "bundle" | "body" | "promise" | None
|
|
33
|
+
promise_type: str | None = None # "vars" | "files" | "classes" | ... | None
|
|
34
|
+
attribute_name: str | None = None # "if" | "string" | "slist" | ... | None
|
|
35
|
+
|
|
36
|
+
def update(self, node) -> "_State":
|
|
37
|
+
"""Updates and returns the state that should apply to the children of `node`."""
|
|
38
|
+
if node.type == "bundle_block":
|
|
39
|
+
return _State(block_type="bundle")
|
|
40
|
+
if node.type == "body_block":
|
|
41
|
+
return _State(block_type="body")
|
|
42
|
+
if node.type == "promise_block":
|
|
43
|
+
return _State(block_type="promise")
|
|
44
|
+
if node.type == "bundle_section":
|
|
45
|
+
for child in node.children:
|
|
46
|
+
if child.type == "promise_guard":
|
|
47
|
+
return _State(
|
|
48
|
+
block_type=self.block_type,
|
|
49
|
+
promise_type=_text(child)[:-1], # strip trailing ':'
|
|
50
|
+
)
|
|
51
|
+
return _State(block_type=self.block_type)
|
|
52
|
+
if node.type == "attribute":
|
|
53
|
+
for child in node.children:
|
|
54
|
+
if child.type == "attribute_name":
|
|
55
|
+
return _State(
|
|
56
|
+
block_type=self.block_type,
|
|
57
|
+
promise_type=self.promise_type,
|
|
58
|
+
attribute_name=_text(child),
|
|
59
|
+
)
|
|
60
|
+
return self
|
|
24
61
|
|
|
25
62
|
|
|
26
63
|
def lint_cfbs_json(filename) -> int:
|
|
@@ -90,16 +127,9 @@ def _find_node_type(filename, lines, node, node_type):
|
|
|
90
127
|
return matches
|
|
91
128
|
|
|
92
129
|
|
|
93
|
-
def
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
_walk_generic(filename, lines, node, visitor)
|
|
97
|
-
return matches
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def _single_node_checks(filename, lines, node):
|
|
101
|
-
"""Things which can be checked by only looking at one node,
|
|
102
|
-
not needing to recurse into children."""
|
|
130
|
+
def _node_checks(filename, lines, node, user_definition, strict, state: _State):
|
|
131
|
+
"""Checks we run on each node in the syntax tree,
|
|
132
|
+
utilizes state for checks which require context."""
|
|
103
133
|
line = node.range.start_point[0] + 1
|
|
104
134
|
column = node.range.start_point[1] + 1
|
|
105
135
|
if node.type == "attribute_name" and _text(node) == "ifvarclass":
|
|
@@ -117,6 +147,19 @@ def _single_node_checks(filename, lines, node):
|
|
|
117
147
|
f"Deprecation: Promise type '{promise_type}' is deprecated at {filename}:{line}:{column}"
|
|
118
148
|
)
|
|
119
149
|
return 1
|
|
150
|
+
if strict and (
|
|
151
|
+
(
|
|
152
|
+
promise_type
|
|
153
|
+
not in BUILTIN_PROMISE_TYPES.union(
|
|
154
|
+
user_definition.get("custom_promise_types", set())
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
):
|
|
158
|
+
_highlight_range(node, lines)
|
|
159
|
+
print(
|
|
160
|
+
f"Error: Undefined promise type '{promise_type}' at {filename}:{line}:{column}"
|
|
161
|
+
)
|
|
162
|
+
return 1
|
|
120
163
|
if node.type == "bundle_block_name":
|
|
121
164
|
if _text(node) != _text(node).lower():
|
|
122
165
|
_highlight_range(node, lines)
|
|
@@ -138,10 +181,52 @@ def _single_node_checks(filename, lines, node):
|
|
|
138
181
|
f"Error: Bundle type must be one of ({', '.join(ALLOWED_BUNDLE_TYPES)}), not '{_text(node)}' at {filename}:{line}:{column}"
|
|
139
182
|
)
|
|
140
183
|
return 1
|
|
184
|
+
if node.type == "calling_identifier":
|
|
185
|
+
if (
|
|
186
|
+
strict
|
|
187
|
+
and _text(node) in user_definition.get("all_bundle_names", set())
|
|
188
|
+
and state.promise_type in user_definition.get("custom_promise_types", set())
|
|
189
|
+
):
|
|
190
|
+
_highlight_range(node, lines)
|
|
191
|
+
print(
|
|
192
|
+
f"Error: Call to bundle '{_text(node)}' inside custom promise: '{state.promise_type}' at {filename}:{line}:{column}"
|
|
193
|
+
)
|
|
194
|
+
return 1
|
|
195
|
+
if strict and (
|
|
196
|
+
_text(node)
|
|
197
|
+
not in BUILTIN_FUNCTIONS.union(
|
|
198
|
+
user_definition.get("all_bundle_names", set()),
|
|
199
|
+
user_definition.get("all_body_names", set()),
|
|
200
|
+
)
|
|
201
|
+
):
|
|
202
|
+
_highlight_range(node, lines)
|
|
203
|
+
print(
|
|
204
|
+
f"Error: Call to unknown function / bundle / body '{_text(node)}' at at {filename}:{line}:{column}"
|
|
205
|
+
)
|
|
206
|
+
return 1
|
|
141
207
|
return 0
|
|
142
208
|
|
|
143
209
|
|
|
144
|
-
def
|
|
210
|
+
def _stateful_walk(
|
|
211
|
+
filename, lines, node, user_definition, strict, state: _State | None = None
|
|
212
|
+
) -> int:
|
|
213
|
+
if state is None:
|
|
214
|
+
state = _State()
|
|
215
|
+
|
|
216
|
+
errors = _node_checks(filename, lines, node, user_definition, strict, state)
|
|
217
|
+
|
|
218
|
+
child_state = state.update(node)
|
|
219
|
+
for child in node.children:
|
|
220
|
+
errors += _stateful_walk(
|
|
221
|
+
filename, lines, child, user_definition, strict, child_state
|
|
222
|
+
)
|
|
223
|
+
return errors
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _walk(filename, lines, node, user_definition=None, strict=True) -> int:
|
|
227
|
+
if user_definition is None:
|
|
228
|
+
user_definition = {}
|
|
229
|
+
|
|
145
230
|
error_nodes = _find_node_type(filename, lines, node, "ERROR")
|
|
146
231
|
if error_nodes:
|
|
147
232
|
for node in error_nodes:
|
|
@@ -154,15 +239,42 @@ def _walk(filename, lines, node) -> int:
|
|
|
154
239
|
line = node.range.start_point[0] + 1
|
|
155
240
|
column = node.range.start_point[1] + 1
|
|
156
241
|
|
|
157
|
-
|
|
158
|
-
for node in _find_nodes(filename, lines, node):
|
|
159
|
-
errors += _single_node_checks(filename, lines, node)
|
|
242
|
+
return _stateful_walk(filename, lines, node, user_definition, strict)
|
|
160
243
|
|
|
161
|
-
|
|
244
|
+
|
|
245
|
+
def _parse_user_definition(filename, lines, root_node):
|
|
246
|
+
promise_blocks = _find_node_type(filename, lines, root_node, "promise_block_name")
|
|
247
|
+
bundle_blocks = _find_node_type(filename, lines, root_node, "bundle_block_name")
|
|
248
|
+
body_blocks = _find_node_type(filename, lines, root_node, "body_block_name")
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
"custom_promise_types": {_text(x) for x in promise_blocks},
|
|
252
|
+
"all_bundle_names": {_text(x) for x in bundle_blocks},
|
|
253
|
+
"all_body_names": {_text(x) for x in body_blocks},
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _parse_policy_file(filename):
|
|
258
|
+
assert os.path.isfile(filename)
|
|
259
|
+
PY_LANGUAGE = Language(tscfengine.language())
|
|
260
|
+
parser = Parser(PY_LANGUAGE)
|
|
261
|
+
|
|
262
|
+
with open(filename, "rb") as f:
|
|
263
|
+
original_data = f.read()
|
|
264
|
+
tree = parser.parse(original_data)
|
|
265
|
+
lines = original_data.decode().split("\n")
|
|
266
|
+
|
|
267
|
+
return tree, lines, original_data
|
|
162
268
|
|
|
163
269
|
|
|
164
270
|
def lint_policy_file(
|
|
165
|
-
filename,
|
|
271
|
+
filename,
|
|
272
|
+
original_filename=None,
|
|
273
|
+
original_line=None,
|
|
274
|
+
snippet=None,
|
|
275
|
+
prefix=None,
|
|
276
|
+
user_definition=None,
|
|
277
|
+
strict=True,
|
|
166
278
|
):
|
|
167
279
|
assert original_filename is None or type(original_filename) is str
|
|
168
280
|
assert original_line is None or type(original_line) is int
|
|
@@ -177,14 +289,11 @@ def lint_policy_file(
|
|
|
177
289
|
assert snippet and snippet > 0
|
|
178
290
|
assert os.path.isfile(filename)
|
|
179
291
|
assert filename.endswith((".cf", ".cfengine3", ".cf3", ".cf.sub"))
|
|
180
|
-
PY_LANGUAGE = Language(tscfengine.language())
|
|
181
|
-
parser = Parser(PY_LANGUAGE)
|
|
182
292
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
tree = parser.parse(original_data)
|
|
186
|
-
lines = original_data.decode().split("\n")
|
|
293
|
+
if user_definition is None:
|
|
294
|
+
user_definition = {}
|
|
187
295
|
|
|
296
|
+
tree, lines, original_data = _parse_policy_file(filename)
|
|
188
297
|
root_node = tree.root_node
|
|
189
298
|
if root_node.type != "source_file":
|
|
190
299
|
if snippet:
|
|
@@ -214,7 +323,7 @@ def lint_policy_file(
|
|
|
214
323
|
else:
|
|
215
324
|
print(f"Error: Empty policy file '{filename}'")
|
|
216
325
|
errors += 1
|
|
217
|
-
errors += _walk(filename, lines, root_node)
|
|
326
|
+
errors += _walk(filename, lines, root_node, user_definition, strict)
|
|
218
327
|
if prefix:
|
|
219
328
|
print(prefix, end="")
|
|
220
329
|
if errors == 0:
|
|
@@ -235,8 +344,9 @@ def lint_policy_file(
|
|
|
235
344
|
return errors
|
|
236
345
|
|
|
237
346
|
|
|
238
|
-
def lint_folder(folder):
|
|
347
|
+
def lint_folder(folder, strict=True):
|
|
239
348
|
errors = 0
|
|
349
|
+
policy_files = []
|
|
240
350
|
while folder.endswith(("/.", "/")):
|
|
241
351
|
folder = folder[0:-1]
|
|
242
352
|
for filename in itertools.chain(
|
|
@@ -246,22 +356,44 @@ def lint_folder(folder):
|
|
|
246
356
|
continue
|
|
247
357
|
if filename.startswith(".") and not filename.startswith("./"):
|
|
248
358
|
continue
|
|
249
|
-
|
|
359
|
+
|
|
360
|
+
if filename.endswith((".cf", ".cfengine3", ".cf3", ".cf.sub")):
|
|
361
|
+
policy_files.append(filename)
|
|
362
|
+
else:
|
|
363
|
+
errors += lint_single_file(filename)
|
|
364
|
+
|
|
365
|
+
user_definition = {}
|
|
366
|
+
|
|
367
|
+
# First pass: Gather custom types
|
|
368
|
+
for filename in policy_files if strict else []:
|
|
369
|
+
tree, lines, _ = _parse_policy_file(filename)
|
|
370
|
+
if tree.root_node.type == "source_file":
|
|
371
|
+
for key, val in _parse_user_definition(
|
|
372
|
+
filename, lines, tree.root_node
|
|
373
|
+
).items():
|
|
374
|
+
user_definition[key] = user_definition.get(key, set()).union(val)
|
|
375
|
+
|
|
376
|
+
# Second pass: lint all policy files
|
|
377
|
+
for filename in policy_files:
|
|
378
|
+
errors += lint_policy_file(
|
|
379
|
+
filename, user_definition=user_definition, strict=strict
|
|
380
|
+
)
|
|
250
381
|
return errors
|
|
251
382
|
|
|
252
383
|
|
|
253
|
-
def lint_single_file(file):
|
|
384
|
+
def lint_single_file(file, user_definition=None, strict=True):
|
|
254
385
|
assert os.path.isfile(file)
|
|
255
386
|
if file.endswith("/cfbs.json"):
|
|
256
387
|
return lint_cfbs_json(file)
|
|
257
388
|
if file.endswith(".json"):
|
|
258
389
|
return lint_json(file)
|
|
259
390
|
assert file.endswith(".cf")
|
|
260
|
-
return lint_policy_file(file)
|
|
391
|
+
return lint_policy_file(file, user_definition=user_definition, strict=strict)
|
|
261
392
|
|
|
262
393
|
|
|
263
|
-
def lint_single_arg(arg):
|
|
394
|
+
def lint_single_arg(arg, strict=True):
|
|
264
395
|
if os.path.isdir(arg):
|
|
265
|
-
return lint_folder(arg)
|
|
396
|
+
return lint_folder(arg, strict)
|
|
266
397
|
assert os.path.isfile(arg)
|
|
267
|
-
|
|
398
|
+
|
|
399
|
+
return lint_single_file(arg, strict)
|
|
@@ -52,6 +52,12 @@ def _get_arg_parser():
|
|
|
52
52
|
"lint",
|
|
53
53
|
help="Look for syntax errors and other simple mistakes",
|
|
54
54
|
)
|
|
55
|
+
lnt.add_argument(
|
|
56
|
+
"--strict",
|
|
57
|
+
type=str,
|
|
58
|
+
default="yes",
|
|
59
|
+
help="Strict mode. Default=yes, checks for undefined promise types, bundles, bodies, functions",
|
|
60
|
+
)
|
|
55
61
|
lnt.add_argument("files", nargs="*", help="Files to format")
|
|
56
62
|
subp.add_parser(
|
|
57
63
|
"report",
|
|
@@ -132,7 +138,7 @@ def run_command_with_args(args) -> int:
|
|
|
132
138
|
if args.command == "format":
|
|
133
139
|
return commands.format(args.files, args.line_length)
|
|
134
140
|
if args.command == "lint":
|
|
135
|
-
return commands.lint(args.files)
|
|
141
|
+
return commands.lint(args.files, (args.strict.lower() in ("y", "ye", "yes")))
|
|
136
142
|
if args.command == "report":
|
|
137
143
|
return commands.report()
|
|
138
144
|
if args.command == "run":
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# These constants are temporary and may change in the future
|
|
2
|
+
# TODO: Find a way to extract these from the generated "syntax-definition"-json file
|
|
3
|
+
|
|
4
|
+
DEPRECATED_PROMISE_TYPES = ["defaults", "guest_environments"]
|
|
5
|
+
ALLOWED_BUNDLE_TYPES = ["agent", "common", "monitor", "server", "edit_line", "edit_xml"]
|
|
6
|
+
BUILTIN_PROMISE_TYPES = {
|
|
7
|
+
"access",
|
|
8
|
+
"build_xpath",
|
|
9
|
+
"classes",
|
|
10
|
+
"commands",
|
|
11
|
+
"databases",
|
|
12
|
+
"defaults",
|
|
13
|
+
"delete_attribute",
|
|
14
|
+
"delete_lines",
|
|
15
|
+
"delete_text",
|
|
16
|
+
"delete_tree",
|
|
17
|
+
"field_edits",
|
|
18
|
+
"files",
|
|
19
|
+
"guest_environments",
|
|
20
|
+
"insert_lines",
|
|
21
|
+
"insert_text",
|
|
22
|
+
"insert_tree",
|
|
23
|
+
"measurements",
|
|
24
|
+
"meta",
|
|
25
|
+
"methods",
|
|
26
|
+
"packages",
|
|
27
|
+
"processes",
|
|
28
|
+
"replace_patterns",
|
|
29
|
+
"reports",
|
|
30
|
+
"roles",
|
|
31
|
+
"services",
|
|
32
|
+
"set_attribute",
|
|
33
|
+
"set_text",
|
|
34
|
+
"storage",
|
|
35
|
+
"users",
|
|
36
|
+
"vars",
|
|
37
|
+
}
|
|
38
|
+
BUILTIN_FUNCTIONS = {
|
|
39
|
+
"accessedbefore",
|
|
40
|
+
"accumulated",
|
|
41
|
+
"ago",
|
|
42
|
+
"and",
|
|
43
|
+
"basename",
|
|
44
|
+
"bundlesmatching",
|
|
45
|
+
"bundlestate",
|
|
46
|
+
"callstack_callers",
|
|
47
|
+
"callstack_promisers",
|
|
48
|
+
"canonify",
|
|
49
|
+
"canonifyuniquely",
|
|
50
|
+
"cf_version_after",
|
|
51
|
+
"cf_version_at",
|
|
52
|
+
"cf_version_before",
|
|
53
|
+
"cf_version_between",
|
|
54
|
+
"cf_version_maximum",
|
|
55
|
+
"cf_version_minimum",
|
|
56
|
+
"changedbefore",
|
|
57
|
+
"classesmatching",
|
|
58
|
+
"classfiltercsv",
|
|
59
|
+
"classfilterdata",
|
|
60
|
+
"classify",
|
|
61
|
+
"classmatch",
|
|
62
|
+
"concat",
|
|
63
|
+
"countclassesmatching",
|
|
64
|
+
"countlinesmatching",
|
|
65
|
+
"data_expand",
|
|
66
|
+
"data_readstringarray",
|
|
67
|
+
"data_readstringarrayidx",
|
|
68
|
+
"data_regextract",
|
|
69
|
+
"data_sysctlvalues",
|
|
70
|
+
"datastate",
|
|
71
|
+
"difference",
|
|
72
|
+
"dirname",
|
|
73
|
+
"diskfree",
|
|
74
|
+
"escape",
|
|
75
|
+
"eval",
|
|
76
|
+
"every",
|
|
77
|
+
"execresult",
|
|
78
|
+
"execresult_as_data",
|
|
79
|
+
"expandrange",
|
|
80
|
+
"file_hash",
|
|
81
|
+
"fileexists",
|
|
82
|
+
"filesexist",
|
|
83
|
+
"filesize",
|
|
84
|
+
"filestat",
|
|
85
|
+
"filter",
|
|
86
|
+
"findfiles",
|
|
87
|
+
"findfiles_up",
|
|
88
|
+
"findlocalgroups",
|
|
89
|
+
"findlocalusers",
|
|
90
|
+
"findprocesses",
|
|
91
|
+
"format",
|
|
92
|
+
"getacls",
|
|
93
|
+
"getbundlemetatags",
|
|
94
|
+
"getclassmetatags",
|
|
95
|
+
"getenv",
|
|
96
|
+
"getfields",
|
|
97
|
+
"getgid",
|
|
98
|
+
"getgroupinfo",
|
|
99
|
+
"getgroups",
|
|
100
|
+
"getindices",
|
|
101
|
+
"getuid",
|
|
102
|
+
"getuserinfo",
|
|
103
|
+
"getusers",
|
|
104
|
+
"getvalues",
|
|
105
|
+
"getvariablemetatags",
|
|
106
|
+
"grep",
|
|
107
|
+
"groupexists",
|
|
108
|
+
"hash",
|
|
109
|
+
"hash_to_int",
|
|
110
|
+
"hashmatch",
|
|
111
|
+
"host2ip",
|
|
112
|
+
"hostinnetgroup",
|
|
113
|
+
"hostrange",
|
|
114
|
+
"hostsseen",
|
|
115
|
+
"hostswithclass",
|
|
116
|
+
"hostswithgroup",
|
|
117
|
+
"hubknowledge",
|
|
118
|
+
"ifelse",
|
|
119
|
+
"int",
|
|
120
|
+
"intersection",
|
|
121
|
+
"ip2host",
|
|
122
|
+
"iprange",
|
|
123
|
+
"irange",
|
|
124
|
+
"is_type",
|
|
125
|
+
"isconnectable",
|
|
126
|
+
"isdir",
|
|
127
|
+
"isexecutable",
|
|
128
|
+
"isgreaterthan",
|
|
129
|
+
"isipinsubnet",
|
|
130
|
+
"islessthan",
|
|
131
|
+
"islink",
|
|
132
|
+
"isnewerthan",
|
|
133
|
+
"isnewerthantime",
|
|
134
|
+
"isplain",
|
|
135
|
+
"isreadable",
|
|
136
|
+
"isvariable",
|
|
137
|
+
"join",
|
|
138
|
+
"lastnode",
|
|
139
|
+
"laterthan",
|
|
140
|
+
"ldaparray",
|
|
141
|
+
"ldaplist",
|
|
142
|
+
"ldapvalue",
|
|
143
|
+
"length",
|
|
144
|
+
"lsdir",
|
|
145
|
+
"makerule",
|
|
146
|
+
"maparray",
|
|
147
|
+
"mapdata",
|
|
148
|
+
"maplist",
|
|
149
|
+
"max",
|
|
150
|
+
"mean",
|
|
151
|
+
"mergedata",
|
|
152
|
+
"min",
|
|
153
|
+
"network_connections",
|
|
154
|
+
"none",
|
|
155
|
+
"not",
|
|
156
|
+
"now",
|
|
157
|
+
"nth",
|
|
158
|
+
"on",
|
|
159
|
+
"or",
|
|
160
|
+
"packagesmatching",
|
|
161
|
+
"packageupdatesmatching",
|
|
162
|
+
"parseintarray",
|
|
163
|
+
"parsejson",
|
|
164
|
+
"parserealarray",
|
|
165
|
+
"parsestringarray",
|
|
166
|
+
"parsestringarrayidx",
|
|
167
|
+
"parseyaml",
|
|
168
|
+
"peerleader",
|
|
169
|
+
"peerleaders",
|
|
170
|
+
"peers",
|
|
171
|
+
"processexists",
|
|
172
|
+
"product",
|
|
173
|
+
"randomint",
|
|
174
|
+
"read_module_protocol",
|
|
175
|
+
"readcsv",
|
|
176
|
+
"readdata",
|
|
177
|
+
"readenvfile",
|
|
178
|
+
"readfile",
|
|
179
|
+
"readintarray",
|
|
180
|
+
"readintlist",
|
|
181
|
+
"readjson",
|
|
182
|
+
"readrealarray",
|
|
183
|
+
"readreallist",
|
|
184
|
+
"readstringarray",
|
|
185
|
+
"readstringarrayidx",
|
|
186
|
+
"readstringlist",
|
|
187
|
+
"readtcp",
|
|
188
|
+
"readyaml",
|
|
189
|
+
"regarray",
|
|
190
|
+
"regcmp",
|
|
191
|
+
"regex_replace",
|
|
192
|
+
"regextract",
|
|
193
|
+
"registryvalue",
|
|
194
|
+
"regldap",
|
|
195
|
+
"regline",
|
|
196
|
+
"reglist",
|
|
197
|
+
"remoteclassesmatching",
|
|
198
|
+
"remotescalar",
|
|
199
|
+
"returnszero",
|
|
200
|
+
"reverse",
|
|
201
|
+
"rrange",
|
|
202
|
+
"search_up",
|
|
203
|
+
"selectservers",
|
|
204
|
+
"shuffle",
|
|
205
|
+
"some",
|
|
206
|
+
"sort",
|
|
207
|
+
"splayclass",
|
|
208
|
+
"splitstring",
|
|
209
|
+
"storejson",
|
|
210
|
+
"strcmp",
|
|
211
|
+
"strftime",
|
|
212
|
+
"string",
|
|
213
|
+
"string_downcase",
|
|
214
|
+
"string_head",
|
|
215
|
+
"string_length",
|
|
216
|
+
"string_mustache",
|
|
217
|
+
"string_replace",
|
|
218
|
+
"string_reverse",
|
|
219
|
+
"string_split",
|
|
220
|
+
"string_tail",
|
|
221
|
+
"string_trim",
|
|
222
|
+
"string_upcase",
|
|
223
|
+
"sublist",
|
|
224
|
+
"sum",
|
|
225
|
+
"sysctlvalue",
|
|
226
|
+
"translatepath",
|
|
227
|
+
"type",
|
|
228
|
+
"unique",
|
|
229
|
+
"url_get",
|
|
230
|
+
"usemodule",
|
|
231
|
+
"userexists",
|
|
232
|
+
"useringroup",
|
|
233
|
+
"validdata",
|
|
234
|
+
"validjson",
|
|
235
|
+
"variablesmatching",
|
|
236
|
+
"variablesmatching_as_data",
|
|
237
|
+
"variance",
|
|
238
|
+
"version_compare",
|
|
239
|
+
}
|
|
@@ -329,7 +329,7 @@ wheels = [
|
|
|
329
329
|
|
|
330
330
|
[[package]]
|
|
331
331
|
name = "requests"
|
|
332
|
-
version = "2.
|
|
332
|
+
version = "2.33.0"
|
|
333
333
|
source = { registry = "https://pypi.org/simple" }
|
|
334
334
|
dependencies = [
|
|
335
335
|
{ name = "certifi" },
|
|
@@ -337,9 +337,9 @@ dependencies = [
|
|
|
337
337
|
{ name = "idna" },
|
|
338
338
|
{ name = "urllib3" },
|
|
339
339
|
]
|
|
340
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
340
|
+
sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232, upload-time = "2026-03-25T15:10:41.586Z" }
|
|
341
341
|
wheels = [
|
|
342
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
342
|
+
{ url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" },
|
|
343
343
|
]
|
|
344
344
|
|
|
345
345
|
[[package]]
|
|
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.11.2 → cfengine-0.12.1}/src/cfengine_cli/masterfiles/check_download_matches_git.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cfengine-0.11.2 → cfengine-0.12.1}/src/cfengine_cli/masterfiles/generate_release_information.py
RENAMED
|
File without changes
|
|
File without changes
|
{cfengine-0.11.2 → cfengine-0.12.1}/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
|