shvcli 0.6.2__tar.gz → 0.8.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.
- {shvcli-0.6.2/shvcli.egg-info → shvcli-0.8.0}/PKG-INFO +54 -18
- {shvcli-0.6.2 → shvcli-0.8.0}/README.rst +49 -13
- {shvcli-0.6.2 → shvcli-0.8.0}/pyproject.toml +5 -4
- shvcli-0.8.0/shvcli/__init__.py +55 -0
- shvcli-0.8.0/shvcli/__main__.py +35 -0
- shvcli-0.8.0/shvcli/__setuptools__.py +18 -0
- shvcli-0.8.0/shvcli/__version__.py +24 -0
- shvcli-0.8.0/shvcli/afterconn.py +55 -0
- shvcli-0.8.0/shvcli/args.py +56 -0
- shvcli-0.8.0/shvcli/builtin.py +86 -0
- shvcli-0.8.0/shvcli/builtins/__init__.py +29 -0
- shvcli-0.8.0/shvcli/builtins/broker.py +100 -0
- shvcli-0.8.0/shvcli/builtins/cd.py +37 -0
- shvcli-0.8.0/shvcli/builtins/file.py +128 -0
- shvcli-0.8.0/shvcli/builtins/help.py +58 -0
- shvcli-0.8.0/shvcli/builtins/history.py +146 -0
- shvcli-0.8.0/shvcli/builtins/scan.py +41 -0
- shvcli-0.8.0/shvcli/builtins/set.py +70 -0
- shvcli-0.8.0/shvcli/builtins/tree.py +66 -0
- shvcli-0.8.0/shvcli/cli.py +184 -0
- shvcli-0.8.0/shvcli/client.py +129 -0
- shvcli-0.8.0/shvcli/cliitems.py +91 -0
- shvcli-0.8.0/shvcli/complet.py +86 -0
- shvcli-0.8.0/shvcli/config.py +106 -0
- shvcli-0.8.0/shvcli/file.py +71 -0
- shvcli-0.8.0/shvcli/lsdir.py +128 -0
- shvcli-0.8.0/shvcli/oauth.py +75 -0
- shvcli-0.8.0/shvcli/option.py +267 -0
- shvcli-0.8.0/shvcli/options.py +168 -0
- {shvcli-0.6.2 → shvcli-0.8.0}/shvcli/scan.py +7 -7
- shvcli-0.8.0/shvcli/state.py +98 -0
- shvcli-0.8.0/shvcli/tools/__init__.py +1 -0
- shvcli-0.8.0/shvcli/tools/complet.py +60 -0
- shvcli-0.6.2/shvcli/tools.py → shvcli-0.8.0/shvcli/tools/print.py +23 -31
- shvcli-0.8.0/shvcli/tree.py +130 -0
- shvcli-0.8.0/shvcli/url.py +184 -0
- shvcli-0.8.0/shvcli/valid.py +78 -0
- {shvcli-0.6.2 → shvcli-0.8.0/shvcli.egg-info}/PKG-INFO +54 -18
- shvcli-0.8.0/shvcli.egg-info/SOURCES.txt +45 -0
- {shvcli-0.6.2 → shvcli-0.8.0}/shvcli.egg-info/requires.txt +2 -1
- shvcli-0.6.2/shvcli/__init__.py +0 -5
- shvcli-0.6.2/shvcli/__main__.py +0 -62
- shvcli-0.6.2/shvcli/__version__.py +0 -26
- shvcli-0.6.2/shvcli/builtin.py +0 -132
- shvcli-0.6.2/shvcli/builtin_impl.py +0 -193
- shvcli-0.6.2/shvcli/cli.py +0 -138
- shvcli-0.6.2/shvcli/client.py +0 -210
- shvcli-0.6.2/shvcli/complet.py +0 -78
- shvcli-0.6.2/shvcli/complet_tools.py +0 -64
- shvcli-0.6.2/shvcli/config.py +0 -176
- shvcli-0.6.2/shvcli/lsdir.py +0 -145
- shvcli-0.6.2/shvcli/parse.py +0 -79
- shvcli-0.6.2/shvcli/valid.py +0 -41
- shvcli-0.6.2/shvcli.egg-info/SOURCES.txt +0 -26
- {shvcli-0.6.2 → shvcli-0.8.0}/LICENSE +0 -0
- {shvcli-0.6.2 → shvcli-0.8.0}/setup.cfg +0 -0
- {shvcli-0.6.2 → shvcli-0.8.0}/shvcli/plugins.py +0 -0
- {shvcli-0.6.2 → shvcli-0.8.0}/shvcli/py.typed +0 -0
- {shvcli-0.6.2 → shvcli-0.8.0}/shvcli.egg-info/dependency_links.txt +0 -0
- {shvcli-0.6.2 → shvcli-0.8.0}/shvcli.egg-info/entry_points.txt +0 -0
- {shvcli-0.6.2 → shvcli-0.8.0}/shvcli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: shvcli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Silicon Heaven CLI access application
|
|
5
5
|
Author: Elektroline a.s.
|
|
6
6
|
License: MIT License
|
|
@@ -27,8 +27,6 @@ License: MIT License
|
|
|
27
27
|
|
|
28
28
|
Project-URL: repository, https://gitlab.com/silicon-heaven/shvcli
|
|
29
29
|
Classifier: Development Status :: 4 - Beta
|
|
30
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
31
|
-
Classifier: Programming Language :: Python :: 3
|
|
32
30
|
Classifier: Operating System :: OS Independent
|
|
33
31
|
Classifier: Environment :: Console
|
|
34
32
|
Classifier: Intended Audience :: End Users/Desktop
|
|
@@ -38,10 +36,12 @@ Classifier: Topic :: Terminals
|
|
|
38
36
|
Requires-Python: >=3.11
|
|
39
37
|
Description-Content-Type: text/x-rst
|
|
40
38
|
License-File: LICENSE
|
|
41
|
-
Requires-Dist: pyshv>=0.
|
|
39
|
+
Requires-Dist: pyshv>=0.10.0
|
|
42
40
|
Requires-Dist: prompt_toolkit
|
|
43
41
|
Requires-Dist: pygments
|
|
44
42
|
Requires-Dist: pyxdg
|
|
43
|
+
Requires-Dist: more-itertools
|
|
44
|
+
Dynamic: license-file
|
|
45
45
|
|
|
46
46
|
=====================================
|
|
47
47
|
Silicon Heaven CLI access application
|
|
@@ -101,20 +101,25 @@ An example of usage:
|
|
|
101
101
|
.app> /:
|
|
102
102
|
>
|
|
103
103
|
|
|
104
|
+
.. TIP::
|
|
105
|
+
The validation that is performed by SHVCLI is best effort and sometimes you
|
|
106
|
+
might need to submit call that is considered invalid by SHVCLI. For that
|
|
107
|
+
reason you can use `Ctrl+o` shortcut instead of pressing enter key.
|
|
108
|
+
|
|
104
109
|
|
|
105
110
|
Configuration file
|
|
106
111
|
------------------
|
|
107
112
|
|
|
108
|
-
Tool reads configuration from files ``/etc/shvcli.
|
|
109
|
-
They are in
|
|
113
|
+
Tool reads configuration from files ``/etc/shvcli.toml`` and ``~/.shvcli.toml``.
|
|
114
|
+
They are in TOML file format and the following sections are supported:
|
|
110
115
|
|
|
111
116
|
**hosts**: That provides mapping from some name to RPC URL.
|
|
112
117
|
|
|
113
118
|
**hosts-shell**: That is same as **hosts** with exception that URL is passed
|
|
114
119
|
through your local Shell to expand any variables or command substitutions.
|
|
115
120
|
|
|
116
|
-
**
|
|
117
|
-
|
|
121
|
+
**option**: That allows you to set initial setting for runtime options. The
|
|
122
|
+
following options are available without any plugins:
|
|
118
123
|
|
|
119
124
|
* **vimode**: If Vi input mode should be used for command line input. The
|
|
120
125
|
default is ``false``.
|
|
@@ -137,16 +142,16 @@ switched in runtime. The following options are available:
|
|
|
137
142
|
be also overwhelming. The default is ``false``. It is beneficial to disable
|
|
138
143
|
the **autobrobe** once you enable debug because otherwise output on CLI will
|
|
139
144
|
be mangled on completion.
|
|
140
|
-
* **
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
* **
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
* **autoget_timeout**: Timeout in seconds before call that is part of autoget
|
|
145
|
+
* **call_query_timeout**: Timeout in seconds for status request query. The
|
|
146
|
+
shorter time will result in faster request lost detection while very short
|
|
147
|
+
time will load SHV network too much.
|
|
148
|
+
* **call_retry_timeout**: Timeout in seconds when call request is sent again if
|
|
149
|
+
no response is received. This is not applied if query is and thus this mostly
|
|
150
|
+
is used only in case when method doesn't support delayed responses.
|
|
151
|
+
* **autoget_timeout**: Timeout in seconds for call that is part of autoget
|
|
148
152
|
functionality.
|
|
149
|
-
|
|
153
|
+
* **history_count**: Integer number used for number of records requested at time
|
|
154
|
+
for ``!history`` builtin.
|
|
150
155
|
|
|
151
156
|
Example configuration file:
|
|
152
157
|
|
|
@@ -200,6 +205,19 @@ disable ``raw`` you use ``noraw``). You can also add ``=true`` or ``=false``.
|
|
|
200
205
|
The equal sign is also used with integer and floating point options. Without any
|
|
201
206
|
configuration option it simply prints the current configuration.
|
|
202
207
|
|
|
208
|
+
**upload**: provides a way to copy local file to the RPC File node. The
|
|
209
|
+
parameter must be path to the local file to be uploaded.
|
|
210
|
+
|
|
211
|
+
**download**: provides a way to copy RPC File node data to local file. The
|
|
212
|
+
parameter must be path to the local file where data will be stored.
|
|
213
|
+
|
|
214
|
+
**verify**: provides a way to verify RPC File node against local file. The
|
|
215
|
+
parameter must be path to the local file used for the verification.
|
|
216
|
+
|
|
217
|
+
**history**: is helper to list recorded history of signals by ``.history`` API.
|
|
218
|
+
The listing is incremental in ``history_count`` configured number of records and
|
|
219
|
+
in the order from the newest ones.
|
|
220
|
+
|
|
203
221
|
|
|
204
222
|
Special methods ``ls`` and ``dir``
|
|
205
223
|
----------------------------------
|
|
@@ -211,3 +229,21 @@ the fullest content.
|
|
|
211
229
|
Their parameter is also handled in a special way. It is considered to be
|
|
212
230
|
additional path suffix unless it is a valid CPON. This is allowed to match the
|
|
213
231
|
common shells.
|
|
232
|
+
|
|
233
|
+
You can see ``raw`` option to disable this behavior.
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
OAuth2 login
|
|
237
|
+
------------
|
|
238
|
+
|
|
239
|
+
SHVCLI supports non-standard login method OAuth2. This is not defined by SHV
|
|
240
|
+
standard. The non-standard URL query ``oauth2=y`` is accepted to perform the
|
|
241
|
+
OAuth2 login. The login is facilitated by web browser. SHVCLI will start server
|
|
242
|
+
on ``tcp://localhost:37719/`` to be able to receive token.
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
Plugins
|
|
246
|
+
-------
|
|
247
|
+
|
|
248
|
+
The support for external plugins is provided. These plugins are discovered using
|
|
249
|
+
Python package metadata using the entry point ``shvcli.plugins``.
|
|
@@ -56,20 +56,25 @@ An example of usage:
|
|
|
56
56
|
.app> /:
|
|
57
57
|
>
|
|
58
58
|
|
|
59
|
+
.. TIP::
|
|
60
|
+
The validation that is performed by SHVCLI is best effort and sometimes you
|
|
61
|
+
might need to submit call that is considered invalid by SHVCLI. For that
|
|
62
|
+
reason you can use `Ctrl+o` shortcut instead of pressing enter key.
|
|
63
|
+
|
|
59
64
|
|
|
60
65
|
Configuration file
|
|
61
66
|
------------------
|
|
62
67
|
|
|
63
|
-
Tool reads configuration from files ``/etc/shvcli.
|
|
64
|
-
They are in
|
|
68
|
+
Tool reads configuration from files ``/etc/shvcli.toml`` and ``~/.shvcli.toml``.
|
|
69
|
+
They are in TOML file format and the following sections are supported:
|
|
65
70
|
|
|
66
71
|
**hosts**: That provides mapping from some name to RPC URL.
|
|
67
72
|
|
|
68
73
|
**hosts-shell**: That is same as **hosts** with exception that URL is passed
|
|
69
74
|
through your local Shell to expand any variables or command substitutions.
|
|
70
75
|
|
|
71
|
-
**
|
|
72
|
-
|
|
76
|
+
**option**: That allows you to set initial setting for runtime options. The
|
|
77
|
+
following options are available without any plugins:
|
|
73
78
|
|
|
74
79
|
* **vimode**: If Vi input mode should be used for command line input. The
|
|
75
80
|
default is ``false``.
|
|
@@ -92,16 +97,16 @@ switched in runtime. The following options are available:
|
|
|
92
97
|
be also overwhelming. The default is ``false``. It is beneficial to disable
|
|
93
98
|
the **autobrobe** once you enable debug because otherwise output on CLI will
|
|
94
99
|
be mangled on completion.
|
|
95
|
-
* **
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
* **
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
* **autoget_timeout**: Timeout in seconds before call that is part of autoget
|
|
100
|
+
* **call_query_timeout**: Timeout in seconds for status request query. The
|
|
101
|
+
shorter time will result in faster request lost detection while very short
|
|
102
|
+
time will load SHV network too much.
|
|
103
|
+
* **call_retry_timeout**: Timeout in seconds when call request is sent again if
|
|
104
|
+
no response is received. This is not applied if query is and thus this mostly
|
|
105
|
+
is used only in case when method doesn't support delayed responses.
|
|
106
|
+
* **autoget_timeout**: Timeout in seconds for call that is part of autoget
|
|
103
107
|
functionality.
|
|
104
|
-
|
|
108
|
+
* **history_count**: Integer number used for number of records requested at time
|
|
109
|
+
for ``!history`` builtin.
|
|
105
110
|
|
|
106
111
|
Example configuration file:
|
|
107
112
|
|
|
@@ -155,6 +160,19 @@ disable ``raw`` you use ``noraw``). You can also add ``=true`` or ``=false``.
|
|
|
155
160
|
The equal sign is also used with integer and floating point options. Without any
|
|
156
161
|
configuration option it simply prints the current configuration.
|
|
157
162
|
|
|
163
|
+
**upload**: provides a way to copy local file to the RPC File node. The
|
|
164
|
+
parameter must be path to the local file to be uploaded.
|
|
165
|
+
|
|
166
|
+
**download**: provides a way to copy RPC File node data to local file. The
|
|
167
|
+
parameter must be path to the local file where data will be stored.
|
|
168
|
+
|
|
169
|
+
**verify**: provides a way to verify RPC File node against local file. The
|
|
170
|
+
parameter must be path to the local file used for the verification.
|
|
171
|
+
|
|
172
|
+
**history**: is helper to list recorded history of signals by ``.history`` API.
|
|
173
|
+
The listing is incremental in ``history_count`` configured number of records and
|
|
174
|
+
in the order from the newest ones.
|
|
175
|
+
|
|
158
176
|
|
|
159
177
|
Special methods ``ls`` and ``dir``
|
|
160
178
|
----------------------------------
|
|
@@ -166,3 +184,21 @@ the fullest content.
|
|
|
166
184
|
Their parameter is also handled in a special way. It is considered to be
|
|
167
185
|
additional path suffix unless it is a valid CPON. This is allowed to match the
|
|
168
186
|
common shells.
|
|
187
|
+
|
|
188
|
+
You can see ``raw`` option to disable this behavior.
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
OAuth2 login
|
|
192
|
+
------------
|
|
193
|
+
|
|
194
|
+
SHVCLI supports non-standard login method OAuth2. This is not defined by SHV
|
|
195
|
+
standard. The non-standard URL query ``oauth2=y`` is accepted to perform the
|
|
196
|
+
OAuth2 login. The login is facilitated by web browser. SHVCLI will start server
|
|
197
|
+
on ``tcp://localhost:37719/`` to be able to receive token.
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
Plugins
|
|
201
|
+
-------
|
|
202
|
+
|
|
203
|
+
The support for external plugins is provided. These plugins are discovered using
|
|
204
|
+
Python package metadata using the entry point ``shvcli.plugins``.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "shvcli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.8.0"
|
|
4
4
|
description = "Silicon Heaven CLI access application"
|
|
5
5
|
readme = "README.rst"
|
|
6
6
|
license = {file = "LICENSE"}
|
|
@@ -9,8 +9,6 @@ authors = [
|
|
|
9
9
|
]
|
|
10
10
|
classifiers = [
|
|
11
11
|
"Development Status :: 4 - Beta",
|
|
12
|
-
"License :: OSI Approved :: MIT License",
|
|
13
|
-
"Programming Language :: Python :: 3",
|
|
14
12
|
"Operating System :: OS Independent",
|
|
15
13
|
"Environment :: Console",
|
|
16
14
|
"Intended Audience :: End Users/Desktop",
|
|
@@ -20,10 +18,11 @@ classifiers = [
|
|
|
20
18
|
]
|
|
21
19
|
requires-python = ">=3.11"
|
|
22
20
|
dependencies = [
|
|
23
|
-
"pyshv >= 0.
|
|
21
|
+
"pyshv >= 0.10.0",
|
|
24
22
|
"prompt_toolkit",
|
|
25
23
|
"pygments",
|
|
26
24
|
"pyxdg",
|
|
25
|
+
"more-itertools",
|
|
27
26
|
]
|
|
28
27
|
|
|
29
28
|
[project.urls]
|
|
@@ -39,6 +38,8 @@ build-backend = "setuptools.build_meta"
|
|
|
39
38
|
[tool.setuptools.packages.find]
|
|
40
39
|
[tool.setuptools.package-data]
|
|
41
40
|
"*" = ["py.typed"]
|
|
41
|
+
[tool.setuptools.cmdclass]
|
|
42
|
+
build_py = "shvcli.__setuptools__.BuildPy"
|
|
42
43
|
|
|
43
44
|
[tool.coverage.run]
|
|
44
45
|
branch = true
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Silicon Heaven Command Line Interface."""
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
|
|
5
|
+
from .__version__ import VERSION
|
|
6
|
+
from .args import register_argparser
|
|
7
|
+
from .builtin import Builtin, Builtins
|
|
8
|
+
from .client import Client
|
|
9
|
+
from .cliitems import CliItems
|
|
10
|
+
from .config import Config, ConfigError, register_config
|
|
11
|
+
from .option import BoolOption, FloatOption, IntOption, Option
|
|
12
|
+
from .options import (
|
|
13
|
+
AutoGetOption,
|
|
14
|
+
AutoGetTimeoutOption,
|
|
15
|
+
AutoProbeOption,
|
|
16
|
+
CallDuration,
|
|
17
|
+
CallQueryTimeout,
|
|
18
|
+
CallRetryTimeout,
|
|
19
|
+
DebugOption,
|
|
20
|
+
RawOption,
|
|
21
|
+
ViModeOption,
|
|
22
|
+
)
|
|
23
|
+
from .state import State, StateVar
|
|
24
|
+
from .tree import Node, Tree
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"VERSION",
|
|
28
|
+
"AutoGetOption",
|
|
29
|
+
"AutoGetTimeoutOption",
|
|
30
|
+
"AutoProbeOption",
|
|
31
|
+
"BoolOption",
|
|
32
|
+
"Builtin",
|
|
33
|
+
"Builtins",
|
|
34
|
+
"CallDuration",
|
|
35
|
+
"CallQueryTimeout",
|
|
36
|
+
"CallRetryTimeout",
|
|
37
|
+
"CliItems",
|
|
38
|
+
"Client",
|
|
39
|
+
"Config",
|
|
40
|
+
"ConfigError",
|
|
41
|
+
"DebugOption",
|
|
42
|
+
"FloatOption",
|
|
43
|
+
"IntOption",
|
|
44
|
+
"Node",
|
|
45
|
+
"Option",
|
|
46
|
+
"RawOption",
|
|
47
|
+
"State",
|
|
48
|
+
"StateVar",
|
|
49
|
+
"Tree",
|
|
50
|
+
"ViModeOption",
|
|
51
|
+
"register_argparser",
|
|
52
|
+
"register_config",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
importlib.import_module(".builtins", package=__package__)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Implementation of command line application."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
5
|
+
from .afterconn import Afterconn
|
|
6
|
+
from .args import args_apply, args_parse
|
|
7
|
+
from .cli import run
|
|
8
|
+
from .config import load_config
|
|
9
|
+
from .plugins import load_plugins
|
|
10
|
+
from .state import State
|
|
11
|
+
from .url import Url
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main() -> None:
|
|
15
|
+
"""Application's entrypoint."""
|
|
16
|
+
load_plugins()
|
|
17
|
+
argsgens, args = args_parse()
|
|
18
|
+
state = State()
|
|
19
|
+
load_config(args.config, state)
|
|
20
|
+
args_apply(argsgens, args, state)
|
|
21
|
+
state.cache_load(Url(state).cache_path())
|
|
22
|
+
|
|
23
|
+
async def async_main() -> None:
|
|
24
|
+
client = await Url(state).connect()
|
|
25
|
+
await Afterconn(state).run(client)
|
|
26
|
+
await run(client)
|
|
27
|
+
if client.client.connected:
|
|
28
|
+
await client.disconnect()
|
|
29
|
+
|
|
30
|
+
asyncio.run(async_main())
|
|
31
|
+
state.cache_dump(Url(state).cache_path())
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
if __name__ == "__main__":
|
|
35
|
+
main()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Setuptools hook used to replace __version__.py file."""
|
|
2
|
+
|
|
3
|
+
import pathlib
|
|
4
|
+
|
|
5
|
+
from setuptools.command.build_py import build_py as _build_py
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BuildPy(_build_py):
|
|
9
|
+
"""Custom package build step."""
|
|
10
|
+
|
|
11
|
+
def run(self) -> None: # noqa: D102
|
|
12
|
+
package = pathlib.Path(__file__).parent.name
|
|
13
|
+
buildlib = pathlib.Path(self.build_lib) / package
|
|
14
|
+
buildlib.mkdir(parents=True, exist_ok=True)
|
|
15
|
+
version = self.distribution.metadata.version
|
|
16
|
+
(buildlib / "__version__.py").write_text(f'VERSION = "{version}"\n')
|
|
17
|
+
super().run()
|
|
18
|
+
(buildlib / "__setuptools__.py").unlink()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""The loader of the version for source file only installation.
|
|
2
|
+
|
|
3
|
+
It looks for pyproject.toml file in upper directory and loads version from
|
|
4
|
+
there.
|
|
5
|
+
|
|
6
|
+
This file is overwritten during distribution build to contain only constant
|
|
7
|
+
VERSION. Please see __setuptools__.py for details.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import pathlib
|
|
11
|
+
import tomllib
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _get_version() -> str:
|
|
15
|
+
pyproject = pathlib.Path(__file__).parent.parent / "pyproject.toml"
|
|
16
|
+
if pyproject.exists():
|
|
17
|
+
with pyproject.open("rb") as f:
|
|
18
|
+
res = tomllib.load(f)["project"]["version"]
|
|
19
|
+
if isinstance(res, str):
|
|
20
|
+
return res
|
|
21
|
+
return "unknown"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
VERSION = _get_version()
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""The after connection tasks."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import collections.abc
|
|
5
|
+
import typing
|
|
6
|
+
|
|
7
|
+
from .args import ArgsParseFuncGenT, register_argparser
|
|
8
|
+
from .client import Client, SHVPath
|
|
9
|
+
from .cliitems import CliItems
|
|
10
|
+
from .scan import scan_nodes
|
|
11
|
+
from .state import StateVar
|
|
12
|
+
|
|
13
|
+
AfterConnT: typing.TypeAlias = collections.abc.Callable[
|
|
14
|
+
[Client], collections.abc.Coroutine[None, None, None]
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Afterconn(StateVar, list[AfterConnT]):
|
|
19
|
+
"""The set of operations to be performed right after connection."""
|
|
20
|
+
|
|
21
|
+
async def run(self, client: Client) -> None:
|
|
22
|
+
"""Run the steps setup to be performed after connection at startup."""
|
|
23
|
+
for func in self:
|
|
24
|
+
await func(client)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@register_argparser
|
|
28
|
+
def _argparser(parser: argparse.ArgumentParser) -> ArgsParseFuncGenT:
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"-s",
|
|
31
|
+
"--subscribe",
|
|
32
|
+
action="append",
|
|
33
|
+
default=[],
|
|
34
|
+
help="Automatic subscription right after connection.",
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"--scan",
|
|
38
|
+
action="store_true",
|
|
39
|
+
help="Perform scan as a first action right after connect.",
|
|
40
|
+
)
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--scan-depth",
|
|
43
|
+
type=int,
|
|
44
|
+
default=3,
|
|
45
|
+
help="Depth of the scan performed if --scan is used.",
|
|
46
|
+
)
|
|
47
|
+
args, state = yield
|
|
48
|
+
|
|
49
|
+
async def afterconn(client: Client) -> None:
|
|
50
|
+
for ri in args.subscribe:
|
|
51
|
+
await client.subscribe(CliItems.extend_ri(ri))
|
|
52
|
+
if args.scan:
|
|
53
|
+
await scan_nodes(client, SHVPath(""), args.scan_dept)
|
|
54
|
+
|
|
55
|
+
Afterconn(state).append(afterconn)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Argument parser wrapper for the SHVCLI."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import collections.abc
|
|
5
|
+
import contextlib
|
|
6
|
+
import pathlib
|
|
7
|
+
import typing
|
|
8
|
+
|
|
9
|
+
from .__version__ import VERSION
|
|
10
|
+
from .state import State
|
|
11
|
+
|
|
12
|
+
ArgsParseFuncGenT: typing.TypeAlias = collections.abc.Generator[
|
|
13
|
+
None, tuple[argparse.Namespace, State], None
|
|
14
|
+
]
|
|
15
|
+
ArgsparseFuncT: typing.TypeAlias = collections.abc.Callable[
|
|
16
|
+
[argparse.ArgumentParser], ArgsParseFuncGenT
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
registered_functions: list[ArgsparseFuncT] = []
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def register_argparser(func: ArgsparseFuncT) -> None:
|
|
23
|
+
"""Decorate function to register it to be called when arguments are being parsed."""
|
|
24
|
+
registered_functions.append(func)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def args_parse() -> tuple[tuple[ArgsParseFuncGenT, ...], argparse.Namespace]:
|
|
28
|
+
"""Parse passed arguments and return result."""
|
|
29
|
+
parser = argparse.ArgumentParser(prog="shvcli", description="Silicon Heaven CLI")
|
|
30
|
+
parser.add_argument("--version", action="version", version="%(prog)s " + VERSION)
|
|
31
|
+
parser.add_argument(
|
|
32
|
+
"-c",
|
|
33
|
+
"--config",
|
|
34
|
+
action="append",
|
|
35
|
+
type=pathlib.Path,
|
|
36
|
+
default=[pathlib.Path("/etc/shvcli.toml"), pathlib.Path("~/.shvcli.toml")],
|
|
37
|
+
)
|
|
38
|
+
gens = tuple(func(parser) for func in registered_functions)
|
|
39
|
+
for gen in gens:
|
|
40
|
+
next(gen)
|
|
41
|
+
args = parser.parse_args()
|
|
42
|
+
return gens, args
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def args_apply(
|
|
46
|
+
gens: tuple[ArgsParseFuncGenT, ...], args: argparse.Namespace, state: State
|
|
47
|
+
) -> None:
|
|
48
|
+
"""Apply parsed arguments on the given state.
|
|
49
|
+
|
|
50
|
+
The parsed arguments should be applied after configuration but
|
|
51
|
+
configuration loading needs to be influenced by arguments and thus split
|
|
52
|
+
arguments parsing to the parsing and application phase.
|
|
53
|
+
"""
|
|
54
|
+
for gen in gens:
|
|
55
|
+
with contextlib.suppress(StopIteration):
|
|
56
|
+
gen.send((args, state))
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Builtin methods glue code so they can be defined separatelly."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import abc
|
|
6
|
+
import collections.abc
|
|
7
|
+
import inspect
|
|
8
|
+
import typing
|
|
9
|
+
|
|
10
|
+
from prompt_toolkit.completion import Completion
|
|
11
|
+
|
|
12
|
+
from .client import Client
|
|
13
|
+
from .cliitems import CliItems
|
|
14
|
+
from .state import State, StateVar
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Builtin(abc.ABC):
|
|
18
|
+
"""The single builtin definition."""
|
|
19
|
+
|
|
20
|
+
builtins: typing.Final[list[type[Builtin]]] = []
|
|
21
|
+
|
|
22
|
+
def __init_subclass__(cls, *args: typing.Any, **kwargs: typing.Any) -> None: # noqa: ANN401
|
|
23
|
+
super().__init_subclass__(*args, **kwargs)
|
|
24
|
+
Builtin.builtins.append(cls)
|
|
25
|
+
|
|
26
|
+
def __init__(self, builtins: Builtins, state: State) -> None:
|
|
27
|
+
self.state = state
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
@abc.abstractmethod
|
|
31
|
+
def description(self) -> tuple[str, str]:
|
|
32
|
+
"""The provider of the description of this builtin.
|
|
33
|
+
|
|
34
|
+
:return: The first string is description of arguments expected by
|
|
35
|
+
builtin and the second one is the builtin description.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def completion( # noqa: PLR6301
|
|
39
|
+
self, items: CliItems, client: Client
|
|
40
|
+
) -> collections.abc.Iterable[Completion]:
|
|
41
|
+
"""Parameter completion for this builtin."""
|
|
42
|
+
return tuple()
|
|
43
|
+
|
|
44
|
+
async def completion_async( # noqa: PLR6301
|
|
45
|
+
self, items: CliItems, client: Client
|
|
46
|
+
) -> collections.abc.AsyncGenerator[Completion, None]:
|
|
47
|
+
"""Asynchronous parameter completion for this builtin.
|
|
48
|
+
|
|
49
|
+
This is used only if :class:`AutoProbeOption` is enabled.
|
|
50
|
+
|
|
51
|
+
It is common that this only fetches the required data with client and
|
|
52
|
+
the completion is performed in :meth:`completion` only.
|
|
53
|
+
"""
|
|
54
|
+
return
|
|
55
|
+
yield # type: ignore
|
|
56
|
+
|
|
57
|
+
def validate(self, items: CliItems, client: Client) -> None: # noqa: PLR6301
|
|
58
|
+
"""Validate the parameter for this builtin."""
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
async def validate_async(self, items: CliItems, client: Client) -> None: # noqa: PLR6301
|
|
62
|
+
"""Asynchronously validate the parameter for this builtin.
|
|
63
|
+
|
|
64
|
+
This is used only if :class:`AutoProbeOption` is enabled.
|
|
65
|
+
|
|
66
|
+
It is common that this only fetches the required data with client and
|
|
67
|
+
the validation is performed in :meth:`validate` only. SHVCLI also
|
|
68
|
+
always uses completion and validation together and because completion
|
|
69
|
+
happens alongside with validation it is rather common to do this
|
|
70
|
+
probing in the :meth:`completion_async` only.
|
|
71
|
+
"""
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
@abc.abstractmethod
|
|
75
|
+
async def run(self, items: CliItems, client: Client) -> None:
|
|
76
|
+
"""Run the builtin."""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class Builtins(StateVar, dict[str, Builtin]):
|
|
80
|
+
"""All initialized builtins."""
|
|
81
|
+
|
|
82
|
+
def __init__(self, state: State) -> None:
|
|
83
|
+
super().__init__(state)
|
|
84
|
+
for builtin in Builtin.builtins:
|
|
85
|
+
if not inspect.isabstract(builtin):
|
|
86
|
+
builtin(self, state)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""All standard builtins.
|
|
2
|
+
|
|
3
|
+
This module is imported in the top level init and thus all builtins imported
|
|
4
|
+
here are automatically registered.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .broker import BuiltinSubscribe, BuiltinSubscriptions, BuiltinUnsubscribe
|
|
8
|
+
from .cd import BuiltinCD
|
|
9
|
+
from .file import BuiltinDownload, BuiltinUpload, BuiltinVerify
|
|
10
|
+
from .help import BuiltinHelp
|
|
11
|
+
from .history import BuiltinHistory
|
|
12
|
+
from .scan import BuiltinScan
|
|
13
|
+
from .set import BuiltinSet
|
|
14
|
+
from .tree import BuiltinTree
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"BuiltinCD",
|
|
18
|
+
"BuiltinDownload",
|
|
19
|
+
"BuiltinHelp",
|
|
20
|
+
"BuiltinHistory",
|
|
21
|
+
"BuiltinScan",
|
|
22
|
+
"BuiltinSet",
|
|
23
|
+
"BuiltinSubscribe",
|
|
24
|
+
"BuiltinSubscriptions",
|
|
25
|
+
"BuiltinTree",
|
|
26
|
+
"BuiltinUnsubscribe",
|
|
27
|
+
"BuiltinUpload",
|
|
28
|
+
"BuiltinVerify",
|
|
29
|
+
]
|