Skip to content

Commit 1850c19

Browse files
authored
Merge pull request #10 from MAK-Relic-Tool/cli-support
Adds SGA support to the command line interface Unpacking: `relic sga unpack src_file out_dir` Packing: `relic sga pack {vX} -h` where vX is the version of SGA to pack. `-h` will print the commands help, which will ispecify how to run that SGA's packer.
2 parents 2add115 + 4866ee5 commit 1850c19

4 files changed

Lines changed: 119 additions & 2 deletions

File tree

setup.cfg

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ classifiers =
1313
Programming Language :: Python :: 3 :: Only
1414
Programming Language :: Python :: 3.9
1515
Programming Language :: Python :: 3.10
16+
Programming Language :: Python :: 3.11
1617
License :: OSI Approved :: GNU General Public License v3 (GPLv3)
1718

1819
[options]
@@ -24,13 +25,19 @@ python_requires = >=3.9
2425

2526
install_requires =
2627
mak-serialization-tools >= 2022.0a19
27-
relic-tool-core
28+
relic-tool-core >= 1.1.1
2829
fs
2930

3031
[options.entry_points]
3132
fs.opener =
3233
sga = relic.sga.core.filesystem:EssenceFSOpener
3334

35+
relic.cli =
36+
sga = relic.sga.core.cli:RelicSgaCli
37+
38+
relic.cli.sga =
39+
unpack = relic.sga.core.cli:RelicSgaUnpackCli
40+
pack = relic.sga.core.cli:RelicSgaPackCli
3441

3542
[options.packages.find]
3643
where = src

src/relic/sga/core/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
"""
44
from relic.sga.core.definitions import Version, MagicWord, StorageType, VerificationType
55

6-
__version__ = "1.0.1"
6+
__version__ = "1.1.0"

src/relic/sga/core/cli.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from __future__ import annotations
2+
3+
from argparse import ArgumentParser, Namespace
4+
from typing import Optional
5+
6+
import fs.copy
7+
from fs.base import FS
8+
from relic.core.cli import CliPluginGroup, _SubParsersAction, CliPlugin
9+
10+
11+
class RelicSgaCli(CliPluginGroup):
12+
GROUP = "relic.cli.sga"
13+
14+
def _create_parser(
15+
self, command_group: Optional[_SubParsersAction] = None
16+
) -> ArgumentParser:
17+
if command_group is None:
18+
return ArgumentParser("sga")
19+
else:
20+
return command_group.add_parser("sga")
21+
22+
23+
class RelicSgaUnpackCli(CliPlugin):
24+
def _create_parser(
25+
self, command_group: Optional[_SubParsersAction] = None
26+
) -> ArgumentParser:
27+
parser: ArgumentParser
28+
if command_group is None:
29+
parser = ArgumentParser("unpack")
30+
else:
31+
parser = command_group.add_parser("unpack")
32+
33+
parser.add_argument("src_sga", type=str, help="Source SGA File")
34+
parser.add_argument("out_dir", type=str, help="Output Directory")
35+
36+
return parser
37+
38+
def command(self, ns: Namespace) -> Optional[int]:
39+
infile: str = ns.src_sga
40+
outdir: str = ns.out_dir
41+
42+
print(f"Unpacking `{infile}`")
43+
44+
def _callback(_1: FS, srcfile: str, _2: FS, _3: str) -> None:
45+
print(f"\t\tUnpacking File `{srcfile}`")
46+
47+
fs.copy.copy_fs(f"sga://{infile}", f"osfs://{outdir}", on_copy=_callback)
48+
49+
return None # To shut-up mypy
50+
51+
52+
class RelicSgaPackCli(CliPluginGroup):
53+
GROUP = "relic.cli.sga.pack"
54+
55+
def _create_parser(
56+
self, command_group: Optional[_SubParsersAction] = None
57+
) -> ArgumentParser:
58+
parser: ArgumentParser
59+
if command_group is None:
60+
parser = ArgumentParser("pack")
61+
else:
62+
parser = command_group.add_parser("pack")
63+
64+
# pack further delegates to version plugins
65+
66+
return parser

tests/test_cli.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import io
2+
import subprocess
3+
4+
# Local testing requires running `pip install -e "."`
5+
from contextlib import redirect_stdout
6+
from typing import Sequence
7+
8+
import pytest
9+
10+
11+
class CommandTests:
12+
def test_run(self, args: Sequence[str], output: str, exit_code: int):
13+
_args = ["relic", *args]
14+
cmd = subprocess.run(_args, capture_output=True, text=True)
15+
result = cmd.stdout
16+
status = cmd.returncode
17+
print(f"'{result}'") # Visual Aid for Debugging
18+
assert output in result
19+
assert status == exit_code
20+
21+
def test_run_with(self, args: Sequence[str], output: str, exit_code: int):
22+
from relic.core.cli import cli_root
23+
24+
with io.StringIO() as f:
25+
with redirect_stdout(f):
26+
status = cli_root.run_with(*args)
27+
f.seek(0)
28+
result = f.read()
29+
print(f"'{result}'") # Visual Aid for Debugging
30+
assert output in result
31+
assert status == exit_code
32+
33+
34+
_SGA_HELP = ["sga", "-h"], """usage: relic sga [-h] {pack,unpack} ...""", 0
35+
_SGA_PACK_HELP = ["sga", "pack", "-h"], """usage: relic sga pack [-h] {} ...""", 0
36+
_SGA_UNPACK_HELP = ["sga", "unpack", "-h"], """usage: relic sga unpack [-h]""", 0
37+
38+
_TESTS = [_SGA_HELP, _SGA_PACK_HELP, _SGA_UNPACK_HELP]
39+
_TEST_IDS = [" ".join(_[0]) for _ in _TESTS]
40+
41+
42+
@pytest.mark.parametrize(["args", "output", "exit_code"], _TESTS, ids=_TEST_IDS)
43+
class TestRelicSgaCli(CommandTests):
44+
...

0 commit comments

Comments
 (0)