Skip to content
This repository was archived by the owner on Aug 25, 2024. It is now read-only.

Commit 87e8a1e

Browse files
committed
in progress
Signed-off-by: John Andersen <[email protected]>
1 parent 3c2f424 commit 87e8a1e

File tree

1 file changed

+177
-71
lines changed

1 file changed

+177
-71
lines changed

dffml/util/testing/manifest/shim.py

Lines changed: 177 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,11 @@
107107
-----
108108
109109
- https://github.com/mjg59/ssh_pki
110-
111-
- Should we use this? No. Are we going to? Yes.
112110
"""
113111
import os
114112
import sys
115113
import pathlib
114+
import argparse
116115
import importlib
117116
import contextlib
118117
import dataclasses
@@ -159,89 +158,41 @@ def parse(contents: str):
159158
except Exception as yaml_parse_error:
160159
raise yaml_parse_error from json_parse_error
161160

162-
from pprint import pprint
163-
164-
# Known parser mapping
165-
parse = {
166-
(
167-
"tps.manifest",
168-
"0.0.0",
169-
"dataflow",
170-
): self.parse_my_document_format_0_0_0_dataflow
171-
}
172-
# Grab mapped parser
173-
document_format_version_output_mode = (
174-
doc.get("$document_format", None),
175-
doc.get("$document_version", None),
176-
doc.get("$document_version", None),
177-
)
178-
parser = parse.get(document_format_version, None)
179-
180-
if parser is None:
181-
raise Exception(
182-
f"Unknown document format/version pair: {document_format_version}"
183-
)
184-
185-
print()
186-
pprint(doc)
187-
print()
188-
parser(doc)
189-
190-
def parse_my_document_format_0_0_0_dataflow(self, doc):
191-
pass
192-
193-
194-
@dataclasses.dataclass
195-
class ManifestFormatParser:
196-
"""
197-
Read in configuration to determine what the next phase of parsing is.
198-
199-
args holds arguments passed to target.
200-
"""
201-
202-
format_name: str
203-
version: str
204-
output: str
205-
action: str
206-
target: str
207-
args: str = ""
208-
209161

210-
ENV_PREFIX = "TPS_MANIFEST_"
211-
212-
213-
def environ_discover_dataclass(
162+
def discover_dataclass_environ(
214163
dataclass,
164+
prefix: str,
215165
environ: Dict[str, str] = None,
216166
*,
217-
prefix: str = ENV_PREFIX,
218167
dataclass_key: str = None,
219168
):
220169
r"""
221170
>>> import dataclasses
222-
>>> from dffml.util.testing.manifest.shim import environ_discover_dataclass
171+
>>> from dffml.util.testing.manifest.shim import discover_dataclass_environ
223172
>>>
224173
>>> @dataclasses.dataclass
225174
... class MyDataclass:
226175
... name: str
227176
... version: str
177+
...
178+
... PREFIX = "MYPREFIX_"
228179
>>>
229-
>>> environ_discover_dataclass(
180+
>>> discover_dataclass_environ(
230181
... MyDataclass,
182+
... MyDataclass.PREFIX,
231183
... {
232184
... "MYPREFIX_NAME_EXAMPLE_FORMAT": "Example Format",
233185
... "MYPREFIX_VERSION_EXAMPLE_FORMAT": "0.0.1",
234186
... },
235-
... prefix="MYPREFIX_",
236187
... )
237188
{'example_format': MyDataclass(name='Example Format', version='0.0.1')}
238189
>>>
239-
>>> environ_discover_dataclass(
190+
>>> discover_dataclass_environ(
240191
... MyDataclass,
192+
... MyDataclass.PREFIX,
241193
... {
242194
... "MYPREFIX_VERSION_EXAMPLE_FORMAT": "0.0.1",
243195
... },
244-
... prefix="MYPREFIX_",
245196
... dataclass_key="name",
246197
... )
247198
{'example_format': MyDataclass(name='example_format', version='0.0.1')}
@@ -265,11 +216,144 @@ def environ_discover_dataclass(
265216
return discovered_parsers
266217

267218

268-
def shim(manifest: str, lockdown: bool, strict: bool):
269-
parsers = environ_discover_dataclass(
270-
ManifestFormatParser, dataclass_key="format_name", environ=os.environ
219+
@dataclasses.dataclass
220+
class ManifestFormatParser:
221+
"""
222+
Read in configuration to determine what the next phase of parsing is.
223+
224+
args holds arguments passed to target.
225+
"""
226+
227+
format_name: str
228+
version: str
229+
output: str
230+
action: str
231+
target: str
232+
args: str = ""
233+
234+
PREFIX: str = "TPS_MANIFEST_PARSER_"
235+
DATACLASS_KEY: str = "format_name"
236+
237+
238+
def input_action_print(
239+
args: argparse.Namespace, parser: ManifestFormatParser, manifest: Dict
240+
):
241+
"""
242+
Print the formated version of the action.
243+
"""
244+
return print()
245+
246+
247+
def input_action_exec(
248+
args: argparse.Namespace, parser: ManifestFormatParser, manifest: Dict
249+
):
250+
"""
251+
Execute the action via :py:func:`os.execvp`.
252+
"""
253+
raise NotImplementedError()
254+
255+
256+
FORMAT_PARSER_ACTIONS = {
257+
"print": input_action_print,
258+
"exec": input_action_exec,
259+
}
260+
261+
262+
def input_action_stdin(args: argparse.Namespace):
263+
"""
264+
Read manifest from stdin
265+
"""
266+
return sys.stdin.read()
267+
268+
269+
def input_action_read_text(args: argparse.Namespace):
270+
"""
271+
Read manifest from target filepath as text
272+
"""
273+
if args.input_target is None:
274+
raise ValueError("input target must be filepath but was None")
275+
input_target_path = pathlib.Path(args.input_target)
276+
if not input_target_path.exists():
277+
raise ValueError(
278+
f"input target must be filepath but was {args.input_target!r}"
279+
)
280+
return input_target_path.read_text()
281+
282+
283+
INPUT_ACTIONS = {
284+
"stdin": input_action_stdin,
285+
"read_text": input_action_read_text,
286+
}
287+
288+
289+
def shim(
290+
args: argparse.Namespace, environ: Dict[str, str] = None,
291+
):
292+
r"""
293+
294+
**TODO** Find code that sends all rest of args to target (QEMU?)
295+
296+
>>> import dataclasses
297+
>>> import sys
298+
>>> import types
299+
>>> import pprint
300+
>>> from dffml.util.testing.manifest.shim import shim
301+
>>>
302+
>>> @dataclasses.dataclass
303+
... class MyDataclass:
304+
... name: str
305+
... version: str
306+
...
307+
... PREFIX = "MYPREFIX_"
308+
>>>
309+
>>> shim(
310+
... types.SimpleNamespace(
311+
... action,
312+
... ),
313+
... {
314+
... "TPS_MANIFSET_ACTION_ONE": "print",
315+
... "TPS_MANIFSET_ACTION_TWO": "print",
316+
... }
317+
... )
318+
"""
319+
# Discover options for format parsers for next phase
320+
parsers = {
321+
(parser.format_name, parser.version, parser.action)
322+
for parser in discover_dataclass_environ(
323+
ManifestFormatParser,
324+
ManifestFormatParser.PREFIX,
325+
dataclass_key=ManifestFormatParser.DATACLASS_KEY,
326+
environ=os.environ,
327+
)
328+
}
329+
# Determine how to get the manifest
330+
input_action = INPUT_ACTIONS[args.input_action]
331+
# Get the manifest
332+
contents = input_action(args)
333+
# Validate the manfiest
334+
if not args.insecure:
335+
# TODO Implement validation
336+
pass
337+
if args.only_validate:
338+
# Bail if we are only validating the manfest and not parsing it
339+
return
340+
# Parse the manifest
341+
manifest = parse(contents)
342+
# Grab mapped parser
343+
format_version_action = (
344+
manifest.get("$document_format", None),
345+
manifest.get("$document_version", None),
346+
args.action,
271347
)
272-
print(parsers)
348+
if format_version_action not in parsers:
349+
raise Exception(
350+
f"Unknown document format/version/action combination: {format_version_action}: {parsers!r}"
351+
)
352+
parser = parsers[format_version_action]
353+
# Determine how to get the manifest
354+
action = FORMAT_PARSER_ACTIONS[parser.action]
355+
# Send manifest to next phase
356+
action(args, parser, manifest)
273357

274358

275359
def make_parser():
@@ -280,24 +364,46 @@ def make_parser():
280364
)
281365

282366
parser.add_argument(
283-
"-l", "--lockdown", type=bool, action="store_true", default=False,
367+
"-l", "--lockdown", action="store_true", default=False,
368+
)
369+
parser.add_argument(
370+
"-s", "--strict", action="store_true", default=False,
284371
)
285372
parser.add_argument(
286-
"-s", "--strict", type=argparse.FileType("r"), default=sys.stdin
373+
"--insecure",
374+
action="store_true",
375+
default=False,
376+
help=f"Skip manifest validation (validation currently unsupported)",
287377
)
288378
parser.add_argument(
289-
"-i", "--input", type=argparse.FileType("r"), default=sys.stdin
379+
"--only-validate",
380+
action="store_true",
381+
default=False,
382+
help=f"Exit after validating the manifest (validation currently unsupported)",
290383
)
291384
parser.add_argument(
292-
"-o", "--output", type=argparse.FileType("w"), default=sys.stdout
385+
"--input-action",
386+
choices=INPUT_ACTIONS.keys(),
387+
default="read_text",
388+
help=f"Method for aquiring manifest",
389+
)
390+
parser.add_argument(
391+
"--input-target",
392+
help="External callable to run which provides manifest",
393+
)
394+
parser.add_argument(
395+
"--input-args",
396+
help="Arguments for input action if externally callable",
293397
)
294-
parser.add_argument("-n", "--name", help="Name of function to replace")
295398
return parser
296399

297400

298401
def main():
299402
parser = make_parser()
300403
args = parser.parse_args()
301-
args.output.write(
302-
replace_function(args.input.read(), args.name, args.func.read()) + "\n"
303-
)
404+
405+
shim(args)
406+
407+
408+
if __name__ == "__main__":
409+
main()

0 commit comments

Comments
 (0)