machine-root 0.1.0__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.
- machine_root-0.1.0.dist-info/METADATA +94 -0
- machine_root-0.1.0.dist-info/RECORD +9 -0
- machine_root-0.1.0.dist-info/WHEEL +4 -0
- machine_root-0.1.0.dist-info/entry_points.txt +2 -0
- machine_root-0.1.0.dist-info/licenses/LICENSE +9 -0
- machineroot/__init__.py +32 -0
- machineroot/__main__.py +144 -0
- machineroot/_exceptions.py +10 -0
- machineroot/_resolve.py +51 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: machine-root
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A minimal shared registry for locating resources on a local machine
|
|
5
|
+
Project-URL: Homepage, https://github.com/LionKimbro/machine-root
|
|
6
|
+
Project-URL: Repository, https://github.com/LionKimbro/machine-root
|
|
7
|
+
Author: Lion Kimbro
|
|
8
|
+
License: CC0-1.0
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Requires-Python: >=3.11
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# machine-root
|
|
17
|
+
|
|
18
|
+
## The Problem
|
|
19
|
+
|
|
20
|
+
Programs, scripts, and AIs that run on a machine often need to locate resources - a project folder, a service registry, a configuration file. The usual solutions are fragile: hard-coded paths break when things move, environment variables require manual setup, and configuration systems are overkill for something this simple.
|
|
21
|
+
|
|
22
|
+
## The System
|
|
23
|
+
|
|
24
|
+
Machine Root is a minimal, shared registry for a local machine. It is a single JSON file - `machine-root.json` - that maps string keys to locations (typically filesystem paths):
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"zoo.projects": "C:/lion/zoo/projects",
|
|
29
|
+
"filetalk.registry": "C:/lion/filetalk/service-registry.json",
|
|
30
|
+
"librarian.main": "C:/lion/librarian/registry.json"
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Any program that knows the convention can read from the same registry. Keys are stable names; values are locations that can change. No metadata, no nesting, no configuration framework required.
|
|
35
|
+
|
|
36
|
+
### Resolution Order
|
|
37
|
+
|
|
38
|
+
When looking for `machine-root.json`, the system checks these locations in order and uses the first one found:
|
|
39
|
+
|
|
40
|
+
1. The path in the `MACHINE_ROOT` environment variable (if set and the file exists)
|
|
41
|
+
2. `./machine-root.json` (current working directory)
|
|
42
|
+
3. `~/machine-root.json` (user home directory)
|
|
43
|
+
4. Machine-level: `C:/machine-root.json` (Windows) or `/etc/machine-root.json` (Linux)
|
|
44
|
+
|
|
45
|
+
If none are found, operations fail clearly.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## The Package
|
|
50
|
+
|
|
51
|
+
`machine-root` is a Python package that implements the Machine Root system. It provides a minimal API and a command-line tool for reading and writing the registry.
|
|
52
|
+
|
|
53
|
+
### Install
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
pip install machine-root
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Python API
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
import machineroot
|
|
63
|
+
|
|
64
|
+
machineroot.locate() # path to the active machine-root.json
|
|
65
|
+
machineroot.keys() # list all keys
|
|
66
|
+
machineroot.get("zoo.projects") # get a value
|
|
67
|
+
machineroot.set("zoo.projects", "C:/lion/zoo/projects") # set a value
|
|
68
|
+
machineroot.delete("zoo.projects") # delete a key
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Errors:
|
|
72
|
+
|
|
73
|
+
- `MachineRootNotFoundError` - no `machine-root.json` could be found
|
|
74
|
+
- `MachineRootKeyError` - the requested key does not exist
|
|
75
|
+
|
|
76
|
+
### CLI
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
machine-root create
|
|
80
|
+
machine-root set zoo.projects C:/lion/zoo/projects
|
|
81
|
+
machine-root get zoo.projects
|
|
82
|
+
machine-root delete zoo.projects
|
|
83
|
+
machine-root keys
|
|
84
|
+
machine-root locate
|
|
85
|
+
machine-root help
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The registry file must be created explicitly with `machine-root create`, which places it in the user's home directory. All other commands fail if the file does not exist.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
CC0-1.0 - public domain.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
machineroot/__init__.py,sha256=9iMItU6DcDiSs1W8NgeGDuecXMPYe0z1XMaECFsi6kQ,720
|
|
2
|
+
machineroot/__main__.py,sha256=onRzIo8JvsuiAZNN9Y-jWC07NJbs5RarUCywvPu_fL8,3625
|
|
3
|
+
machineroot/_exceptions.py,sha256=F3_MyAp_6KP5krcDxlXTaFRSusUWdkRLbVmBLAO7_jQ,181
|
|
4
|
+
machineroot/_resolve.py,sha256=z4yZQelGTDw1hXciKikDRWTzg3UM02sfsyL-87dgjtk,1163
|
|
5
|
+
machine_root-0.1.0.dist-info/METADATA,sha256=kfXfC_6x59z90jhqkeykEA2NggRLXQ7trADgYTmBBps,3084
|
|
6
|
+
machine_root-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
7
|
+
machine_root-0.1.0.dist-info/entry_points.txt,sha256=I0gmRNltiMgr6aSGfaaSLi-EtcNG7WtONtDw7XXtX0M,59
|
|
8
|
+
machine_root-0.1.0.dist-info/licenses/LICENSE,sha256=J3cutLOIV6T_qvfoxvKVoFemyzMQtnMARm5jpL5TYI4,335
|
|
9
|
+
machine_root-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
CC0 1.0 Universal
|
|
2
|
+
|
|
3
|
+
This work is dedicated to the public domain under the Creative Commons CC0 1.0
|
|
4
|
+
Universal Public Domain Dedication.
|
|
5
|
+
|
|
6
|
+
To the extent possible under law, the author(s) have waived all copyright and
|
|
7
|
+
related or neighboring rights to this work.
|
|
8
|
+
|
|
9
|
+
See https://creativecommons.org/publicdomain/zero/1.0/ for details.
|
machineroot/__init__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from ._exceptions import MachineRootError, MachineRootNotFoundError, MachineRootKeyError
|
|
2
|
+
from ._resolve import locate as _locate_path, read_registry, write_registry
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def locate():
|
|
6
|
+
return str(_locate_path())
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get(key):
|
|
10
|
+
data, _ = read_registry()
|
|
11
|
+
if key not in data:
|
|
12
|
+
raise MachineRootKeyError(key)
|
|
13
|
+
return data[key]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def set(key, value):
|
|
17
|
+
data, path = read_registry()
|
|
18
|
+
data[key] = value
|
|
19
|
+
write_registry(data, path)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def keys():
|
|
23
|
+
data, _ = read_registry()
|
|
24
|
+
return list(data.keys())
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def delete(key):
|
|
28
|
+
data, path = read_registry()
|
|
29
|
+
if key not in data:
|
|
30
|
+
raise MachineRootKeyError(key)
|
|
31
|
+
del data[key]
|
|
32
|
+
write_registry(data, path)
|
machineroot/__main__.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import machineroot
|
|
5
|
+
from machineroot._exceptions import MachineRootError, MachineRootNotFoundError
|
|
6
|
+
from machineroot._resolve import kFILENAME, locate as _locate_path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
kHELP = """\
|
|
10
|
+
machine-root — locate and manage the machine-root.json registry
|
|
11
|
+
|
|
12
|
+
USAGE
|
|
13
|
+
machine-root <command> [arguments]
|
|
14
|
+
|
|
15
|
+
COMMANDS
|
|
16
|
+
create
|
|
17
|
+
Create an empty machine-root.json file in the user's home directory.
|
|
18
|
+
Fails if the file already exists.
|
|
19
|
+
|
|
20
|
+
get <key>
|
|
21
|
+
Print the value associated with <key>.
|
|
22
|
+
Fails if the registry file or key does not exist.
|
|
23
|
+
|
|
24
|
+
set <key> <value>
|
|
25
|
+
Set or update the value for <key>.
|
|
26
|
+
Fails if the registry file does not exist.
|
|
27
|
+
|
|
28
|
+
delete <key>
|
|
29
|
+
Delete the entry for <key>.
|
|
30
|
+
Fails if the registry file or key does not exist.
|
|
31
|
+
|
|
32
|
+
keys
|
|
33
|
+
List all keys in the registry.
|
|
34
|
+
Fails if the registry file does not exist.
|
|
35
|
+
|
|
36
|
+
locate
|
|
37
|
+
Print the path to the active machine-root.json file.
|
|
38
|
+
Fails if no registry file can be found.
|
|
39
|
+
|
|
40
|
+
help
|
|
41
|
+
Show this help message.
|
|
42
|
+
|
|
43
|
+
RESOLUTION ORDER
|
|
44
|
+
1. MACHINE_ROOT environment variable
|
|
45
|
+
2. ./machine-root.json
|
|
46
|
+
3. ~/machine-root.json
|
|
47
|
+
4. Machine-level file
|
|
48
|
+
- Windows: C:/machine-root.json
|
|
49
|
+
- Linux: /etc/machine-root.json
|
|
50
|
+
|
|
51
|
+
EXAMPLES
|
|
52
|
+
machine-root create
|
|
53
|
+
machine-root set zoo.projects C:/lion/zoo/projects
|
|
54
|
+
machine-root get zoo.projects
|
|
55
|
+
machine-root keys
|
|
56
|
+
machine-root locate
|
|
57
|
+
|
|
58
|
+
NOTES
|
|
59
|
+
- The registry file must be created explicitly using 'machine-root create'.
|
|
60
|
+
- All commands fail if the registry file is not found.
|
|
61
|
+
- Keys are simple strings; values are typically filesystem paths.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def run_create():
|
|
66
|
+
path = pathlib.Path.home() / kFILENAME
|
|
67
|
+
if path.exists():
|
|
68
|
+
print(f"error: {path} already exists.", file=sys.stderr)
|
|
69
|
+
sys.exit(1)
|
|
70
|
+
import json
|
|
71
|
+
tmp = pathlib.Path(str(path) + ".tmp")
|
|
72
|
+
with open(tmp, "w", encoding="utf-8") as f:
|
|
73
|
+
json.dump({}, f, indent=2)
|
|
74
|
+
f.write("\n")
|
|
75
|
+
tmp.replace(path)
|
|
76
|
+
print(f"Created {path}")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def run_get(key):
|
|
80
|
+
print(machineroot.get(key))
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def run_set(key, value):
|
|
84
|
+
machineroot.set(key, value)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def run_delete(key):
|
|
88
|
+
machineroot.delete(key)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def run_keys():
|
|
92
|
+
for k in machineroot.keys():
|
|
93
|
+
print(k)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def run_locate():
|
|
97
|
+
print(machineroot.locate())
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def run_help():
|
|
101
|
+
print(kHELP, end="")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def main():
|
|
105
|
+
args = sys.argv[1:]
|
|
106
|
+
|
|
107
|
+
if not args or args[0] == "help":
|
|
108
|
+
run_help()
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
cmd = args[0]
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
if cmd == "create":
|
|
115
|
+
run_create()
|
|
116
|
+
elif cmd == "get":
|
|
117
|
+
if len(args) < 2:
|
|
118
|
+
print("error: get requires a key.", file=sys.stderr)
|
|
119
|
+
sys.exit(1)
|
|
120
|
+
run_get(args[1])
|
|
121
|
+
elif cmd == "set":
|
|
122
|
+
if len(args) < 3:
|
|
123
|
+
print("error: set requires a key and a value.", file=sys.stderr)
|
|
124
|
+
sys.exit(1)
|
|
125
|
+
run_set(args[1], args[2])
|
|
126
|
+
elif cmd == "delete":
|
|
127
|
+
if len(args) < 2:
|
|
128
|
+
print("error: delete requires a key.", file=sys.stderr)
|
|
129
|
+
sys.exit(1)
|
|
130
|
+
run_delete(args[1])
|
|
131
|
+
elif cmd == "keys":
|
|
132
|
+
run_keys()
|
|
133
|
+
elif cmd == "locate":
|
|
134
|
+
run_locate()
|
|
135
|
+
else:
|
|
136
|
+
print(f"error: unknown command '{cmd}'. Run 'machine-root help' for usage.", file=sys.stderr)
|
|
137
|
+
sys.exit(1)
|
|
138
|
+
except MachineRootError as e:
|
|
139
|
+
print(f"error: {e}", file=sys.stderr)
|
|
140
|
+
sys.exit(1)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
if __name__ == "__main__":
|
|
144
|
+
main()
|
machineroot/_resolve.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import pathlib
|
|
4
|
+
|
|
5
|
+
from ._exceptions import MachineRootNotFoundError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
kFILENAME = "machine-root.json"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def locate():
|
|
12
|
+
# 1. MACHINE_ROOT environment variable
|
|
13
|
+
env = os.environ.get("MACHINE_ROOT")
|
|
14
|
+
if env:
|
|
15
|
+
p = pathlib.Path(env)
|
|
16
|
+
if p.exists():
|
|
17
|
+
return p
|
|
18
|
+
|
|
19
|
+
# 2. Current working directory
|
|
20
|
+
p = pathlib.Path.cwd() / kFILENAME
|
|
21
|
+
if p.exists():
|
|
22
|
+
return p
|
|
23
|
+
|
|
24
|
+
# 3. User home directory
|
|
25
|
+
p = pathlib.Path.home() / kFILENAME
|
|
26
|
+
if p.exists():
|
|
27
|
+
return p
|
|
28
|
+
|
|
29
|
+
# 4. Machine-level
|
|
30
|
+
if os.name == "nt":
|
|
31
|
+
p = pathlib.Path("C:/") / kFILENAME
|
|
32
|
+
else:
|
|
33
|
+
p = pathlib.Path("/etc") / kFILENAME
|
|
34
|
+
if p.exists():
|
|
35
|
+
return p
|
|
36
|
+
|
|
37
|
+
raise MachineRootNotFoundError("No machine-root.json file could be found.")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def read_registry():
|
|
41
|
+
p = locate()
|
|
42
|
+
with open(p, "r", encoding="utf-8") as f:
|
|
43
|
+
return json.load(f), p
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def write_registry(data, path):
|
|
47
|
+
tmp = pathlib.Path(str(path) + ".tmp")
|
|
48
|
+
with open(tmp, "w", encoding="utf-8") as f:
|
|
49
|
+
json.dump(data, f, indent=2)
|
|
50
|
+
f.write("\n")
|
|
51
|
+
tmp.replace(path)
|