omdev 0.0.0.dev212__py3-none-any.whl → 0.0.0.dev213__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,