omdev 0.0.0.dev212__py3-none-any.whl → 0.0.0.dev214__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 +1 -1
- omdev/cc/cdeps.py +34 -1
- omdev/cc/cdeps.toml +19 -2
- omdev/cc/cli.py +13 -1
- omdev/ci/__init__.py +1 -0
- omdev/ci/cache.py +100 -121
- omdev/ci/ci.py +161 -136
- omdev/ci/cli.py +62 -30
- omdev/ci/compose.py +26 -62
- omdev/ci/consts.py +1 -0
- omdev/ci/docker.py +39 -22
- omdev/ci/github/{cacheapi.py → api.py} +1 -2
- omdev/ci/github/bootstrap.py +8 -1
- omdev/ci/github/cache.py +36 -320
- omdev/ci/github/cli.py +9 -5
- omdev/ci/github/client.py +492 -0
- omdev/ci/github/env.py +21 -0
- omdev/ci/requirements.py +0 -1
- omdev/ci/shell.py +0 -1
- omdev/ci/utils.py +2 -14
- omdev/git/shallow.py +1 -1
- omdev/scripts/ci.py +1602 -887
- omdev/scripts/interp.py +23 -0
- omdev/scripts/pyproject.py +23 -0
- omdev/tokens/tokenizert.py +1 -3
- omdev/tools/docker.py +6 -0
- {omdev-0.0.0.dev212.dist-info → omdev-0.0.0.dev214.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev212.dist-info → omdev-0.0.0.dev214.dist-info}/RECORD +32 -29
- {omdev-0.0.0.dev212.dist-info → omdev-0.0.0.dev214.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev212.dist-info → omdev-0.0.0.dev214.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev212.dist-info → omdev-0.0.0.dev214.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev212.dist-info → omdev-0.0.0.dev214.dist-info}/top_level.txt +0 -0
omdev/ci/ci.py
CHANGED
@@ -1,19 +1,15 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
-
# @omlish-lite
|
3
2
|
import dataclasses as dc
|
4
3
|
import os.path
|
5
|
-
import shutil
|
6
|
-
import tarfile
|
7
|
-
import tempfile
|
8
4
|
import typing as ta
|
9
5
|
|
6
|
+
from omlish.lite.cached import async_cached_nullary
|
10
7
|
from omlish.lite.cached import cached_nullary
|
11
8
|
from omlish.lite.check import check
|
12
|
-
from omlish.lite.contextmanagers import
|
13
|
-
from omlish.
|
9
|
+
from omlish.lite.contextmanagers import AsyncExitStacked
|
10
|
+
from omlish.os.temp import temp_file_context
|
14
11
|
|
15
12
|
from .cache import FileCache
|
16
|
-
from .cache import ShellCache
|
17
13
|
from .compose import DockerComposeRun
|
18
14
|
from .compose import get_compose_service_dependencies
|
19
15
|
from .docker import build_docker_file_hash
|
@@ -22,14 +18,14 @@ from .docker import is_docker_image_present
|
|
22
18
|
from .docker import load_docker_tar_cmd
|
23
19
|
from .docker import pull_docker_image
|
24
20
|
from .docker import save_docker_tar_cmd
|
21
|
+
from .docker import tag_docker_image
|
25
22
|
from .requirements import build_requirements_hash
|
26
|
-
from .requirements import download_requirements
|
27
23
|
from .shell import ShellCmd
|
28
24
|
from .utils import log_timing_context
|
29
25
|
|
30
26
|
|
31
|
-
class Ci(
|
32
|
-
|
27
|
+
class Ci(AsyncExitStacked):
|
28
|
+
KEY_HASH_LEN = 16
|
33
29
|
|
34
30
|
@dc.dataclass(frozen=True)
|
35
31
|
class Config:
|
@@ -42,9 +38,18 @@ class Ci(ExitStacked):
|
|
42
38
|
|
43
39
|
cmd: ShellCmd
|
44
40
|
|
41
|
+
#
|
42
|
+
|
45
43
|
requirements_txts: ta.Optional[ta.Sequence[str]] = None
|
46
44
|
|
47
45
|
always_pull: bool = False
|
46
|
+
always_build: bool = False
|
47
|
+
|
48
|
+
no_dependencies: bool = False
|
49
|
+
|
50
|
+
run_options: ta.Optional[ta.Sequence[str]] = None
|
51
|
+
|
52
|
+
#
|
48
53
|
|
49
54
|
def __post_init__(self) -> None:
|
50
55
|
check.not_isinstance(self.requirements_txts, str)
|
@@ -53,44 +58,17 @@ class Ci(ExitStacked):
|
|
53
58
|
self,
|
54
59
|
cfg: Config,
|
55
60
|
*,
|
56
|
-
shell_cache: ta.Optional[ShellCache] = None,
|
57
61
|
file_cache: ta.Optional[FileCache] = None,
|
58
62
|
) -> None:
|
59
63
|
super().__init__()
|
60
64
|
|
61
65
|
self._cfg = cfg
|
62
|
-
self._shell_cache = shell_cache
|
63
66
|
self._file_cache = file_cache
|
64
67
|
|
65
68
|
#
|
66
69
|
|
67
|
-
def
|
68
|
-
if self.
|
69
|
-
return None
|
70
|
-
|
71
|
-
get_cache_cmd = self._shell_cache.get_file_cmd(key)
|
72
|
-
if get_cache_cmd is None:
|
73
|
-
return None
|
74
|
-
|
75
|
-
get_cache_cmd = dc.replace(get_cache_cmd, s=f'{get_cache_cmd.s} | zstd -cd --long') # noqa
|
76
|
-
|
77
|
-
return load_docker_tar_cmd(get_cache_cmd)
|
78
|
-
|
79
|
-
def _save_cache_docker_image(self, key: str, image: str) -> None:
|
80
|
-
if self._shell_cache is None:
|
81
|
-
return
|
82
|
-
|
83
|
-
with self._shell_cache.put_file_cmd(key) as put_cache:
|
84
|
-
put_cache_cmd = put_cache.cmd
|
85
|
-
|
86
|
-
put_cache_cmd = dc.replace(put_cache_cmd, s=f'zstd | {put_cache_cmd.s}')
|
87
|
-
|
88
|
-
save_docker_tar_cmd(image, put_cache_cmd)
|
89
|
-
|
90
|
-
#
|
91
|
-
|
92
|
-
def _load_docker_image(self, image: str) -> None:
|
93
|
-
if not self._cfg.always_pull and is_docker_image_present(image):
|
70
|
+
async def _load_docker_image(self, image: str) -> None:
|
71
|
+
if not self._cfg.always_pull and (await is_docker_image_present(image)):
|
94
72
|
return
|
95
73
|
|
96
74
|
dep_suffix = image
|
@@ -98,152 +76,199 @@ class Ci(ExitStacked):
|
|
98
76
|
dep_suffix = dep_suffix.replace(c, '-')
|
99
77
|
|
100
78
|
cache_key = f'docker-{dep_suffix}'
|
101
|
-
if self._load_cache_docker_image(cache_key) is not None:
|
79
|
+
if (await self._load_cache_docker_image(cache_key)) is not None:
|
102
80
|
return
|
103
81
|
|
104
|
-
pull_docker_image(image)
|
82
|
+
await pull_docker_image(image)
|
105
83
|
|
106
|
-
self._save_cache_docker_image(cache_key, image)
|
84
|
+
await self._save_cache_docker_image(cache_key, image)
|
107
85
|
|
108
|
-
def load_docker_image(self, image: str) -> None:
|
86
|
+
async def load_docker_image(self, image: str) -> None:
|
109
87
|
with log_timing_context(f'Load docker image: {image}'):
|
110
|
-
self._load_docker_image(image)
|
111
|
-
|
112
|
-
@cached_nullary
|
113
|
-
def load_compose_service_dependencies(self) -> None:
|
114
|
-
deps = get_compose_service_dependencies(
|
115
|
-
self._cfg.compose_file,
|
116
|
-
self._cfg.service,
|
117
|
-
)
|
118
|
-
|
119
|
-
for dep_image in deps.values():
|
120
|
-
self.load_docker_image(dep_image)
|
88
|
+
await self._load_docker_image(image)
|
121
89
|
|
122
90
|
#
|
123
91
|
|
124
|
-
def
|
125
|
-
|
92
|
+
async def _load_cache_docker_image(self, key: str) -> ta.Optional[str]:
|
93
|
+
if self._file_cache is None:
|
94
|
+
return None
|
126
95
|
|
127
|
-
|
128
|
-
if
|
129
|
-
return
|
96
|
+
cache_file = await self._file_cache.get_file(key)
|
97
|
+
if cache_file is None:
|
98
|
+
return None
|
130
99
|
|
131
|
-
|
132
|
-
self._cfg.docker_file,
|
133
|
-
cwd=self._cfg.project_dir,
|
134
|
-
)
|
100
|
+
get_cache_cmd = ShellCmd(f'cat {cache_file} | zstd -cd --long')
|
135
101
|
|
136
|
-
|
102
|
+
return await load_docker_tar_cmd(get_cache_cmd)
|
137
103
|
|
138
|
-
|
104
|
+
async def _save_cache_docker_image(self, key: str, image: str) -> None:
|
105
|
+
if self._file_cache is None:
|
106
|
+
return
|
139
107
|
|
140
|
-
|
141
|
-
|
142
|
-
with log_timing_context('Resolve ci image') as ltc:
|
143
|
-
image_id = self._resolve_ci_image()
|
144
|
-
ltc.set_description(f'Resolve ci image: {image_id}')
|
145
|
-
return image_id
|
108
|
+
with temp_file_context() as tmp_file:
|
109
|
+
write_tmp_cmd = ShellCmd(f'zstd > {tmp_file}')
|
146
110
|
|
147
|
-
|
111
|
+
await save_docker_tar_cmd(image, write_tmp_cmd)
|
148
112
|
|
149
|
-
|
150
|
-
requirements_txts = [
|
151
|
-
os.path.join(self._cfg.project_dir, rf)
|
152
|
-
for rf in check.not_none(self._cfg.requirements_txts)
|
153
|
-
]
|
113
|
+
await self._file_cache.put_file(key, tmp_file, steal=True)
|
154
114
|
|
155
|
-
|
115
|
+
#
|
156
116
|
|
157
|
-
|
158
|
-
|
117
|
+
async def _resolve_docker_image(
|
118
|
+
self,
|
119
|
+
cache_key: str,
|
120
|
+
build_and_tag: ta.Callable[[str], ta.Awaitable[str]],
|
121
|
+
) -> str:
|
122
|
+
image_tag = f'{self._cfg.service}:{cache_key}'
|
159
123
|
|
160
|
-
|
161
|
-
|
124
|
+
if not self._cfg.always_build and (await is_docker_image_present(image_tag)):
|
125
|
+
return image_tag
|
162
126
|
|
163
|
-
if
|
164
|
-
|
165
|
-
|
127
|
+
if (cache_image_id := await self._load_cache_docker_image(cache_key)) is not None:
|
128
|
+
await tag_docker_image(
|
129
|
+
cache_image_id,
|
130
|
+
image_tag,
|
131
|
+
)
|
132
|
+
return image_tag
|
166
133
|
|
167
|
-
|
134
|
+
image_id = await build_and_tag(image_tag)
|
168
135
|
|
169
|
-
|
170
|
-
os.makedirs(temp_requirements_dir)
|
136
|
+
await self._save_cache_docker_image(cache_key, image_id)
|
171
137
|
|
172
|
-
|
173
|
-
self.resolve_ci_image(),
|
174
|
-
temp_requirements_dir,
|
175
|
-
requirements_txts,
|
176
|
-
)
|
138
|
+
return image_tag
|
177
139
|
|
178
|
-
|
179
|
-
temp_tar_file = os.path.join(temp_dir, tar_file_name)
|
140
|
+
#
|
180
141
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
142
|
+
@cached_nullary
|
143
|
+
def docker_file_hash(self) -> str:
|
144
|
+
return build_docker_file_hash(self._cfg.docker_file)[:self.KEY_HASH_LEN]
|
145
|
+
|
146
|
+
async def _resolve_ci_base_image(self) -> str:
|
147
|
+
async def build_and_tag(image_tag: str) -> str:
|
148
|
+
return await build_docker_image(
|
149
|
+
self._cfg.docker_file,
|
150
|
+
tag=image_tag,
|
151
|
+
cwd=self._cfg.project_dir,
|
152
|
+
)
|
153
|
+
|
154
|
+
cache_key = f'ci-base-{self.docker_file_hash()}'
|
155
|
+
|
156
|
+
return await self._resolve_docker_image(cache_key, build_and_tag)
|
157
|
+
|
158
|
+
@async_cached_nullary
|
159
|
+
async def resolve_ci_base_image(self) -> str:
|
160
|
+
with log_timing_context('Resolve ci base image') as ltc:
|
161
|
+
image_id = await self._resolve_ci_base_image()
|
162
|
+
ltc.set_description(f'Resolve ci base image: {image_id}')
|
163
|
+
return image_id
|
187
164
|
|
188
|
-
|
165
|
+
#
|
189
166
|
|
190
|
-
|
167
|
+
@cached_nullary
|
168
|
+
def requirements_txts(self) -> ta.Sequence[str]:
|
169
|
+
return [
|
170
|
+
os.path.join(self._cfg.project_dir, rf)
|
171
|
+
for rf in check.not_none(self._cfg.requirements_txts)
|
172
|
+
]
|
191
173
|
|
192
174
|
@cached_nullary
|
193
|
-
def
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
175
|
+
def requirements_hash(self) -> str:
|
176
|
+
return build_requirements_hash(self.requirements_txts())[:self.KEY_HASH_LEN]
|
177
|
+
|
178
|
+
async def _resolve_ci_image(self) -> str:
|
179
|
+
async def build_and_tag(image_tag: str) -> str:
|
180
|
+
base_image = await self.resolve_ci_base_image()
|
181
|
+
|
182
|
+
setup_cmds = [
|
183
|
+
' '.join([
|
184
|
+
'pip install',
|
185
|
+
'--no-cache-dir',
|
186
|
+
'--root-user-action ignore',
|
187
|
+
'uv',
|
188
|
+
]),
|
189
|
+
' '.join([
|
190
|
+
'uv pip install',
|
191
|
+
'--no-cache',
|
192
|
+
'--index-strategy unsafe-best-match',
|
193
|
+
'--system',
|
194
|
+
*[f'-r /project/{rf}' for rf in self._cfg.requirements_txts or []],
|
195
|
+
]),
|
196
|
+
]
|
197
|
+
setup_cmd = ' && '.join(setup_cmds)
|
198
|
+
|
199
|
+
docker_file_lines = [
|
200
|
+
f'FROM {base_image}',
|
201
|
+
'RUN mkdir /project',
|
202
|
+
*[f'COPY {rf} /project/{rf}' for rf in self._cfg.requirements_txts or []],
|
203
|
+
f'RUN {setup_cmd}',
|
204
|
+
'RUN rm /project/*',
|
205
|
+
'WORKDIR /project',
|
206
|
+
]
|
207
|
+
|
208
|
+
with temp_file_context() as docker_file:
|
209
|
+
with open(docker_file, 'w') as f: # noqa
|
210
|
+
f.write('\n'.join(docker_file_lines))
|
211
|
+
|
212
|
+
return await build_docker_image(
|
213
|
+
docker_file,
|
214
|
+
tag=image_tag,
|
215
|
+
cwd=self._cfg.project_dir,
|
216
|
+
)
|
217
|
+
|
218
|
+
cache_key = f'ci-{self.docker_file_hash()}-{self.requirements_hash()}'
|
219
|
+
|
220
|
+
return await self._resolve_docker_image(cache_key, build_and_tag)
|
221
|
+
|
222
|
+
@async_cached_nullary
|
223
|
+
async def resolve_ci_image(self) -> str:
|
224
|
+
with log_timing_context('Resolve ci image') as ltc:
|
225
|
+
image_id = await self._resolve_ci_image()
|
226
|
+
ltc.set_description(f'Resolve ci image: {image_id}')
|
227
|
+
return image_id
|
198
228
|
|
199
229
|
#
|
200
230
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
),
|
208
|
-
]
|
209
|
-
|
210
|
-
#
|
231
|
+
@async_cached_nullary
|
232
|
+
async def load_dependencies(self) -> None:
|
233
|
+
deps = get_compose_service_dependencies(
|
234
|
+
self._cfg.compose_file,
|
235
|
+
self._cfg.service,
|
236
|
+
)
|
211
237
|
|
212
|
-
|
213
|
-
|
214
|
-
f'({self._cfg.cmd.s})',
|
215
|
-
]))
|
238
|
+
for dep_image in deps.values():
|
239
|
+
await self.load_docker_image(dep_image)
|
216
240
|
|
217
|
-
|
241
|
+
#
|
218
242
|
|
219
|
-
|
243
|
+
async def _run_compose_(self) -> None:
|
244
|
+
async with DockerComposeRun(DockerComposeRun.Config(
|
220
245
|
compose_file=self._cfg.compose_file,
|
221
246
|
service=self._cfg.service,
|
222
247
|
|
223
|
-
image=self.resolve_ci_image(),
|
248
|
+
image=await self.resolve_ci_image(),
|
224
249
|
|
225
|
-
cmd=
|
250
|
+
cmd=self._cfg.cmd,
|
226
251
|
|
227
252
|
run_options=[
|
228
253
|
'-v', f'{os.path.abspath(self._cfg.project_dir)}:/project',
|
229
|
-
|
254
|
+
*(self._cfg.run_options or []),
|
230
255
|
],
|
231
256
|
|
232
257
|
cwd=self._cfg.project_dir,
|
258
|
+
|
259
|
+
no_dependencies=self._cfg.no_dependencies,
|
233
260
|
)) as ci_compose_run:
|
234
|
-
ci_compose_run.run()
|
261
|
+
await ci_compose_run.run()
|
235
262
|
|
236
|
-
def _run_compose(self) -> None:
|
263
|
+
async def _run_compose(self) -> None:
|
237
264
|
with log_timing_context('Run compose'):
|
238
|
-
self._run_compose_()
|
265
|
+
await self._run_compose_()
|
239
266
|
|
240
267
|
#
|
241
268
|
|
242
|
-
def run(self) -> None:
|
243
|
-
self.
|
244
|
-
|
245
|
-
self.resolve_ci_image()
|
269
|
+
async def run(self) -> None:
|
270
|
+
await self.resolve_ci_image()
|
246
271
|
|
247
|
-
self.
|
272
|
+
await self.load_dependencies()
|
248
273
|
|
249
|
-
self._run_compose()
|
274
|
+
await self._run_compose()
|
omdev/ci/cli.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# @omlish-amalg ../scripts/ci.py
|
2
2
|
# ruff: noqa: UP006 UP007
|
3
|
-
# @omlish-lite
|
4
3
|
"""
|
5
4
|
Inputs:
|
6
5
|
- requirements.txt
|
@@ -9,9 +8,11 @@ Inputs:
|
|
9
8
|
|
10
9
|
==
|
11
10
|
|
12
|
-
./python -m ci run --cache-dir ci/cache ci/project omlish-ci
|
11
|
+
./python -m omdev.ci run --cache-dir omdev/ci/tests/cache omdev/ci/tests/project omlish-ci
|
13
12
|
"""
|
13
|
+
import argparse
|
14
14
|
import asyncio
|
15
|
+
import itertools
|
15
16
|
import os.path
|
16
17
|
import sys
|
17
18
|
import typing as ta
|
@@ -20,15 +21,15 @@ from omlish.argparse.cli import ArgparseCli
|
|
20
21
|
from omlish.argparse.cli import argparse_arg
|
21
22
|
from omlish.argparse.cli import argparse_cmd
|
22
23
|
from omlish.lite.check import check
|
24
|
+
from omlish.lite.logs import log
|
23
25
|
from omlish.logs.standard import configure_standard_logging
|
24
26
|
|
25
27
|
from .cache import DirectoryFileCache
|
26
|
-
from .cache import DirectoryShellCache
|
27
28
|
from .cache import FileCache
|
28
|
-
from .cache import ShellCache
|
29
29
|
from .ci import Ci
|
30
30
|
from .compose import get_compose_service_dependencies
|
31
|
-
from .github.
|
31
|
+
from .github.bootstrap import is_in_github_actions
|
32
|
+
from .github.cache import GithubFileCache
|
32
33
|
from .github.cli import GithubCli
|
33
34
|
from .requirements import build_requirements_hash
|
34
35
|
from .shell import ShellCmd
|
@@ -65,8 +66,8 @@ class CiCli(ArgparseCli):
|
|
65
66
|
@argparse_cmd(
|
66
67
|
accepts_unknown=True,
|
67
68
|
)
|
68
|
-
def github(self) -> ta.Optional[int]:
|
69
|
-
return GithubCli(self.unknown_args).
|
69
|
+
async def github(self) -> ta.Optional[int]:
|
70
|
+
return await GithubCli(self.unknown_args).async_cli_run()
|
70
71
|
|
71
72
|
#
|
72
73
|
|
@@ -76,18 +77,33 @@ class CiCli(ArgparseCli):
|
|
76
77
|
argparse_arg('--docker-file'),
|
77
78
|
argparse_arg('--compose-file'),
|
78
79
|
argparse_arg('-r', '--requirements-txt', action='append'),
|
79
|
-
|
80
|
+
|
80
81
|
argparse_arg('--cache-dir'),
|
82
|
+
|
83
|
+
argparse_arg('--github', action='store_true'),
|
84
|
+
argparse_arg('--github-detect', action='store_true'),
|
85
|
+
|
81
86
|
argparse_arg('--always-pull', action='store_true'),
|
87
|
+
argparse_arg('--always-build', action='store_true'),
|
88
|
+
|
89
|
+
argparse_arg('--no-dependencies', action='store_true'),
|
90
|
+
|
91
|
+
argparse_arg('-e', '--env', action='append'),
|
92
|
+
argparse_arg('-v', '--volume', action='append'),
|
93
|
+
|
94
|
+
argparse_arg('cmd', nargs=argparse.REMAINDER),
|
82
95
|
)
|
83
96
|
async def run(self) -> None:
|
84
97
|
project_dir = self.args.project_dir
|
85
98
|
docker_file = self.args.docker_file
|
86
99
|
compose_file = self.args.compose_file
|
87
|
-
service = self.args.service
|
88
100
|
requirements_txts = self.args.requirements_txt
|
89
101
|
cache_dir = self.args.cache_dir
|
90
|
-
|
102
|
+
|
103
|
+
#
|
104
|
+
|
105
|
+
cmd = ' '.join(self.args.cmd)
|
106
|
+
check.non_empty_str(cmd)
|
91
107
|
|
92
108
|
#
|
93
109
|
|
@@ -99,6 +115,7 @@ class CiCli(ArgparseCli):
|
|
99
115
|
for alt in alts:
|
100
116
|
alt_file = os.path.abspath(os.path.join(project_dir, alt))
|
101
117
|
if os.path.isfile(alt_file):
|
118
|
+
log.debug('Using %s', alt_file)
|
102
119
|
return alt_file
|
103
120
|
return None
|
104
121
|
|
@@ -132,6 +149,7 @@ class CiCli(ArgparseCli):
|
|
132
149
|
'requirements-ci.txt',
|
133
150
|
]:
|
134
151
|
if os.path.exists(os.path.join(project_dir, rf)):
|
152
|
+
log.debug('Using %s', rf)
|
135
153
|
requirements_txts.append(rf)
|
136
154
|
else:
|
137
155
|
for rf in requirements_txts:
|
@@ -139,46 +157,60 @@ class CiCli(ArgparseCli):
|
|
139
157
|
|
140
158
|
#
|
141
159
|
|
142
|
-
|
160
|
+
github = self.args.github
|
161
|
+
if not github and self.args.github_detect:
|
162
|
+
github = is_in_github_actions()
|
163
|
+
if github:
|
164
|
+
log.debug('Github detected')
|
165
|
+
|
166
|
+
#
|
167
|
+
|
143
168
|
file_cache: ta.Optional[FileCache] = None
|
144
169
|
if cache_dir is not None:
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
170
|
+
cache_dir = os.path.abspath(cache_dir)
|
171
|
+
log.debug('Using cache dir %s', cache_dir)
|
172
|
+
if github:
|
173
|
+
file_cache = GithubFileCache(cache_dir)
|
174
|
+
else:
|
175
|
+
file_cache = DirectoryFileCache(cache_dir)
|
150
176
|
|
151
|
-
|
177
|
+
#
|
152
178
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
179
|
+
run_options: ta.List[str] = []
|
180
|
+
for run_arg, run_arg_vals in [
|
181
|
+
('-e', self.args.env or []),
|
182
|
+
('-v', self.args.volume or []),
|
183
|
+
]:
|
184
|
+
run_options.extend(itertools.chain.from_iterable(
|
185
|
+
[run_arg, run_arg_val]
|
186
|
+
for run_arg_val in run_arg_vals
|
187
|
+
))
|
157
188
|
|
158
189
|
#
|
159
190
|
|
160
|
-
with Ci(
|
191
|
+
async with Ci(
|
161
192
|
Ci.Config(
|
162
193
|
project_dir=project_dir,
|
163
194
|
|
164
195
|
docker_file=docker_file,
|
165
196
|
|
166
197
|
compose_file=compose_file,
|
167
|
-
service=service,
|
198
|
+
service=self.args.service,
|
168
199
|
|
169
200
|
requirements_txts=requirements_txts,
|
170
201
|
|
171
|
-
cmd=ShellCmd(
|
172
|
-
|
173
|
-
|
174
|
-
|
202
|
+
cmd=ShellCmd(cmd),
|
203
|
+
|
204
|
+
always_pull=self.args.always_pull,
|
205
|
+
always_build=self.args.always_build,
|
206
|
+
|
207
|
+
no_dependencies=self.args.no_dependencies,
|
175
208
|
|
176
|
-
|
209
|
+
run_options=run_options,
|
177
210
|
),
|
178
211
|
file_cache=file_cache,
|
179
|
-
shell_cache=shell_cache,
|
180
212
|
) as ci:
|
181
|
-
ci.run()
|
213
|
+
await ci.run()
|
182
214
|
|
183
215
|
|
184
216
|
async def _async_main() -> ta.Optional[int]:
|