+42
-16
python/pmgfal/__init__.py
+42
-16
python/pmgfal/__init__.py
···
5
import argparse
6
import os
7
import shutil
8
import sys
9
from pathlib import Path
10
11
from pmgfal._pmgfal import __version__, generate, hash_lexicons
12
13
-
__all__ = ["__version__", "generate", "hash_lexicons", "main", "get_cache_dir"]
14
15
16
def get_cache_dir() -> Path:
···
24
return base / "pmgfal"
25
26
27
def main(args: list[str] | None = None) -> int:
28
"""cli entry point."""
29
parser = argparse.ArgumentParser(
···
31
description="pydantic model generator for atproto lexicons",
32
)
33
parser.add_argument(
34
-
"lexicon_dir",
35
nargs="?",
36
-
type=Path,
37
-
help="directory containing lexicon json files (default: ./lexicons or .)",
38
)
39
parser.add_argument(
40
"-o",
···
64
65
parsed = parser.parse_args(args)
66
67
-
# auto-detect lexicon directory
68
-
if parsed.lexicon_dir is None:
69
-
if Path("./lexicons").is_dir():
70
-
lexicon_dir = Path("./lexicons")
71
else:
72
-
lexicon_dir = Path(".")
73
-
else:
74
-
lexicon_dir = parsed.lexicon_dir
75
76
-
if not lexicon_dir.is_dir():
77
-
print(f"error: not a directory: {lexicon_dir}", file=sys.stderr)
78
-
return 1
79
-
80
-
try:
81
# compute hash of lexicons (in rust)
82
lexicon_hash = hash_lexicons(str(lexicon_dir), parsed.prefix)
83
cache_dir = get_cache_dir() / lexicon_hash
···
114
except Exception as e:
115
print(f"error: {e}", file=sys.stderr)
116
return 1
117
118
119
if __name__ == "__main__":
···
5
import argparse
6
import os
7
import shutil
8
+
import subprocess
9
import sys
10
+
import tempfile
11
from pathlib import Path
12
13
from pmgfal._pmgfal import __version__, generate, hash_lexicons
14
15
+
__all__ = ["__version__", "generate", "get_cache_dir", "hash_lexicons", "main"]
16
17
18
def get_cache_dir() -> Path:
···
26
return base / "pmgfal"
27
28
29
+
def is_git_url(path: str) -> bool:
30
+
"""check if path looks like a git url."""
31
+
return path.startswith(("https://", "git@", "ssh://", "git://"))
32
+
33
+
34
def main(args: list[str] | None = None) -> int:
35
"""cli entry point."""
36
parser = argparse.ArgumentParser(
···
38
description="pydantic model generator for atproto lexicons",
39
)
40
parser.add_argument(
41
+
"lexicon_source",
42
nargs="?",
43
+
help="directory or git url containing lexicon json files (default: ./lexicons or .)",
44
)
45
parser.add_argument(
46
"-o",
···
70
71
parsed = parser.parse_args(args)
72
73
+
temp_dir = None
74
+
try:
75
+
# handle git urls by cloning to temp dir
76
+
if parsed.lexicon_source and is_git_url(parsed.lexicon_source):
77
+
temp_dir = tempfile.mkdtemp(prefix="pmgfal-")
78
+
print(f"cloning {parsed.lexicon_source}...")
79
+
result = subprocess.run(
80
+
["git", "clone", "--depth=1", parsed.lexicon_source, temp_dir],
81
+
capture_output=True,
82
+
text=True,
83
+
)
84
+
if result.returncode != 0:
85
+
print(f"error: git clone failed: {result.stderr}", file=sys.stderr)
86
+
return 1
87
+
# look for lexicons subdir in cloned repo
88
+
if (Path(temp_dir) / "lexicons").is_dir():
89
+
lexicon_dir = Path(temp_dir) / "lexicons"
90
+
else:
91
+
lexicon_dir = Path(temp_dir)
92
+
# auto-detect lexicon directory
93
+
elif parsed.lexicon_source is None:
94
+
if Path("./lexicons").is_dir():
95
+
lexicon_dir = Path("./lexicons")
96
+
else:
97
+
lexicon_dir = Path(".")
98
else:
99
+
lexicon_dir = Path(parsed.lexicon_source)
100
101
+
if not lexicon_dir.is_dir():
102
+
print(f"error: not a directory: {lexicon_dir}", file=sys.stderr)
103
+
return 1
104
# compute hash of lexicons (in rust)
105
lexicon_hash = hash_lexicons(str(lexicon_dir), parsed.prefix)
106
cache_dir = get_cache_dir() / lexicon_hash
···
137
except Exception as e:
138
print(f"error: {e}", file=sys.stderr)
139
return 1
140
+
finally:
141
+
if temp_dir and Path(temp_dir).exists():
142
+
shutil.rmtree(temp_dir)
143
144
145
if __name__ == "__main__":
+8
-2
tests/test_generate.py
+8
-2
tests/test_generate.py
···
266
"defs": {
267
"main": {
268
"type": "record",
269
+
"record": {
270
+
"type": "object",
271
+
"properties": {"x": {"type": "string"}},
272
+
},
273
}
274
},
275
}
···
304
"defs": {
305
"main": {
306
"type": "record",
307
+
"record": {
308
+
"type": "object",
309
+
"properties": {"y": {"type": "string"}},
310
+
},
311
}
312
},
313
}