moat-kv 0.71.0__py3-none-any.whl → 0.71.7__py3-none-any.whl
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.
- moat/kv/__init__.py +6 -7
- moat/kv/_cfg.yaml +3 -2
- moat/kv/actor/__init__.py +2 -1
- moat/kv/actor/deletor.py +4 -1
- moat/kv/auth/__init__.py +12 -13
- moat/kv/auth/_test.py +4 -1
- moat/kv/auth/password.py +11 -7
- moat/kv/backend/mqtt.py +4 -5
- moat/kv/client.py +20 -39
- moat/kv/code.py +3 -3
- moat/kv/command/data.py +4 -3
- moat/kv/command/dump/__init__.py +36 -34
- moat/kv/command/internal.py +2 -3
- moat/kv/command/job.py +1 -2
- moat/kv/command/type.py +3 -6
- moat/kv/data.py +9 -8
- moat/kv/errors.py +16 -8
- moat/kv/mock/__init__.py +2 -12
- moat/kv/model.py +29 -33
- moat/kv/obj/__init__.py +3 -3
- moat/kv/obj/command.py +3 -3
- moat/kv/runner.py +4 -5
- moat/kv/server.py +106 -126
- moat/kv/types.py +10 -12
- {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/METADATA +6 -2
- moat_kv-0.71.7.dist-info/RECORD +47 -0
- {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/WHEEL +1 -1
- moat_kv-0.71.7.dist-info/licenses/LICENSE +3 -0
- moat_kv-0.71.7.dist-info/licenses/LICENSE.APACHE2 +202 -0
- moat_kv-0.71.7.dist-info/licenses/LICENSE.MIT +20 -0
- moat_kv-0.71.7.dist-info/top_level.txt +1 -0
- build/lib/docs/source/conf.py +0 -201
- build/lib/examples/pathify.py +0 -45
- build/lib/moat/kv/__init__.py +0 -19
- build/lib/moat/kv/_cfg.yaml +0 -93
- build/lib/moat/kv/_main.py +0 -91
- build/lib/moat/kv/actor/__init__.py +0 -98
- build/lib/moat/kv/actor/deletor.py +0 -139
- build/lib/moat/kv/auth/__init__.py +0 -444
- build/lib/moat/kv/auth/_test.py +0 -166
- build/lib/moat/kv/auth/password.py +0 -234
- build/lib/moat/kv/auth/root.py +0 -58
- build/lib/moat/kv/backend/__init__.py +0 -67
- build/lib/moat/kv/backend/mqtt.py +0 -71
- build/lib/moat/kv/client.py +0 -1025
- build/lib/moat/kv/code.py +0 -236
- build/lib/moat/kv/codec.py +0 -11
- build/lib/moat/kv/command/__init__.py +0 -1
- build/lib/moat/kv/command/acl.py +0 -180
- build/lib/moat/kv/command/auth.py +0 -261
- build/lib/moat/kv/command/code.py +0 -293
- build/lib/moat/kv/command/codec.py +0 -186
- build/lib/moat/kv/command/data.py +0 -265
- build/lib/moat/kv/command/dump/__init__.py +0 -143
- build/lib/moat/kv/command/error.py +0 -149
- build/lib/moat/kv/command/internal.py +0 -248
- build/lib/moat/kv/command/job.py +0 -433
- build/lib/moat/kv/command/log.py +0 -53
- build/lib/moat/kv/command/server.py +0 -114
- build/lib/moat/kv/command/type.py +0 -201
- build/lib/moat/kv/config.py +0 -46
- build/lib/moat/kv/data.py +0 -216
- build/lib/moat/kv/errors.py +0 -561
- build/lib/moat/kv/exceptions.py +0 -126
- build/lib/moat/kv/mock/__init__.py +0 -101
- build/lib/moat/kv/mock/mqtt.py +0 -159
- build/lib/moat/kv/mock/tracer.py +0 -63
- build/lib/moat/kv/model.py +0 -1069
- build/lib/moat/kv/obj/__init__.py +0 -646
- build/lib/moat/kv/obj/command.py +0 -241
- build/lib/moat/kv/runner.py +0 -1347
- build/lib/moat/kv/server.py +0 -2809
- build/lib/moat/kv/types.py +0 -513
- ci/rtd-requirements.txt +0 -4
- ci/test-requirements.txt +0 -7
- ci/travis.sh +0 -96
- debian/.gitignore +0 -7
- debian/changelog +0 -1435
- debian/control +0 -43
- debian/moat-kv/usr/lib/python3/dist-packages/docs/source/conf.py +0 -201
- debian/moat-kv/usr/lib/python3/dist-packages/examples/pathify.py +0 -45
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/__init__.py +0 -19
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_cfg.yaml +0 -93
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_main.py +0 -91
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/__init__.py +0 -98
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/deletor.py +0 -139
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/__init__.py +0 -444
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/_test.py +0 -166
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/password.py +0 -234
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/root.py +0 -58
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/__init__.py +0 -67
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/mqtt.py +0 -71
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/client.py +0 -1025
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/code.py +0 -236
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/codec.py +0 -11
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/__init__.py +0 -1
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/acl.py +0 -180
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/auth.py +0 -261
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/code.py +0 -293
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/codec.py +0 -186
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/data.py +0 -265
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/dump/__init__.py +0 -143
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/error.py +0 -149
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/internal.py +0 -248
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/job.py +0 -433
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/log.py +0 -53
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/server.py +0 -114
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/type.py +0 -201
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/config.py +0 -46
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/data.py +0 -216
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/errors.py +0 -561
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/exceptions.py +0 -126
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/__init__.py +0 -101
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/mqtt.py +0 -159
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/tracer.py +0 -63
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/model.py +0 -1069
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/__init__.py +0 -646
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/command.py +0 -241
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/runner.py +0 -1347
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/server.py +0 -2809
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/types.py +0 -513
- debian/moat-kv.postinst +0 -3
- debian/rules +0 -20
- debian/source/format +0 -1
- debian/watch +0 -4
- docs/Makefile +0 -20
- docs/make.bat +0 -36
- docs/source/TODO.rst +0 -61
- docs/source/_static/.gitkeep +0 -0
- docs/source/acls.rst +0 -80
- docs/source/auth.rst +0 -84
- docs/source/client_protocol.rst +0 -456
- docs/source/code.rst +0 -341
- docs/source/command_line.rst +0 -1187
- docs/source/common_protocol.rst +0 -47
- docs/source/conf.py +0 -201
- docs/source/debugging.rst +0 -70
- docs/source/extend.rst +0 -37
- docs/source/history.rst +0 -36
- docs/source/index.rst +0 -75
- docs/source/model.rst +0 -54
- docs/source/overview.rst +0 -83
- docs/source/related.rst +0 -89
- docs/source/server_protocol.rst +0 -450
- docs/source/startup.rst +0 -31
- docs/source/translator.rst +0 -244
- docs/source/tutorial.rst +0 -711
- docs/source/v3.rst +0 -168
- examples/code/transform.scale.yml +0 -21
- examples/code/transform.switch.yml +0 -82
- examples/code/transform.timeslot.yml +0 -63
- examples/pathify.py +0 -45
- moat/kv/codec.py +0 -11
- moat_kv-0.71.0.dist-info/RECORD +0 -188
- moat_kv-0.71.0.dist-info/top_level.txt +0 -9
- scripts/current +0 -15
- scripts/env +0 -8
- scripts/init +0 -39
- scripts/recover +0 -17
- scripts/rotate +0 -33
- scripts/run +0 -29
- scripts/run-all +0 -10
- scripts/run-any +0 -10
- scripts/run-single +0 -15
- scripts/success +0 -4
- systemd/moat-kv-recover.service +0 -21
- systemd/moat-kv-rotate.service +0 -20
- systemd/moat-kv-rotate.timer +0 -10
- systemd/moat-kv-run-all.service +0 -26
- systemd/moat-kv-run-all@.service +0 -25
- systemd/moat-kv-run-any.service +0 -26
- systemd/moat-kv-run-any@.service +0 -25
- systemd/moat-kv-run-single.service +0 -26
- systemd/moat-kv-run-single@.service +0 -25
- systemd/moat-kv.service +0 -27
- systemd/postinst +0 -7
- systemd/sysusers +0 -3
- {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/licenses/LICENSE.txt +0 -0
build/lib/moat/kv/command/log.py
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
# command line interface
|
2
|
-
from __future__ import annotations
|
3
|
-
|
4
|
-
import asyncclick as click
|
5
|
-
from moat.util import yprint
|
6
|
-
|
7
|
-
|
8
|
-
@click.group(short_help="Manage logging.") # pylint: disable=undefined-variable
|
9
|
-
async def cli():
|
10
|
-
"""
|
11
|
-
This subcommand controls a server's logging.
|
12
|
-
"""
|
13
|
-
pass
|
14
|
-
|
15
|
-
|
16
|
-
@cli.command()
|
17
|
-
@click.option("-i", "--incremental", is_flag=True, help="Don't write the initial state")
|
18
|
-
@click.argument("path", nargs=1)
|
19
|
-
@click.pass_obj
|
20
|
-
async def dest(obj, path, incremental):
|
21
|
-
"""
|
22
|
-
Log changes to a file.
|
23
|
-
|
24
|
-
Any previously open log (on the server you talk to) is closed as soon
|
25
|
-
as the new one is opened and ready.
|
26
|
-
"""
|
27
|
-
res = await obj.client._request("log", path=path, fetch=not incremental)
|
28
|
-
if obj.meta:
|
29
|
-
yprint(res, stream=obj.stdout)
|
30
|
-
|
31
|
-
|
32
|
-
@cli.command()
|
33
|
-
@click.option("-f", "--full", is_flag=1, help="Also dump internal state")
|
34
|
-
@click.argument("path", nargs=1)
|
35
|
-
@click.pass_obj
|
36
|
-
async def save(obj, path, full):
|
37
|
-
"""
|
38
|
-
Write the server's current state to a file.
|
39
|
-
"""
|
40
|
-
res = await obj.client._request("save", path=path, full=full)
|
41
|
-
if obj.meta:
|
42
|
-
yprint(res, stream=obj.stdout)
|
43
|
-
|
44
|
-
|
45
|
-
@cli.command()
|
46
|
-
@click.pass_obj
|
47
|
-
async def stop(obj):
|
48
|
-
"""
|
49
|
-
Stop logging changes.
|
50
|
-
"""
|
51
|
-
res = await obj.client._request("log") # no path == stop
|
52
|
-
if obj.meta:
|
53
|
-
yprint(res, stream=obj.stdout)
|
@@ -1,114 +0,0 @@
|
|
1
|
-
# command line interface
|
2
|
-
from __future__ import annotations
|
3
|
-
|
4
|
-
import asyncclick as click
|
5
|
-
|
6
|
-
from moat.kv.server import Server
|
7
|
-
|
8
|
-
|
9
|
-
@click.command(short_help="Run the MoaT-KV server.") # pylint: disable=undefined-variable
|
10
|
-
@click.option(
|
11
|
-
"-l",
|
12
|
-
"--load",
|
13
|
-
type=click.Path(readable=True, exists=True, allow_dash=False),
|
14
|
-
default=None,
|
15
|
-
help="Event log to preload.",
|
16
|
-
)
|
17
|
-
@click.option(
|
18
|
-
"-s",
|
19
|
-
"--save",
|
20
|
-
type=click.Path(writable=True, allow_dash=False),
|
21
|
-
default=None,
|
22
|
-
help="Event log to write to.",
|
23
|
-
hidden=True,
|
24
|
-
)
|
25
|
-
@click.option(
|
26
|
-
"-i",
|
27
|
-
"--incremental",
|
28
|
-
default=None,
|
29
|
-
help="Save incremental changes, not the complete state",
|
30
|
-
hidden=True,
|
31
|
-
)
|
32
|
-
@click.option(
|
33
|
-
"-I",
|
34
|
-
"--init",
|
35
|
-
default=None,
|
36
|
-
help="Initial value to set the root to. Use only when setting up "
|
37
|
-
"a cluster for the first time!",
|
38
|
-
hidden=True,
|
39
|
-
)
|
40
|
-
@click.option(
|
41
|
-
"-e",
|
42
|
-
"--eval",
|
43
|
-
"eval_",
|
44
|
-
is_flag=True,
|
45
|
-
help="The 'init' value shall be evaluated.",
|
46
|
-
hidden=True,
|
47
|
-
)
|
48
|
-
@click.option(
|
49
|
-
"-a",
|
50
|
-
"--auth",
|
51
|
-
"--authoritative",
|
52
|
-
is_flag=True,
|
53
|
-
help="Data in this file is complete: mark anything missing as known even if not.",
|
54
|
-
)
|
55
|
-
@click.option(
|
56
|
-
"-f",
|
57
|
-
"--force",
|
58
|
-
is_flag=True,
|
59
|
-
help="Force 'successful' startup even if data are missing.",
|
60
|
-
)
|
61
|
-
@click.argument("name", nargs=1)
|
62
|
-
@click.argument("nodes", nargs=-1)
|
63
|
-
@click.pass_obj
|
64
|
-
async def cli(obj, name, load, save, init, incremental, eval_, auth, force, nodes):
|
65
|
-
"""
|
66
|
-
This command starts a MoaT-KV server. It defaults to connecting to the local Serf
|
67
|
-
agent.
|
68
|
-
|
69
|
-
All MoaT-KV servers must have a unique name. Its uniqueness cannot be
|
70
|
-
verified reliably.
|
71
|
-
|
72
|
-
One server in your network needs either an initial datum, or a copy of
|
73
|
-
a previously-saved MoaT-KV state. Otherwise, no client connections will
|
74
|
-
be accepted until synchronization with the other servers in your MoaT-KV
|
75
|
-
network is complete.
|
76
|
-
|
77
|
-
This command requires a unique NAME argument. The name identifies this
|
78
|
-
server on the network. Never start two servers with the same name!
|
79
|
-
|
80
|
-
You can force the server to fetch its data from a specific node, in
|
81
|
-
case some data are corrupted. (This should never be necessary.)
|
82
|
-
|
83
|
-
A server will refuse to start up as long as it knows about missing
|
84
|
-
entries. Use the 'force' flag to disable that. You should disable
|
85
|
-
any clients which use this server until the situation is resolved!
|
86
|
-
|
87
|
-
An auhthoritative server doesn't have missing data in its storage by
|
88
|
-
definition. This flag is used in the 'run' script when loading from a
|
89
|
-
file.
|
90
|
-
"""
|
91
|
-
|
92
|
-
kw = {}
|
93
|
-
if eval_:
|
94
|
-
kw["init"] = eval(init) # pylint: disable=eval-used
|
95
|
-
elif init == "-":
|
96
|
-
kw["init"] = None
|
97
|
-
elif init is not None:
|
98
|
-
kw["init"] = init
|
99
|
-
|
100
|
-
from moat.util import as_service
|
101
|
-
|
102
|
-
if load and nodes:
|
103
|
-
raise click.UsageError("Either read from a file or fetch from a node. Not both.")
|
104
|
-
if auth and force:
|
105
|
-
raise click.UsageError("Using both '-a' and '-f' is redundant. Choose one.")
|
106
|
-
|
107
|
-
async with as_service(obj) as evt:
|
108
|
-
s = Server(name, cfg=obj.cfg["kv"], **kw)
|
109
|
-
if load is not None:
|
110
|
-
await s.load(path=load, local=True, authoritative=auth)
|
111
|
-
if nodes:
|
112
|
-
await s.fetch_data(nodes, authoritative=auth)
|
113
|
-
|
114
|
-
await s.serve(log_path=save, log_inc=incremental, force=force, ready_evt=evt)
|
@@ -1,201 +0,0 @@
|
|
1
|
-
# command line interface
|
2
|
-
from __future__ import annotations
|
3
|
-
|
4
|
-
import json
|
5
|
-
|
6
|
-
import asyncclick as click
|
7
|
-
from moat.util import NotGiven, P, Path, PathLongener, yload, yprint
|
8
|
-
|
9
|
-
|
10
|
-
@click.group() # pylint: disable=undefined-variable
|
11
|
-
async def cli():
|
12
|
-
"""Manage types and type matches. Usage: … type …"""
|
13
|
-
pass
|
14
|
-
|
15
|
-
|
16
|
-
@cli.command()
|
17
|
-
@click.option("-s", "--script", type=click.File(mode="w", lazy=True), help="Save the script here")
|
18
|
-
@click.option("-S", "--schema", type=click.File(mode="w", lazy=True), help="Save the schema here")
|
19
|
-
@click.option("-y", "--yaml", "yaml_", is_flag=True, help="Write schema as YAML. Default: JSON.")
|
20
|
-
@click.argument("path", type=P, nargs=1)
|
21
|
-
@click.pass_obj
|
22
|
-
async def get(obj, path, script, schema, yaml_):
|
23
|
-
"""Read type checker information"""
|
24
|
-
if not len(path):
|
25
|
-
raise click.UsageError("You need a non-empty path.")
|
26
|
-
res = await obj.client._request(
|
27
|
-
action="get_internal",
|
28
|
-
path=Path("type") + path,
|
29
|
-
iter=False,
|
30
|
-
nchain=obj.meta,
|
31
|
-
)
|
32
|
-
try:
|
33
|
-
r = res.value
|
34
|
-
except AttributeError:
|
35
|
-
raise click.UsageError(f"No data at {Path('type') + path}") from None
|
36
|
-
|
37
|
-
if not obj.meta:
|
38
|
-
res = res.value
|
39
|
-
if script:
|
40
|
-
script.write(r.pop("code"))
|
41
|
-
if schema:
|
42
|
-
if yaml_:
|
43
|
-
yprint(r.pop("schema"), stream=schema)
|
44
|
-
else:
|
45
|
-
json.dump(r.pop("schema"), schema)
|
46
|
-
yprint(res, stream=obj.stdout)
|
47
|
-
|
48
|
-
|
49
|
-
@cli.command("set")
|
50
|
-
@click.option("-g", "--good", multiple=True, help="Example for passing values")
|
51
|
-
@click.option("-b", "--bad", multiple=True, help="Example for failing values")
|
52
|
-
@click.option("-d", "--data", type=click.File(mode="r"), help="Load metadata from this YAML file.")
|
53
|
-
@click.option("-s", "--script", type=click.File(mode="r"), help="File with the checking script")
|
54
|
-
@click.option("-S", "--schema", type=click.File(mode="r"), help="File with the JSON schema")
|
55
|
-
@click.option("-y", "--yaml", "yaml_", is_flag=True, help="load the schema as YAML. Default: JSON")
|
56
|
-
@click.argument("path", type=P, nargs=1)
|
57
|
-
@click.pass_obj
|
58
|
-
async def set_(obj, path, good, bad, script, schema, yaml_, data):
|
59
|
-
"""Write type checker information."""
|
60
|
-
if not len(path):
|
61
|
-
raise click.UsageError("You need a non-empty path.")
|
62
|
-
|
63
|
-
if data:
|
64
|
-
msg = yload(data)
|
65
|
-
else:
|
66
|
-
msg = {}
|
67
|
-
chain = NotGiven
|
68
|
-
if "value" in msg:
|
69
|
-
chain = msg.get("chain", NotGiven)
|
70
|
-
msg = msg["value"]
|
71
|
-
|
72
|
-
msg.setdefault("good", [])
|
73
|
-
msg.setdefault("bad", [])
|
74
|
-
for x in good:
|
75
|
-
msg["good"].append(eval(x)) # pylint: disable=eval-used
|
76
|
-
for x in bad:
|
77
|
-
msg["bad"].append(eval(x)) # pylint: disable=eval-used
|
78
|
-
|
79
|
-
if "code" in msg:
|
80
|
-
if script:
|
81
|
-
raise click.UsageError("Duplicate script")
|
82
|
-
elif script:
|
83
|
-
msg["code"] = script.read()
|
84
|
-
|
85
|
-
if "schema" in msg:
|
86
|
-
raise click.UsageError("Missing schema")
|
87
|
-
elif schema:
|
88
|
-
if yaml_:
|
89
|
-
msg["schema"] = yload(schema)
|
90
|
-
else:
|
91
|
-
msg["schema"] = json.load(schema)
|
92
|
-
|
93
|
-
if "schema" not in msg and "code" not in msg:
|
94
|
-
raise click.UsageError("I need a schema, Python code, or both.")
|
95
|
-
|
96
|
-
if len(msg["good"]) < 2:
|
97
|
-
raise click.UsageError("Missing known-good test values (at least two)")
|
98
|
-
if not msg["bad"]:
|
99
|
-
raise click.UsageError("Missing known-bad test values")
|
100
|
-
|
101
|
-
res = await obj.client._request(
|
102
|
-
action="set_internal",
|
103
|
-
value=msg,
|
104
|
-
path=Path("type") + path,
|
105
|
-
iter=False,
|
106
|
-
nchain=obj.meta,
|
107
|
-
**({} if chain is NotGiven else {"chain": chain}),
|
108
|
-
)
|
109
|
-
if obj.meta:
|
110
|
-
yprint(res, stream=obj.stdout)
|
111
|
-
|
112
|
-
|
113
|
-
@cli.command()
|
114
|
-
@click.option("-R", "--raw", is_flag=True, help="Print just the path.")
|
115
|
-
@click.option("-t", "--type", "type_", help="Type path to link to.")
|
116
|
-
@click.option("-d", "--delete", help="Use to delete this mapping.")
|
117
|
-
@click.argument("path", type=P, nargs=1)
|
118
|
-
@click.pass_obj
|
119
|
-
async def match(obj, path, type_, delete, raw): # pylint: disable=redefined-builtin
|
120
|
-
"""Match a type to a path (read, if no type given; list if empty path)"""
|
121
|
-
if not len(path):
|
122
|
-
if raw or type_ or delete:
|
123
|
-
raise click.UsageError("No options allowed when dumping the match tree..")
|
124
|
-
y = {}
|
125
|
-
pl = PathLongener()
|
126
|
-
async for r in await obj.client._request(
|
127
|
-
"get_tree_internal",
|
128
|
-
path=Path("match") + path,
|
129
|
-
iter=True,
|
130
|
-
nchain=0,
|
131
|
-
):
|
132
|
-
pl(r)
|
133
|
-
path = r["path"]
|
134
|
-
yy = y
|
135
|
-
for p in path:
|
136
|
-
yy = yy.setdefault(p, {})
|
137
|
-
try:
|
138
|
-
yy["_"] = r["value"]
|
139
|
-
except KeyError:
|
140
|
-
pass
|
141
|
-
yprint(y, stream=obj.stdout)
|
142
|
-
return
|
143
|
-
|
144
|
-
if type_ and delete:
|
145
|
-
raise click.UsageError("You can't both set and delete a path.")
|
146
|
-
if raw and (type_ or delete):
|
147
|
-
raise click.UsageError("You can only print the raw path when reading a match.")
|
148
|
-
|
149
|
-
if delete:
|
150
|
-
res = await obj.client._request(action="delete_internal", path=Path("type") + path)
|
151
|
-
if obj.meta:
|
152
|
-
yprint(res, stream=obj.stdout)
|
153
|
-
return
|
154
|
-
|
155
|
-
msg = {}
|
156
|
-
if type_:
|
157
|
-
msg["type"] = P(type_)
|
158
|
-
act = "set_internal"
|
159
|
-
elif delete:
|
160
|
-
act = "delete_internal"
|
161
|
-
else:
|
162
|
-
act = "get_internal"
|
163
|
-
res = await obj.client._request(
|
164
|
-
action=act,
|
165
|
-
value=msg,
|
166
|
-
path=Path("match") + path,
|
167
|
-
iter=False,
|
168
|
-
nchain=obj.meta,
|
169
|
-
)
|
170
|
-
if obj.meta:
|
171
|
-
yprint(res, stream=obj.stdout)
|
172
|
-
elif type_ or delete:
|
173
|
-
pass
|
174
|
-
else:
|
175
|
-
print(" ".join(str(x) for x in res.type), file=obj.stdout)
|
176
|
-
|
177
|
-
|
178
|
-
@cli.command()
|
179
|
-
@click.argument("path", type=P, nargs=1)
|
180
|
-
@click.pass_obj
|
181
|
-
async def list(obj, path): # pylint: disable=redefined-builtin
|
182
|
-
"""Dump type data"""
|
183
|
-
|
184
|
-
y = {}
|
185
|
-
pl = PathLongener()
|
186
|
-
async for r in await obj.client._request(
|
187
|
-
"get_tree_internal",
|
188
|
-
path=Path("type") + path,
|
189
|
-
iter=True,
|
190
|
-
nchain=0,
|
191
|
-
):
|
192
|
-
pl(r)
|
193
|
-
path = r["path"]
|
194
|
-
yy = y
|
195
|
-
for p in path:
|
196
|
-
yy = yy.setdefault(p, {})
|
197
|
-
try:
|
198
|
-
yy["_"] = r["value"]
|
199
|
-
except KeyError:
|
200
|
-
pass
|
201
|
-
yprint(y, stream=obj.stdout)
|
build/lib/moat/kv/config.py
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
An online-updated config store
|
3
|
-
|
4
|
-
"""
|
5
|
-
|
6
|
-
from __future__ import annotations
|
7
|
-
|
8
|
-
try:
|
9
|
-
from contextlib import asynccontextmanager
|
10
|
-
except ImportError: # pragma: no cover
|
11
|
-
from async_generator import asynccontextmanager
|
12
|
-
|
13
|
-
import logging
|
14
|
-
|
15
|
-
from .exceptions import ServerClosedError, ServerError
|
16
|
-
from .obj import ClientEntry, ClientRoot
|
17
|
-
|
18
|
-
logger = logging.getLogger(__name__)
|
19
|
-
|
20
|
-
|
21
|
-
class ConfigEntry(ClientEntry):
|
22
|
-
@classmethod
|
23
|
-
def child_type(cls, name): # pragma: no cover
|
24
|
-
logger.warning("Online config sub-entries are ignored")
|
25
|
-
return ClientEntry
|
26
|
-
|
27
|
-
async def set_value(self, value):
|
28
|
-
await self.root.client.config._update(self._name, value)
|
29
|
-
|
30
|
-
|
31
|
-
class ConfigRoot(ClientRoot):
|
32
|
-
CFG = "config"
|
33
|
-
|
34
|
-
@classmethod
|
35
|
-
def child_type(cls, name):
|
36
|
-
return ConfigEntry
|
37
|
-
|
38
|
-
@asynccontextmanager
|
39
|
-
async def run(self):
|
40
|
-
try:
|
41
|
-
async with super().run() as x:
|
42
|
-
yield x
|
43
|
-
except ServerClosedError: # pragma: no cover
|
44
|
-
pass
|
45
|
-
except ServerError: # pragma: no cover
|
46
|
-
logger.exception("No config data")
|
build/lib/moat/kv/data.py
DELETED
@@ -1,216 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Data access
|
3
|
-
"""
|
4
|
-
from __future__ import annotations
|
5
|
-
|
6
|
-
import datetime
|
7
|
-
import os
|
8
|
-
import sys
|
9
|
-
import time
|
10
|
-
from collections.abc import Mapping
|
11
|
-
|
12
|
-
from moat.util import NotGiven, Path, attrdict, process_args, yprint
|
13
|
-
|
14
|
-
|
15
|
-
def add_dates(d):
|
16
|
-
"""
|
17
|
-
Given a dict with int/float entries that might conceivably be dates,
|
18
|
-
add ``_*`` with a textual representation.
|
19
|
-
"""
|
20
|
-
|
21
|
-
t = time.time()
|
22
|
-
start = t - 366 * 24 * 3600
|
23
|
-
stop = t + 366 * 24 * 3600
|
24
|
-
|
25
|
-
def _add(d):
|
26
|
-
if isinstance(d, (list, tuple)):
|
27
|
-
for dd in d:
|
28
|
-
_add(dd)
|
29
|
-
return
|
30
|
-
if not isinstance(d, Mapping):
|
31
|
-
return
|
32
|
-
for k, v in list(d.items()):
|
33
|
-
if isinstance(k, str) and k.startswith("_"):
|
34
|
-
continue
|
35
|
-
if not isinstance(v, (int, float)):
|
36
|
-
_add(v)
|
37
|
-
continue
|
38
|
-
if start <= v <= stop:
|
39
|
-
d[f"_{k}"] = datetime.datetime.fromtimestamp(v).isoformat(
|
40
|
-
sep=" ",
|
41
|
-
timespec="milliseconds",
|
42
|
-
)
|
43
|
-
|
44
|
-
_add(d)
|
45
|
-
|
46
|
-
|
47
|
-
async def data_get(
|
48
|
-
obj,
|
49
|
-
path,
|
50
|
-
*,
|
51
|
-
recursive=True,
|
52
|
-
as_dict="_",
|
53
|
-
maxdepth=-1,
|
54
|
-
mindepth=0,
|
55
|
-
empty=False,
|
56
|
-
raw=False,
|
57
|
-
internal=False,
|
58
|
-
path_mangle=None,
|
59
|
-
item_mangle=None,
|
60
|
-
add_date=False,
|
61
|
-
):
|
62
|
-
"""Generic code to dump a subtree.
|
63
|
-
|
64
|
-
`path_mangle` accepts a path and the as_dict parameter. It should
|
65
|
-
return the new path. This is used for e.g. prefixing the path with a
|
66
|
-
device name. Returning ``None`` causes the entry to be skipped.
|
67
|
-
"""
|
68
|
-
if path_mangle is None:
|
69
|
-
path_mangle = lambda x: x
|
70
|
-
if item_mangle is None:
|
71
|
-
|
72
|
-
async def item_mangle(x): # pylint: disable=function-redefined
|
73
|
-
return x
|
74
|
-
|
75
|
-
if recursive:
|
76
|
-
kw = {}
|
77
|
-
if maxdepth is not None and maxdepth >= 0:
|
78
|
-
kw["max_depth"] = maxdepth
|
79
|
-
if mindepth:
|
80
|
-
kw["min_depth"] = mindepth
|
81
|
-
if empty:
|
82
|
-
kw["empty"] = True
|
83
|
-
if obj.meta:
|
84
|
-
kw.setdefault("nchain", obj.meta)
|
85
|
-
y = {}
|
86
|
-
if internal:
|
87
|
-
res = await obj.client._request(action="get_tree_internal", path=path, iter=True, **kw)
|
88
|
-
else:
|
89
|
-
res = obj.client.get_tree(path, **kw)
|
90
|
-
async for r in res:
|
91
|
-
r = await item_mangle(r)
|
92
|
-
if r is None:
|
93
|
-
continue
|
94
|
-
r.pop("seq", None)
|
95
|
-
path = r.pop("path")
|
96
|
-
path = path_mangle(path)
|
97
|
-
if path is None:
|
98
|
-
continue
|
99
|
-
if add_date and "value" in r:
|
100
|
-
add_dates(r.value)
|
101
|
-
|
102
|
-
if as_dict is not None:
|
103
|
-
yy = y
|
104
|
-
for p in path:
|
105
|
-
yy = yy.setdefault(p, {})
|
106
|
-
try:
|
107
|
-
yy[as_dict] = r if obj.meta else r.value
|
108
|
-
except AttributeError:
|
109
|
-
if empty:
|
110
|
-
yy[as_dict] = None
|
111
|
-
else:
|
112
|
-
if raw:
|
113
|
-
y = path
|
114
|
-
else:
|
115
|
-
y = {}
|
116
|
-
try:
|
117
|
-
y[path] = r if obj.meta else r.value
|
118
|
-
except AttributeError:
|
119
|
-
if empty:
|
120
|
-
y[path] = None
|
121
|
-
else:
|
122
|
-
continue
|
123
|
-
yprint([y], stream=obj.stdout)
|
124
|
-
|
125
|
-
if as_dict is not None:
|
126
|
-
if maxdepth:
|
127
|
-
|
128
|
-
def simplex(d):
|
129
|
-
for k, v in d.items():
|
130
|
-
if isinstance(v, dict):
|
131
|
-
d[k] = simplex(d[k])
|
132
|
-
if as_dict in d and d[as_dict] is None:
|
133
|
-
if len(d) == 1:
|
134
|
-
return None
|
135
|
-
else:
|
136
|
-
del d[as_dict]
|
137
|
-
return d
|
138
|
-
|
139
|
-
y = simplex(y)
|
140
|
-
yprint(y, stream=obj.stdout)
|
141
|
-
return # end "if recursive"
|
142
|
-
|
143
|
-
res = await obj.client.get(path, nchain=obj.meta)
|
144
|
-
if not obj.meta:
|
145
|
-
try:
|
146
|
-
res = res.value
|
147
|
-
except AttributeError:
|
148
|
-
if obj.debug:
|
149
|
-
print("No data at", path, file=sys.stderr)
|
150
|
-
return
|
151
|
-
|
152
|
-
if not raw:
|
153
|
-
yprint(res, stream=obj.stdout)
|
154
|
-
elif isinstance(res, bytes):
|
155
|
-
os.write(obj.stdout.fileno(), res)
|
156
|
-
else:
|
157
|
-
obj.stdout.write(str(res))
|
158
|
-
pass # end get
|
159
|
-
|
160
|
-
|
161
|
-
def res_get(res, attr: Path, **kw): # pylint: disable=redefined-outer-name
|
162
|
-
"""
|
163
|
-
Get a node's value and access the dict items beneath it.
|
164
|
-
|
165
|
-
The node value must be an attrdict.
|
166
|
-
"""
|
167
|
-
val = res.get("value", None)
|
168
|
-
if val is None:
|
169
|
-
return None
|
170
|
-
return val._get(attr, **kw)
|
171
|
-
|
172
|
-
|
173
|
-
def res_update(res, attr: Path, value=None, **kw): # pylint: disable=redefined-outer-name
|
174
|
-
"""
|
175
|
-
Set a node's sub-item's value, possibly merging dicts.
|
176
|
-
Entries set to 'NotGiven' are deleted.
|
177
|
-
|
178
|
-
The node value must be an attrdict.
|
179
|
-
|
180
|
-
Returns the new value.
|
181
|
-
"""
|
182
|
-
val = res.get("value", attrdict())
|
183
|
-
return val._update(attr, value=value, **kw)
|
184
|
-
|
185
|
-
|
186
|
-
async def node_attr(obj, path, res=None, chain=None, **kw):
|
187
|
-
"""
|
188
|
-
Sub-attr setter.
|
189
|
-
|
190
|
-
Args:
|
191
|
-
obj: command object
|
192
|
-
path: address of the node to change
|
193
|
-
res: old node, if it has been read already
|
194
|
-
chain: change chain of node, copied from res if clear
|
195
|
-
**kw: the results of `attr_args`
|
196
|
-
|
197
|
-
Returns the result of setting the attribute.
|
198
|
-
"""
|
199
|
-
if res is None:
|
200
|
-
res = await obj.client.get(path, nchain=obj.meta or 2)
|
201
|
-
if chain is None:
|
202
|
-
try:
|
203
|
-
chain = res.chain
|
204
|
-
except AttributeError:
|
205
|
-
pass
|
206
|
-
try:
|
207
|
-
val = res.value
|
208
|
-
except AttributeError:
|
209
|
-
chain = None
|
210
|
-
val = NotGiven
|
211
|
-
val = process_args(val, **kw)
|
212
|
-
if val is NotGiven:
|
213
|
-
res = await obj.client.delete(path, nchain=obj.meta, chain=chain)
|
214
|
-
else:
|
215
|
-
res = await obj.client.set(path, value=val, nchain=obj.meta, chain=chain)
|
216
|
-
return res
|