ominfra 0.0.0.dev127__py3-none-any.whl → 0.0.0.dev128__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.
Files changed (36) hide show
  1. ominfra/scripts/supervisor.py +723 -731
  2. ominfra/supervisor/configs.py +34 -11
  3. ominfra/supervisor/context.py +5 -9
  4. ominfra/supervisor/dispatchers.py +4 -3
  5. ominfra/supervisor/dispatchersimpl.py +10 -9
  6. ominfra/supervisor/groups.py +1 -1
  7. ominfra/supervisor/inject.py +5 -5
  8. ominfra/supervisor/main.py +2 -2
  9. ominfra/supervisor/pipes.py +15 -13
  10. ominfra/supervisor/poller.py +36 -35
  11. ominfra/supervisor/{processes.py → process.py} +2 -1
  12. ominfra/supervisor/{processesimpl.py → processimpl.py} +35 -40
  13. ominfra/supervisor/setup.py +1 -1
  14. ominfra/supervisor/setupimpl.py +4 -3
  15. ominfra/supervisor/spawning.py +2 -1
  16. ominfra/supervisor/spawningimpl.py +15 -12
  17. ominfra/supervisor/supervisor.py +16 -8
  18. ominfra/supervisor/types.py +7 -9
  19. ominfra/supervisor/utils/__init__.py +0 -0
  20. ominfra/supervisor/utils/diag.py +31 -0
  21. ominfra/supervisor/utils/fds.py +46 -0
  22. ominfra/supervisor/utils/fs.py +47 -0
  23. ominfra/supervisor/utils/os.py +45 -0
  24. ominfra/supervisor/utils/ostypes.py +9 -0
  25. ominfra/supervisor/utils/strings.py +105 -0
  26. ominfra/supervisor/{users.py → utils/users.py} +11 -8
  27. {ominfra-0.0.0.dev127.dist-info → ominfra-0.0.0.dev128.dist-info}/METADATA +3 -3
  28. {ominfra-0.0.0.dev127.dist-info → ominfra-0.0.0.dev128.dist-info}/RECORD +34 -29
  29. ominfra/supervisor/datatypes.py +0 -113
  30. ominfra/supervisor/utils.py +0 -206
  31. /ominfra/supervisor/{collections.py → utils/collections.py} +0 -0
  32. /ominfra/supervisor/{signals.py → utils/signals.py} +0 -0
  33. {ominfra-0.0.0.dev127.dist-info → ominfra-0.0.0.dev128.dist-info}/LICENSE +0 -0
  34. {ominfra-0.0.0.dev127.dist-info → ominfra-0.0.0.dev128.dist-info}/WHEEL +0 -0
  35. {ominfra-0.0.0.dev127.dist-info → ominfra-0.0.0.dev128.dist-info}/entry_points.txt +0 -0
  36. {ominfra-0.0.0.dev127.dist-info → ominfra-0.0.0.dev128.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,105 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import typing as ta
3
+
4
+
5
+ ##
6
+
7
+
8
+ def as_bytes(s: ta.Union[str, bytes], encoding: str = 'utf8') -> bytes:
9
+ if isinstance(s, bytes):
10
+ return s
11
+ else:
12
+ return s.encode(encoding)
13
+
14
+
15
+ @ta.overload
16
+ def find_prefix_at_end(haystack: str, needle: str) -> int:
17
+ ...
18
+
19
+
20
+ @ta.overload
21
+ def find_prefix_at_end(haystack: bytes, needle: bytes) -> int:
22
+ ...
23
+
24
+
25
+ def find_prefix_at_end(haystack, needle):
26
+ l = len(needle) - 1
27
+ while l and not haystack.endswith(needle[:l]):
28
+ l -= 1
29
+ return l
30
+
31
+
32
+ ##
33
+
34
+
35
+ ANSI_ESCAPE_BEGIN = b'\x1b['
36
+ ANSI_TERMINATORS = (b'H', b'f', b'A', b'B', b'C', b'D', b'R', b's', b'u', b'J', b'K', b'h', b'l', b'p', b'm')
37
+
38
+
39
+ def strip_escapes(s: bytes) -> bytes:
40
+ """Remove all ANSI color escapes from the given string."""
41
+
42
+ result = b''
43
+ show = 1
44
+ i = 0
45
+ l = len(s)
46
+ while i < l:
47
+ if show == 0 and s[i:i + 1] in ANSI_TERMINATORS:
48
+ show = 1
49
+ elif show:
50
+ n = s.find(ANSI_ESCAPE_BEGIN, i)
51
+ if n == -1:
52
+ return result + s[i:]
53
+ else:
54
+ result = result + s[i:n]
55
+ i = n
56
+ show = 0
57
+ i += 1
58
+ return result
59
+
60
+
61
+ ##
62
+
63
+
64
+ class SuffixMultiplier:
65
+ # d is a dictionary of suffixes to integer multipliers. If no suffixes match, default is the multiplier. Matches
66
+ # are case insensitive. Return values are in the fundamental unit.
67
+ def __init__(self, d, default=1):
68
+ super().__init__()
69
+ self._d = d
70
+ self._default = default
71
+ # all keys must be the same size
72
+ self._keysz = None
73
+ for k in d:
74
+ if self._keysz is None:
75
+ self._keysz = len(k)
76
+ elif self._keysz != len(k): # type: ignore
77
+ raise ValueError(k)
78
+
79
+ def __call__(self, v: ta.Union[str, int]) -> int:
80
+ if isinstance(v, int):
81
+ return v
82
+ v = v.lower()
83
+ for s, m in self._d.items():
84
+ if v[-self._keysz:] == s: # type: ignore
85
+ return int(v[:-self._keysz]) * m # type: ignore
86
+ return int(v) * self._default
87
+
88
+
89
+ parse_bytes_size = SuffixMultiplier({
90
+ 'kb': 1024,
91
+ 'mb': 1024 * 1024,
92
+ 'gb': 1024 * 1024 * 1024,
93
+ })
94
+
95
+
96
+ #
97
+
98
+
99
+ def parse_octal(arg: ta.Union[str, int]) -> int:
100
+ if isinstance(arg, int):
101
+ return arg
102
+ try:
103
+ return int(arg, 8)
104
+ except (TypeError, ValueError):
105
+ raise ValueError(f'{arg} can not be converted to an octal type') # noqa
@@ -3,11 +3,14 @@ import dataclasses as dc
3
3
  import grp
4
4
  import pwd
5
5
 
6
+ from .ostypes import Gid
7
+ from .ostypes import Uid
8
+
6
9
 
7
10
  ##
8
11
 
9
12
 
10
- def name_to_uid(name: str) -> int:
13
+ def name_to_uid(name: str) -> Uid:
11
14
  try:
12
15
  uid = int(name)
13
16
  except ValueError:
@@ -21,10 +24,10 @@ def name_to_uid(name: str) -> int:
21
24
  pwd.getpwuid(uid) # check if uid is valid
22
25
  except KeyError:
23
26
  raise ValueError(f'Invalid user id {name}') # noqa
24
- return uid
27
+ return Uid(uid)
25
28
 
26
29
 
27
- def name_to_gid(name: str) -> int:
30
+ def name_to_gid(name: str) -> Gid:
28
31
  try:
29
32
  gid = int(name)
30
33
  except ValueError:
@@ -38,12 +41,12 @@ def name_to_gid(name: str) -> int:
38
41
  grp.getgrgid(gid) # check if gid is valid
39
42
  except KeyError:
40
43
  raise ValueError(f'Invalid group id {name}') # noqa
41
- return gid
44
+ return Gid(gid)
42
45
 
43
46
 
44
- def gid_for_uid(uid: int) -> int:
47
+ def gid_for_uid(uid: Uid) -> Gid:
45
48
  pwrec = pwd.getpwuid(uid)
46
- return pwrec[3]
49
+ return Gid(pwrec[3])
47
50
 
48
51
 
49
52
  ##
@@ -52,8 +55,8 @@ def gid_for_uid(uid: int) -> int:
52
55
  @dc.dataclass(frozen=True)
53
56
  class User:
54
57
  name: str
55
- uid: int
56
- gid: int
58
+ uid: Uid
59
+ gid: Gid
57
60
 
58
61
 
59
62
  def get_user(name: str) -> User:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ominfra
3
- Version: 0.0.0.dev127
3
+ Version: 0.0.0.dev128
4
4
  Summary: ominfra
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,8 +12,8 @@ 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: omdev==0.0.0.dev127
16
- Requires-Dist: omlish==0.0.0.dev127
15
+ Requires-Dist: omdev==0.0.0.dev128
16
+ Requires-Dist: omlish==0.0.0.dev128
17
17
  Provides-Extra: all
18
18
  Requires-Dist: paramiko~=3.5; extra == "all"
19
19
  Requires-Dist: asyncssh~=2.18; extra == "all"
@@ -61,45 +61,50 @@ ominfra/pyremote/bootstrap.py,sha256=RvMO3YGaN1E4sgUi1JEtiPak8cjvqtc_vRCq1yqbeZg
61
61
  ominfra/pyremote/runcommands.py,sha256=bviS0_TDIoZVAe4h-_iavbvJtVSFu8lnk7fQ5iasCWE,1571
62
62
  ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  ominfra/scripts/journald2aws.py,sha256=UpwV8P1ZE8ywXW-8xpCaTCBRWe94BuG_MS1CXfD3wcw,128547
64
- ominfra/scripts/supervisor.py,sha256=siWG3_UrS0hxHPnoxUlEKm2jvW4O28lAPvlArlfKIwo,222808
64
+ ominfra/scripts/supervisor.py,sha256=ZqUDlxRxSML5Ty0sOKuils35km5-9xjYBQF4yQDnVaY,222164
65
65
  ominfra/supervisor/LICENSE.txt,sha256=yvqaMNsDhWxziHa9ien6qCW1SkZv-DQlAg96XjfSee8,1746
66
66
  ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
67
67
  ominfra/supervisor/__main__.py,sha256=I0yFw-C08OOiZ3BF6lF1Oiv789EQXu-_j6whDhQUTEA,66
68
- ominfra/supervisor/collections.py,sha256=vcfmVYS4QngMdtEI1DvdRIcubmy55Wj40NCzW27_rIY,1361
69
- ominfra/supervisor/configs.py,sha256=TtVyWdxinrd3tueM6q8j2YVcEqauFTJqlbykkSjByEo,3524
70
- ominfra/supervisor/context.py,sha256=4wOymUkic00rzt7UycQ0zqG4l5EXOsb-agr2IZ9OEWo,2697
71
- ominfra/supervisor/datatypes.py,sha256=3iMPodw0n9xnQzFN16gwYFU6wVb6NMMxKMZSSeAaXM4,2788
72
- ominfra/supervisor/dispatchers.py,sha256=nbgTaWrRxBvVfJSBsf2wnL4hTAG63PETXXpFaol6VCw,936
73
- ominfra/supervisor/dispatchersimpl.py,sha256=Shey0RVWxX1cgShEIlOsM3iJY5LAmayigi9sNnu4fQc,10897
68
+ ominfra/supervisor/configs.py,sha256=AhBlbifwDXc0acEhcbdv9jphJL-SBFODFDAWDVckzAE,3945
69
+ ominfra/supervisor/context.py,sha256=UDJc0mVHHFg3T7MyO7gehWX1wwmFvw-7xeKLl-cC8jc,2595
70
+ ominfra/supervisor/dispatchers.py,sha256=qWtVLx-4H3I-Io7OPcVgRpIYehGsA4q3Duo5ZWdUM4Y,970
71
+ ominfra/supervisor/dispatchersimpl.py,sha256=t1VFcofj1kTH1q13Z-S1OUTXixPwgSqJkh5A5IkHKPA,10956
74
72
  ominfra/supervisor/events.py,sha256=w3HQFrq-SuroYWoQfNFYeU1phnTvHTgsAqA6TGtAafI,6593
75
73
  ominfra/supervisor/exceptions.py,sha256=Qbu211H3CLlSmi9LsSikOwrcL5HgJP9ugvcKWlGTAoI,750
76
- ominfra/supervisor/groups.py,sha256=dznGuFQjNXH3qMimTuL_squgfwD-EcbBZQtjBjGd4wU,2157
74
+ ominfra/supervisor/groups.py,sha256=g5Zp_lkVhn1FSe6GSEPbaELincG5a46ctv1xpB-WmnQ,2163
77
75
  ominfra/supervisor/groupsimpl.py,sha256=_5Mxf6VdVV375KgwcuUTpErUH4FBpmzbNm3vbGB_JaQ,2304
78
- ominfra/supervisor/inject.py,sha256=JBb6bC82Ud1YVAt5fJHc8Qp_xMhUa_q1njweADtRzfM,3036
79
- ominfra/supervisor/main.py,sha256=4vtYKLBX68MaTk3WEYv-oW_mayZGSdBnfUGgKqgeLR8,4131
80
- ominfra/supervisor/pipes.py,sha256=xJqpZb8X6CNWZq788g7zQoc--iJCAOurGPZn2YEP1ck,2169
81
- ominfra/supervisor/poller.py,sha256=ijCjVg7aHuSBape49f5v1nI1jQv0czZjNXEDPdNFTNg,7764
76
+ ominfra/supervisor/inject.py,sha256=ZCfloXxURjiVTutzudGFWybrVCvjDD_C3HayMATCMrY,3042
77
+ ominfra/supervisor/main.py,sha256=RCCpMX4D2RKT8vZMF82pENKpXfW3GUdNgMEUzUtpqL0,4140
78
+ ominfra/supervisor/pipes.py,sha256=XrJ9lD04tPdzZD3xhhYKxpBKHWhZ0Ii315E78bgj7ws,2233
79
+ ominfra/supervisor/poller.py,sha256=LnQVttPCm8a1UtnDvsho6zLw8NP-2_2VUiNM-d0w_FU,7776
82
80
  ominfra/supervisor/privileges.py,sha256=bO7rJGT7cMOBALK_4D4NiQnOS5dOYb14Sz66R-ymG24,2071
83
- ominfra/supervisor/processes.py,sha256=iYvhd9fsqvMFacN1btCV_-ICahMB4lXqcfV1IQdAziA,186
84
- ominfra/supervisor/processesimpl.py,sha256=AHj-3vzoUCDK4TnGuVfXwtruHPwpuizwd0mGDClJvgM,19050
85
- ominfra/supervisor/setup.py,sha256=TmSs6dPnKaeZ4fuCvY-O1FL5-Nil0pSJC8ZG8i84Olk,616
86
- ominfra/supervisor/setupimpl.py,sha256=bwgu2QaBqUeMiiiOZBU0IvLjKEjA230eUNkrdeO3bnA,9608
87
- ominfra/supervisor/signals.py,sha256=uZkTvissbtq7TlJD4MkTiL3F-zyWmAFUuWQtFjsf0MI,1474
88
- ominfra/supervisor/spawning.py,sha256=bX6pnxIACXioTFxKTn6siuRuNRk9AjSCexYUdoCG0Ds,591
89
- ominfra/supervisor/spawningimpl.py,sha256=zaamb1aOsHv1QaV4Rh_e6LErUTwXJULcf_PGsrhNz_c,10941
81
+ ominfra/supervisor/process.py,sha256=UaubVxsxVqDnbuWVpTH0DTGbJGLO0vGJ9mNcvy2kCXM,217
82
+ ominfra/supervisor/processimpl.py,sha256=0i0P3gdxuJsgcvy2VTKN6-NYgcBjozUaPsA_tUcEmb4,18769
83
+ ominfra/supervisor/setup.py,sha256=7HwwwI-WT_Z0WjZ9_l5Orr4K298nKKhQ1f_ZgGsi9TU,622
84
+ ominfra/supervisor/setupimpl.py,sha256=S_YgCH3XzLsFIAriJROvDMUDh7OzVVJoxzEzCkbb4g4,9648
85
+ ominfra/supervisor/spawning.py,sha256=i1k3tmqWyU-KIN7kel-JVxTVGnLiTIVmZzlstJSZpjM,622
86
+ ominfra/supervisor/spawningimpl.py,sha256=0InDyRPh7gAEX07lg6eUYMymX0RikHOz_ieAghxKx8Y,11063
90
87
  ominfra/supervisor/states.py,sha256=9yoNOSwalRcKEnCP9zG6tVS0oivo5tCeuH6AaaW7Jpc,890
91
- ominfra/supervisor/supervisor.py,sha256=R5tx5htbabV1p-MIS2W0G5A54T5edISa5A3VG19Ib-0,11972
92
- ominfra/supervisor/types.py,sha256=PuLvxK-kIzzf6G3Ou9JlbDg9jfu1hBVhohr-56Qu1xk,4772
93
- ominfra/supervisor/users.py,sha256=7aTI1oWMWSTLuhWCtoKZd11F9kRKR21by6_GKuvWe50,1279
94
- ominfra/supervisor/utils.py,sha256=jlUy5WaCIG7YqOLRoV_9aU5i26K0Cn7ID4_Mj-Y0Z2w,4368
88
+ ominfra/supervisor/supervisor.py,sha256=3yBaGJHJGqDXlARjpHWg7371N6jb29HaFEI-_fSp-xU,12028
89
+ ominfra/supervisor/types.py,sha256=i2C7ZBvLqjVliIYAYQnPx2WwIQ14HIVV1hTUgB2mbBM,4740
90
+ ominfra/supervisor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
+ ominfra/supervisor/utils/collections.py,sha256=vcfmVYS4QngMdtEI1DvdRIcubmy55Wj40NCzW27_rIY,1361
92
+ ominfra/supervisor/utils/diag.py,sha256=ujz4gkW7p3wmbaKFM8Hz5eHEwpoUkbB8JeDvcHilCz0,705
93
+ ominfra/supervisor/utils/fds.py,sha256=lz8DWXzGYvu93dqhWK0WrhXrrJVQ_psoom4Nj_o8g2g,849
94
+ ominfra/supervisor/utils/fs.py,sha256=ABbNcsCpzSXAvq_ZZSCj61mj5kGnVuC4spUmoWenlqw,1155
95
+ ominfra/supervisor/utils/os.py,sha256=9fw--tpHOrSjGTCkUo1KRBgbGGxKW2va5xKw2cHwtRU,1096
96
+ ominfra/supervisor/utils/ostypes.py,sha256=B7VjwbzVesz9we9MztoSk8bH8sTxMIWtILy_Qde0G7w,164
97
+ ominfra/supervisor/utils/signals.py,sha256=uZkTvissbtq7TlJD4MkTiL3F-zyWmAFUuWQtFjsf0MI,1474
98
+ ominfra/supervisor/utils/strings.py,sha256=B0UOuVM_NIWmcznycmiEbwJ0lcoTGEd3Ir1AeLkBXeU,2478
99
+ ominfra/supervisor/utils/users.py,sha256=PRUhWy74WQCxix4BLNYcWW1i2mF1IyAxj1RzElnP4iM,1345
95
100
  ominfra/tailscale/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
101
  ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
97
102
  ominfra/tailscale/cli.py,sha256=DSGp4hn5xwOW-l_u_InKlSF6kIobxtUtVssf_73STs0,3567
98
103
  ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
99
104
  ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
100
- ominfra-0.0.0.dev127.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
101
- ominfra-0.0.0.dev127.dist-info/METADATA,sha256=hh8Q28eSocVm9p5V6DwXLyomgWAU_HqKJhx5CKlVr58,731
102
- ominfra-0.0.0.dev127.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
103
- ominfra-0.0.0.dev127.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
104
- ominfra-0.0.0.dev127.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
105
- ominfra-0.0.0.dev127.dist-info/RECORD,,
105
+ ominfra-0.0.0.dev128.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
106
+ ominfra-0.0.0.dev128.dist-info/METADATA,sha256=JV6Hw2ZOpDub73wDD4p69Qq9F6XbbKlthV7CmH6G_-k,731
107
+ ominfra-0.0.0.dev128.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
108
+ ominfra-0.0.0.dev128.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
109
+ ominfra-0.0.0.dev128.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
110
+ ominfra-0.0.0.dev128.dist-info/RECORD,,
@@ -1,113 +0,0 @@
1
- # ruff: noqa: UP007
2
- import logging
3
- import os
4
- import typing as ta
5
-
6
-
7
- class Automatic:
8
- pass
9
-
10
-
11
- class Syslog:
12
- """TODO deprecated; remove this special 'syslog' filename in the future"""
13
-
14
-
15
- LOGFILE_NONES = ('none', 'off', None)
16
- LOGFILE_AUTOS = (Automatic, 'auto')
17
- LOGFILE_SYSLOGS = (Syslog, 'syslog')
18
-
19
-
20
- def logfile_name(val):
21
- if hasattr(val, 'lower'):
22
- coerced = val.lower()
23
- else:
24
- coerced = val
25
-
26
- if coerced in LOGFILE_NONES:
27
- return None
28
- elif coerced in LOGFILE_AUTOS:
29
- return Automatic
30
- elif coerced in LOGFILE_SYSLOGS:
31
- return Syslog
32
- else:
33
- return existing_dirpath(val)
34
-
35
-
36
- ##
37
-
38
-
39
- def octal_type(arg: ta.Union[str, int]) -> int:
40
- if isinstance(arg, int):
41
- return arg
42
- try:
43
- return int(arg, 8)
44
- except (TypeError, ValueError):
45
- raise ValueError(f'{arg} can not be converted to an octal type') # noqa
46
-
47
-
48
- def existing_directory(v: str) -> str:
49
- nv = os.path.expanduser(v)
50
- if os.path.isdir(nv):
51
- return nv
52
- raise ValueError(f'{v} is not an existing directory')
53
-
54
-
55
- def existing_dirpath(v: str) -> str:
56
- nv = os.path.expanduser(v)
57
- dir = os.path.dirname(nv) # noqa
58
- if not dir:
59
- # relative pathname with no directory component
60
- return nv
61
- if os.path.isdir(dir):
62
- return nv
63
- raise ValueError(f'The directory named as part of the path {v} does not exist')
64
-
65
-
66
- def logging_level(value: ta.Union[str, int]) -> int:
67
- if isinstance(value, int):
68
- return value
69
- s = str(value).lower()
70
- level = logging.getLevelNamesMapping().get(s.upper())
71
- if level is None:
72
- raise ValueError(f'bad logging level name {value!r}')
73
- return level
74
-
75
-
76
- class SuffixMultiplier:
77
- # d is a dictionary of suffixes to integer multipliers. If no suffixes match, default is the multiplier. Matches
78
- # are case insensitive. Return values are in the fundamental unit.
79
- def __init__(self, d, default=1):
80
- super().__init__()
81
- self._d = d
82
- self._default = default
83
- # all keys must be the same size
84
- self._keysz = None
85
- for k in d:
86
- if self._keysz is None:
87
- self._keysz = len(k)
88
- elif self._keysz != len(k): # type: ignore
89
- raise ValueError(k)
90
-
91
- def __call__(self, v: ta.Union[str, int]) -> int:
92
- if isinstance(v, int):
93
- return v
94
- v = v.lower()
95
- for s, m in self._d.items():
96
- if v[-self._keysz:] == s: # type: ignore
97
- return int(v[:-self._keysz]) * m # type: ignore
98
- return int(v) * self._default
99
-
100
-
101
- byte_size = SuffixMultiplier({
102
- 'kb': 1024,
103
- 'mb': 1024 * 1024,
104
- 'gb': 1024 * 1024 * 1024,
105
- })
106
-
107
-
108
- class RestartWhenExitUnexpected:
109
- pass
110
-
111
-
112
- class RestartUnconditionally:
113
- pass
@@ -1,206 +0,0 @@
1
- # ruff: noqa: UP006 UP007
2
- import errno
3
- import os
4
- import sys
5
- import tempfile
6
- import types
7
- import typing as ta
8
-
9
- from .signals import sig_name
10
-
11
-
12
- T = ta.TypeVar('T')
13
-
14
-
15
- ##
16
-
17
-
18
- def as_bytes(s: ta.Union[str, bytes], encoding: str = 'utf8') -> bytes:
19
- if isinstance(s, bytes):
20
- return s
21
- else:
22
- return s.encode(encoding)
23
-
24
-
25
- def as_string(s: ta.Union[str, bytes], encoding: str = 'utf8') -> str:
26
- if isinstance(s, str):
27
- return s
28
- else:
29
- return s.decode(encoding)
30
-
31
-
32
- def find_prefix_at_end(haystack: bytes, needle: bytes) -> int:
33
- l = len(needle) - 1
34
- while l and not haystack.endswith(needle[:l]):
35
- l -= 1
36
- return l
37
-
38
-
39
- ##
40
-
41
-
42
- def compact_traceback() -> ta.Tuple[
43
- ta.Tuple[str, str, int],
44
- ta.Type[BaseException],
45
- BaseException,
46
- types.TracebackType,
47
- ]:
48
- t, v, tb = sys.exc_info()
49
- if not tb:
50
- raise RuntimeError('No traceback')
51
-
52
- tbinfo = []
53
- while tb:
54
- tbinfo.append((
55
- tb.tb_frame.f_code.co_filename,
56
- tb.tb_frame.f_code.co_name,
57
- str(tb.tb_lineno),
58
- ))
59
- tb = tb.tb_next
60
-
61
- # just to be safe
62
- del tb
63
-
64
- file, function, line = tbinfo[-1]
65
- info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo]) # noqa
66
- return (file, function, line), t, v, info # type: ignore
67
-
68
-
69
- class ExitNow(Exception): # noqa
70
- pass
71
-
72
-
73
- def real_exit(code: int) -> None:
74
- os._exit(code) # noqa
75
-
76
-
77
- ##
78
-
79
-
80
- def decode_wait_status(sts: int) -> ta.Tuple[int, str]:
81
- """
82
- Decode the status returned by wait() or waitpid().
83
-
84
- Return a tuple (exitstatus, message) where exitstatus is the exit status, or -1 if the process was killed by a
85
- signal; and message is a message telling what happened. It is the caller's responsibility to display the message.
86
- """
87
-
88
- if os.WIFEXITED(sts):
89
- es = os.WEXITSTATUS(sts) & 0xffff
90
- msg = f'exit status {es}'
91
- return es, msg
92
- elif os.WIFSIGNALED(sts):
93
- sig = os.WTERMSIG(sts)
94
- msg = f'terminated by {sig_name(sig)}'
95
- if hasattr(os, 'WCOREDUMP'):
96
- iscore = os.WCOREDUMP(sts)
97
- else:
98
- iscore = bool(sts & 0x80)
99
- if iscore:
100
- msg += ' (core dumped)'
101
- return -1, msg
102
- else:
103
- msg = 'unknown termination cause 0x%04x' % sts # noqa
104
- return -1, msg
105
-
106
-
107
- ##
108
-
109
-
110
- def read_fd(fd: int) -> bytes:
111
- try:
112
- data = os.read(fd, 2 << 16) # 128K
113
- except OSError as why:
114
- if why.args[0] not in (errno.EWOULDBLOCK, errno.EBADF, errno.EINTR):
115
- raise
116
- data = b''
117
- return data
118
-
119
-
120
- def try_unlink(path: str) -> bool:
121
- try:
122
- os.unlink(path)
123
- except OSError:
124
- return False
125
- return True
126
-
127
-
128
- def close_fd(fd: int) -> bool:
129
- try:
130
- os.close(fd)
131
- except OSError:
132
- return False
133
- return True
134
-
135
-
136
- def is_fd_open(fd: int) -> bool:
137
- try:
138
- n = os.dup(fd)
139
- except OSError:
140
- return False
141
- os.close(n)
142
- return True
143
-
144
-
145
- def get_open_fds(limit: int) -> ta.FrozenSet[int]:
146
- return frozenset(filter(is_fd_open, range(limit)))
147
-
148
-
149
- def mktempfile(suffix: str, prefix: str, dir: str) -> str: # noqa
150
- fd, filename = tempfile.mkstemp(suffix, prefix, dir)
151
- os.close(fd)
152
- return filename
153
-
154
-
155
- ##
156
-
157
-
158
- def get_path() -> ta.Sequence[str]:
159
- """Return a list corresponding to $PATH, or a default."""
160
-
161
- path = ['/bin', '/usr/bin', '/usr/local/bin']
162
- if 'PATH' in os.environ:
163
- p = os.environ['PATH']
164
- if p:
165
- path = p.split(os.pathsep)
166
- return path
167
-
168
-
169
- def normalize_path(v: str) -> str:
170
- return os.path.normpath(os.path.abspath(os.path.expanduser(v)))
171
-
172
-
173
- ##
174
-
175
-
176
- ANSI_ESCAPE_BEGIN = b'\x1b['
177
- ANSI_TERMINATORS = (b'H', b'f', b'A', b'B', b'C', b'D', b'R', b's', b'u', b'J', b'K', b'h', b'l', b'p', b'm')
178
-
179
-
180
- def strip_escapes(s: bytes) -> bytes:
181
- """Remove all ANSI color escapes from the given string."""
182
-
183
- result = b''
184
- show = 1
185
- i = 0
186
- l = len(s)
187
- while i < l:
188
- if show == 0 and s[i:i + 1] in ANSI_TERMINATORS:
189
- show = 1
190
- elif show:
191
- n = s.find(ANSI_ESCAPE_BEGIN, i)
192
- if n == -1:
193
- return result + s[i:]
194
- else:
195
- result = result + s[i:n]
196
- i = n
197
- show = 0
198
- i += 1
199
- return result
200
-
201
-
202
- ##
203
-
204
-
205
- def timeslice(period: int, when: float) -> int:
206
- return int(when - (when % period))
File without changes