omdev 0.0.0.dev305__py3-none-any.whl → 0.0.0.dev306__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.
omdev/.manifests.json CHANGED
@@ -47,6 +47,18 @@
47
47
  }
48
48
  }
49
49
  },
50
+ {
51
+ "module": ".cmdlog.__main__",
52
+ "attr": "_CLI_MODULE",
53
+ "file": "omdev/cmdlog/__main__.py",
54
+ "line": 4,
55
+ "value": {
56
+ "$.cli.types.CliModule": {
57
+ "cmd_name": "cmdlog",
58
+ "mod_name": "omdev.cmdlog.__main__"
59
+ }
60
+ }
61
+ },
50
62
  {
51
63
  "module": ".imgur",
52
64
  "attr": "_FOO_CLI_MODULE",
@@ -0,0 +1,7 @@
1
+ from ._cmdlog import ( # noqa
2
+ CmdLogEntry,
3
+ )
4
+
5
+ from .cmdlog import ( # noqa
6
+ CmdLog,
7
+ )
@@ -0,0 +1,11 @@
1
+ from ..cli import CliModule
2
+
3
+
4
+ # @omlish-manifest
5
+ _CLI_MODULE = CliModule('cmdlog', __name__)
6
+
7
+
8
+ if __name__ == '__main__':
9
+ from .cli import _main
10
+
11
+ _main()
@@ -0,0 +1,73 @@
1
+ # NOTE: not '@omlish-lite' due to root level __init__ imports, but effectively lite.
2
+ import dataclasses as dc
3
+ import fcntl
4
+ import json
5
+ import os.path
6
+ import shutil
7
+ import sys
8
+ import time
9
+ import typing as ta
10
+
11
+
12
+ ##
13
+
14
+
15
+ @dc.dataclass(frozen=True)
16
+ class CmdLogEntry:
17
+ cmd: str
18
+ pid: int
19
+ ppid: int
20
+ time: float
21
+ cwd: str
22
+
23
+ argv: ta.Sequence[str]
24
+ env: ta.Mapping[str, str]
25
+
26
+
27
+ ##
28
+
29
+
30
+ LOG_FILE_ENV_VAR: str = '_CMD_LOG_FILE'
31
+
32
+
33
+ def _main() -> None:
34
+ cmd = os.path.basename(sys.argv[0])
35
+
36
+ entry = CmdLogEntry(
37
+ cmd=cmd,
38
+ pid=os.getpid(),
39
+ ppid=os.getppid(),
40
+ time=time.time(),
41
+ cwd=os.getcwd(),
42
+
43
+ argv=sys.argv,
44
+ env=dict(os.environ),
45
+ )
46
+
47
+ entry_json = json.dumps(dc.asdict(entry), separators=(',', ':'), indent=None)
48
+
49
+ log_file = os.environ[LOG_FILE_ENV_VAR]
50
+ fd = os.open(log_file, os.O_WRONLY | os.O_CREAT | os.O_APPEND)
51
+ fcntl.flock(fd, fcntl.LOCK_EX)
52
+ os.write(fd, entry_json.encode() + b'\n')
53
+ os.close(fd)
54
+
55
+ u_ap = None # type: str | None
56
+ self_ap = os.path.abspath(os.path.realpath(__file__))
57
+ for p in os.environ.get('PATH', '').split(os.pathsep):
58
+ if (p_cmd := shutil.which(cmd, path=p)) is None:
59
+ continue
60
+ p_ap = os.path.abspath(os.path.realpath(p_cmd))
61
+ if p_ap == self_ap:
62
+ continue
63
+ u_ap = p_ap
64
+ break
65
+
66
+ if u_ap is None:
67
+ raise FileNotFoundError(cmd)
68
+
69
+ os.execl(u_ap, cmd, *sys.argv[1:])
70
+
71
+
72
+ if __name__ == '__main__':
73
+ _main()
omdev/cmdlog/cli.py ADDED
@@ -0,0 +1,67 @@
1
+ import argparse
2
+ import os.path
3
+ import subprocess
4
+ import sys
5
+ import typing as ta
6
+
7
+ from omlish.formats import json
8
+
9
+ from .cmdlog import CmdLog
10
+
11
+
12
+ ##
13
+
14
+
15
+ DEFAULT_PROXIED_CMDS: ta.Collection[str] = [
16
+ 'ar',
17
+ 'as',
18
+ 'clang',
19
+ 'clang++',
20
+ 'g++',
21
+ 'gcc',
22
+ 'ld',
23
+ 'lld',
24
+ 'make',
25
+ ]
26
+
27
+
28
+ def _main() -> None:
29
+ parser = argparse.ArgumentParser()
30
+ parser.add_argument('cmd', nargs=argparse.REMAINDER)
31
+ parser.add_argument('-l', '--log-file')
32
+ parser.add_argument('-P', '--print', action='store_true')
33
+ parser.add_argument('-p', '--proxy', action='append')
34
+ args = parser.parse_args()
35
+
36
+ if not args.cmd:
37
+ parser.error('Must specify cmd')
38
+ raise RuntimeError # noqa
39
+
40
+ exec_cmd, *exec_argv = args.cmd
41
+
42
+ #
43
+
44
+ cl = CmdLog(
45
+ args.proxy if args.proxy is not None else DEFAULT_PROXIED_CMDS,
46
+ log_file=os.path.abspath(args.log_file) if args.log_file is not None else None,
47
+ )
48
+ cl.exe()
49
+ cl.proxy_cmds()
50
+
51
+ rc = subprocess.call(
52
+ [exec_cmd, *exec_argv],
53
+ env=cl.child_env(),
54
+ )
55
+
56
+ if args.log_file is None or args.print:
57
+ if os.path.exists(cl.log_file()):
58
+ with open(cl.log_file()) as f:
59
+ log_lines = f.readlines()
60
+ entry_dcts = [json.loads(sl) for l in log_lines if (sl := l.strip())]
61
+ print(json.dumps_compact(entry_dcts))
62
+
63
+ sys.exit(rc)
64
+
65
+
66
+ if __name__ == '__main__':
67
+ _main()
omdev/cmdlog/cmdlog.py ADDED
@@ -0,0 +1,86 @@
1
+ import inspect
2
+ import os.path
3
+ import sys
4
+ import tempfile
5
+ import typing as ta
6
+
7
+ from omlish import cached
8
+ from omlish import check
9
+
10
+ from . import _cmdlog
11
+
12
+
13
+ ##
14
+
15
+
16
+ class CmdLog:
17
+ def __init__(
18
+ self,
19
+ proxied_cmds: ta.Iterable[str],
20
+ *,
21
+ tmp_dir: str | None = None,
22
+ log_file: str | None = None,
23
+ exe_name: str | None = None,
24
+ ) -> None:
25
+ super().__init__()
26
+
27
+ self._proxied_cmds = {
28
+ check.non_empty_str(c)
29
+ for c in check.not_isinstance(proxied_cmds, str)
30
+ }
31
+
32
+ self._given_tmp_dir = tmp_dir
33
+ self._given_log_file = log_file
34
+ self._exe_name = check.non_empty_str(exe_name) if exe_name is not None else self.DEFAULT_EXE_NAME
35
+
36
+ #
37
+
38
+ @cached.function
39
+ def tmp_dir(self) -> str:
40
+ if (gtd := self._given_tmp_dir) is not None:
41
+ return gtd
42
+ return tempfile.mkdtemp()
43
+
44
+ #
45
+
46
+ DEFAULT_LOG_FILE_NAME: ta.ClassVar[str] = '_cmdlog.jsonl'
47
+
48
+ @cached.function
49
+ def log_file(self) -> str:
50
+ if (glf := self._given_log_file) is not None:
51
+ return glf
52
+ return os.path.join(self.tmp_dir(), self.DEFAULT_LOG_FILE_NAME)
53
+
54
+ #
55
+
56
+ DEFAULT_EXE_NAME: ta.ClassVar[str] = '_cmdlog.py'
57
+
58
+ @cached.function
59
+ def exe(self) -> str:
60
+ src = '\n'.join([
61
+ f'#!{os.path.abspath(sys.executable)}',
62
+ inspect.getsource(_cmdlog),
63
+ ])
64
+
65
+ exe = os.path.join(self.tmp_dir(), self._exe_name)
66
+
67
+ with open(exe, 'w') as f:
68
+ f.write(src)
69
+
70
+ os.chmod(exe, 0o550) # noqa
71
+
72
+ return exe
73
+
74
+ #
75
+
76
+ def proxy_cmds(self) -> None:
77
+ for p_c in self._proxied_cmds:
78
+ os.symlink(self._exe_name, os.path.join(self.tmp_dir(), p_c))
79
+
80
+ #
81
+
82
+ def child_env(self) -> ta.Mapping[str, str]:
83
+ return {
84
+ _cmdlog.LOG_FILE_ENV_VAR: self.log_file(),
85
+ 'PATH': os.pathsep.join([self.tmp_dir(), os.environ['PATH']]),
86
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omdev
3
- Version: 0.0.0.dev305
3
+ Version: 0.0.0.dev306
4
4
  Summary: omdev
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
13
  Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omlish==0.0.0.dev305
15
+ Requires-Dist: omlish==0.0.0.dev306
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black~=25.1; extra == "all"
18
18
  Requires-Dist: pycparser~=2.22; extra == "all"
@@ -1,4 +1,4 @@
1
- omdev/.manifests.json,sha256=ouzCsEt6dHvLXr-DyZ-gLxbnizOFe0BE6u6xKH3RKEI,10721
1
+ omdev/.manifests.json,sha256=M4fAkk-dlyvEzkya4HhuU9Hb9QpVYgp1AgJB6eXgmuI,10982
2
2
  omdev/__about__.py,sha256=16xa_1BdZanTpZbkjAOQ11_x5kJcb1m1tKdvb06J7VI,1202
3
3
  omdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  omdev/cmake.py,sha256=9rfSvFHPmKDj9ngvfDB2vK8O-xO_ZwUm7hMKLWA-yOw,4578
@@ -114,6 +114,11 @@ omdev/clipboard/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
114
  omdev/clipboard/clipboard.py,sha256=9HFpcijpn0XDTI89ZRm2WA1G7O4HsTdVXZHqMULu3N0,1630
115
115
  omdev/clipboard/darwin_cf.py,sha256=1gFkxEN6w9HTcA0eiWw14oL7xjC1wSmY_hUrRr5OU4Y,7687
116
116
  omdev/clipboard/linux_x11.py,sha256=oa-mxMRNaZJOdBAZ8Nki-CAGIb63X8OFUTXKjmiwfSo,6718
117
+ omdev/cmdlog/__init__.py,sha256=026o1leEXU5bsNZPpEOeLf_Ml1wQXzbiFDmlcKHX-Nw,95
118
+ omdev/cmdlog/__main__.py,sha256=m31h6AcI9rjRNVeBGoLcR-5pWp-yS8LXCorf4iBhX9w,162
119
+ omdev/cmdlog/_cmdlog.py,sha256=9VSuUKXBMBHAH3OfBCeqp16YPddPT9Man2zDHgzzCtI,1507
120
+ omdev/cmdlog/cli.py,sha256=9AJC3xeQA-2pdmTnsjo__9WRAML1jpEJUJMn6qQQpJA,1427
121
+ omdev/cmdlog/cmdlog.py,sha256=MJqfCG7sVWjSK_i1shD7cgWpFZXZkPvGhGEh-yd6iwM,1982
117
122
  omdev/dataserver/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
118
123
  omdev/dataserver/handlers.py,sha256=rCptrmV2RnutmGE5MAgjLDYW1QncqsSHhyRBL4H5bsg,5440
119
124
  omdev/dataserver/http.py,sha256=SozI4233RP40m2EX45HtBvdIj-CBFlhHH7ekIbMir-Q,1724
@@ -277,9 +282,9 @@ omdev/tools/json/rendering.py,sha256=tMcjOW5edfozcMSTxxvF7WVTsbYLoe9bCKFh50qyaGw
277
282
  omdev/tools/pawk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
278
283
  omdev/tools/pawk/__main__.py,sha256=VCqeRVnqT1RPEoIrqHFSu4PXVMg4YEgF4qCQm90-eRI,66
279
284
  omdev/tools/pawk/pawk.py,sha256=zsEkfQX0jF5bn712uqPAyBSdJt2dno1LH2oeSMNfXQI,11424
280
- omdev-0.0.0.dev305.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
281
- omdev-0.0.0.dev305.dist-info/METADATA,sha256=Dp_xG1ayIA3fP9VGM69G_Xa_oVLFp24uVQFOSMaNQew,1674
282
- omdev-0.0.0.dev305.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
283
- omdev-0.0.0.dev305.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
284
- omdev-0.0.0.dev305.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
285
- omdev-0.0.0.dev305.dist-info/RECORD,,
285
+ omdev-0.0.0.dev306.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
286
+ omdev-0.0.0.dev306.dist-info/METADATA,sha256=fiHu3utIwUEtAURhnU-PYrXupHEa1PloV_2uGgqozvk,1674
287
+ omdev-0.0.0.dev306.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
288
+ omdev-0.0.0.dev306.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
289
+ omdev-0.0.0.dev306.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
290
+ omdev-0.0.0.dev306.dist-info/RECORD,,