omdev 0.0.0.dev212__py3-none-any.whl → 0.0.0.dev213__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.
@@ -0,0 +1,209 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import dataclasses as dc
4
+ import json
5
+ import os
6
+ import shlex
7
+ import typing as ta
8
+
9
+ from omlish.lite.check import check
10
+ from omlish.lite.contextmanagers import defer
11
+ from omlish.lite.json import json_dumps_compact
12
+ from omlish.subprocesses import subprocesses
13
+
14
+ from ..shell import ShellCmd
15
+ from ..utils import make_temp_file
16
+
17
+
18
+ ##
19
+
20
+
21
+ class GithubServiceCurlClient:
22
+ def __init__(
23
+ self,
24
+ service_url: str,
25
+ auth_token: ta.Optional[str] = None,
26
+ *,
27
+ api_version: ta.Optional[str] = None,
28
+ ) -> None:
29
+ super().__init__()
30
+
31
+ self._service_url = check.non_empty_str(service_url)
32
+ self._auth_token = auth_token
33
+ self._api_version = api_version
34
+
35
+ #
36
+
37
+ _MISSING = object()
38
+
39
+ def build_headers(
40
+ self,
41
+ headers: ta.Optional[ta.Mapping[str, str]] = None,
42
+ *,
43
+ auth_token: ta.Any = _MISSING,
44
+ content_type: ta.Optional[str] = None,
45
+ ) -> ta.Dict[str, str]:
46
+ dct = {
47
+ 'Accept': ';'.join([
48
+ 'application/json',
49
+ *([f'api-version={self._api_version}'] if self._api_version else []),
50
+ ]),
51
+ }
52
+
53
+ if auth_token is self._MISSING:
54
+ auth_token = self._auth_token
55
+ if auth_token:
56
+ dct['Authorization'] = f'Bearer {auth_token}'
57
+
58
+ if content_type is not None:
59
+ dct['Content-Type'] = content_type
60
+
61
+ if headers:
62
+ dct.update(headers)
63
+
64
+ return dct
65
+
66
+ #
67
+
68
+ HEADER_AUTH_TOKEN_ENV_KEY_PREFIX = '_GITHUB_SERVICE_AUTH_TOKEN' # noqa
69
+
70
+ @property
71
+ def header_auth_token_env_key(self) -> str:
72
+ return f'{self.HEADER_AUTH_TOKEN_ENV_KEY_PREFIX}_{id(self)}'
73
+
74
+ def build_cmd(
75
+ self,
76
+ method: str,
77
+ url: str,
78
+ *,
79
+ json_content: bool = False,
80
+ content_type: ta.Optional[str] = None,
81
+ headers: ta.Optional[ta.Dict[str, str]] = None,
82
+ ) -> ShellCmd:
83
+ if content_type is None and json_content:
84
+ content_type = 'application/json'
85
+
86
+ env = {}
87
+
88
+ header_auth_token: ta.Optional[str]
89
+ if self._auth_token:
90
+ header_env_key = self.header_auth_token_env_key
91
+ env[header_env_key] = self._auth_token
92
+ header_auth_token = f'${header_env_key}'
93
+ else:
94
+ header_auth_token = None
95
+
96
+ built_hdrs = self.build_headers(
97
+ headers,
98
+ auth_token=header_auth_token,
99
+ content_type=content_type,
100
+ )
101
+
102
+ url = f'{self._service_url}/{url}'
103
+
104
+ cmd = ' '.join([
105
+ 'curl',
106
+ '-s',
107
+ '-X', method,
108
+ url,
109
+ *[f'-H "{k}: {v}"' for k, v in built_hdrs.items()],
110
+ ])
111
+
112
+ return ShellCmd(
113
+ cmd,
114
+ env=env,
115
+ )
116
+
117
+ def build_post_json_cmd(
118
+ self,
119
+ url: str,
120
+ obj: ta.Any,
121
+ **kwargs: ta.Any,
122
+ ) -> ShellCmd:
123
+ curl_cmd = self.build_cmd(
124
+ 'POST',
125
+ url,
126
+ json_content=True,
127
+ **kwargs,
128
+ )
129
+
130
+ obj_json = json_dumps_compact(obj)
131
+
132
+ return dc.replace(curl_cmd, s=f'{curl_cmd.s} -d {shlex.quote(obj_json)}')
133
+
134
+ #
135
+
136
+ @dc.dataclass()
137
+ class Error(RuntimeError):
138
+ status_code: int
139
+ body: ta.Optional[bytes]
140
+
141
+ def __str__(self) -> str:
142
+ return repr(self)
143
+
144
+ @dc.dataclass(frozen=True)
145
+ class Result:
146
+ status_code: int
147
+ body: ta.Optional[bytes]
148
+
149
+ def as_error(self) -> 'GithubServiceCurlClient.Error':
150
+ return GithubServiceCurlClient.Error(
151
+ status_code=self.status_code,
152
+ body=self.body,
153
+ )
154
+
155
+ def run_cmd(
156
+ self,
157
+ cmd: ShellCmd,
158
+ *,
159
+ raise_: bool = False,
160
+ **subprocess_kwargs: ta.Any,
161
+ ) -> Result:
162
+ out_file = make_temp_file()
163
+ with defer(lambda: os.unlink(out_file)):
164
+ run_cmd = dc.replace(cmd, s=f"{cmd.s} -o {out_file} -w '%{{json}}'")
165
+
166
+ out_json_bytes = run_cmd.run(
167
+ subprocesses.check_output,
168
+ **subprocess_kwargs,
169
+ )
170
+
171
+ out_json = json.loads(out_json_bytes.decode())
172
+ status_code = check.isinstance(out_json['response_code'], int)
173
+
174
+ with open(out_file, 'rb') as f:
175
+ body = f.read()
176
+
177
+ result = self.Result(
178
+ status_code=status_code,
179
+ body=body,
180
+ )
181
+
182
+ if raise_ and (500 <= status_code <= 600):
183
+ raise result.as_error()
184
+
185
+ return result
186
+
187
+ def run_json_cmd(
188
+ self,
189
+ cmd: ShellCmd,
190
+ *,
191
+ success_status_codes: ta.Optional[ta.Container[int]] = None,
192
+ ) -> ta.Optional[ta.Any]:
193
+ result = self.run_cmd(cmd, raise_=True)
194
+
195
+ if success_status_codes is not None:
196
+ is_success = result.status_code in success_status_codes
197
+ else:
198
+ is_success = 200 <= result.status_code < 300
199
+
200
+ if is_success:
201
+ if not (body := result.body):
202
+ return None
203
+ return json.loads(body.decode('utf-8-sig'))
204
+
205
+ elif result.status_code == 404:
206
+ return None
207
+
208
+ else:
209
+ raise result.as_error()
omdev/git/shallow.py CHANGED
@@ -44,7 +44,7 @@ class GitShallowCloner:
44
44
  'clone',
45
45
  '-n',
46
46
  '--depth=1',
47
- *(['--filter=tree:0'] if self.repo_subtrees is not None else []),
47
+ '--filter=tree:0',
48
48
  *(['-b', self.branch] if self.branch else []),
49
49
  '--single-branch',
50
50
  self.repo_url,