dycw-utilities 0.174.15__py3-none-any.whl → 0.174.17__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.
- {dycw_utilities-0.174.15.dist-info → dycw_utilities-0.174.17.dist-info}/METADATA +1 -1
- {dycw_utilities-0.174.15.dist-info → dycw_utilities-0.174.17.dist-info}/RECORD +12 -12
- {dycw_utilities-0.174.15.dist-info → dycw_utilities-0.174.17.dist-info}/WHEEL +1 -1
- utilities/__init__.py +1 -1
- utilities/click.py +1 -2
- utilities/docker.py +1 -1
- utilities/functions.py +1 -1
- utilities/hypothesis.py +1 -1
- utilities/pathlib.py +1 -1
- utilities/platform.py +1 -1
- utilities/subprocess.py +146 -14
- {dycw_utilities-0.174.15.dist-info → dycw_utilities-0.174.17.dist-info}/entry_points.txt +0 -0
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
utilities/__init__.py,sha256=
|
|
1
|
+
utilities/__init__.py,sha256=kcADuh_nb8xfuYrat4AkfaKqdxp3l7xyrXWoJJ5JZLk,61
|
|
2
2
|
utilities/aeventkit.py,sha256=OmDBhYGgbsKrB7cdC5FFpJHUatX9O76eTeKVVTksp2Y,12673
|
|
3
3
|
utilities/altair.py,sha256=rUK99g9x6CYDDfiZrf-aTx5fSRbL1Q8ctgKORowzXHg,9060
|
|
4
4
|
utilities/asyncio.py,sha256=aJySVxBY0gqsIYnoNmH7-1r8djKuf4vSsU69VCD08t8,16772
|
|
5
5
|
utilities/atomicwrites.py,sha256=tPo6r-Rypd9u99u66B9z86YBPpnLrlHtwox_8Z7T34Y,5790
|
|
6
6
|
utilities/atools.py,sha256=6neeCcgXxK2dlsc0xp15Za7nSucbCgFtAJepGI_-WXU,2549
|
|
7
7
|
utilities/cachetools.py,sha256=2S9LMHIunDYMIu8JGI7OLN04sQ7-xZGdEdP1Li0vksA,2775
|
|
8
|
-
utilities/click.py,sha256
|
|
8
|
+
utilities/click.py,sha256=ScLzBLoBp8Si5YjgB18A0IVMAR-r4sGUnVfJbAaru98,19191
|
|
9
9
|
utilities/concurrent.py,sha256=fHeW2SZ_TEMfFY0C8pyQI6aPlnecvx9x6SuUwBWj_JY,2853
|
|
10
10
|
utilities/contextlib.py,sha256=iP7R2tIm6ZsbfLD5ks6UKBYwj50e9gBI8AkpLN-chro,7476
|
|
11
11
|
utilities/contextvars.py,sha256=J8OhC7jqozAGYOCe2KUWysbPXNGe5JYz3HfaY_mIs08,883
|
|
12
12
|
utilities/cryptography.py,sha256=5PFrzsNUGHay91dFgYnDKwYprXxahrBqztmUqViRzBk,956
|
|
13
13
|
utilities/cvxpy.py,sha256=Rv1-fD-XYerosCavRF8Pohop2DBkU3AlFaGTfD8AEAA,13776
|
|
14
14
|
utilities/dataclasses.py,sha256=xbU3QN1GFy7RC6hIJRZIeUZm7YRlodrgEWmahWG6k2g,32465
|
|
15
|
-
utilities/docker.py,sha256=
|
|
15
|
+
utilities/docker.py,sha256=l_R9Eyhc-_JbkkaYXYKGZ0PZ_oukrSj8aKtD1NyAhMM,7879
|
|
16
16
|
utilities/enum.py,sha256=5l6pwZD1cjSlVW4ss-zBPspWvrbrYrdtJWcg6f5_J5w,5781
|
|
17
17
|
utilities/errors.py,sha256=mFlDGSM0LI1jZ1pbqwLAH3ttLZ2JVIxyZLojw8tGVZU,1479
|
|
18
18
|
utilities/fastapi.py,sha256=TqyKvBjiMS594sXPjrz-KRTLMb3l3D3rZ1zAYV7GfOk,1454
|
|
19
19
|
utilities/fpdf2.py,sha256=dSiYz0FJTD2sQuxpxqFWwwIe2-p6Y7oTB9Tv0Jajit0,1866
|
|
20
|
-
utilities/functions.py,sha256=
|
|
20
|
+
utilities/functions.py,sha256=18Zda7nTloARdcEudH8YJ4e13xAdWShAGhPNN4w2Gyc,21498
|
|
21
21
|
utilities/functools.py,sha256=I00ru2gQPakZw2SHVeKIKXfTv741655s6HI0lUoE0D4,1552
|
|
22
22
|
utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
|
|
23
23
|
utilities/git.py,sha256=U1RFvCTANGENgx9wVBDvllioqBQZM2ns12ivKhOsaO4,414
|
|
@@ -25,7 +25,7 @@ utilities/grp.py,sha256=1vV3gNR9dQsl1vtUtvC_2qgVdQzm7O8lLMSh56cTbeg,694
|
|
|
25
25
|
utilities/gzip.py,sha256=fkGP3KdsBfXlstodT4wtlp-PwNyUsogpbDCVVVGdsm4,781
|
|
26
26
|
utilities/hashlib.py,sha256=SVTgtguur0P4elppvzOBbLEjVM3Pea0eWB61yg2ilxo,309
|
|
27
27
|
utilities/http.py,sha256=TsavEfHlRtlLaeV21Z6KZh0qbPw-kvD1zsQdZ7Kep5Q,977
|
|
28
|
-
utilities/hypothesis.py,sha256=
|
|
28
|
+
utilities/hypothesis.py,sha256=NUu30pl5kjL3tzo-m8SMRwTqLAmTWK-_Sau2NemJcQo,46773
|
|
29
29
|
utilities/importlib.py,sha256=mV1xT_O_zt_GnZZ36tl3xOmMaN_3jErDWY54fX39F6Y,429
|
|
30
30
|
utilities/inflect.py,sha256=v7YkOWSu8NAmVghPcf4F3YBZQoJCS47_DLf9jbfWIs0,581
|
|
31
31
|
utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
|
|
@@ -46,10 +46,10 @@ utilities/optuna.py,sha256=C-fhWYiXHVPo1l8QctYkFJ4DyhbSrGorzP1dJb_qvd8,1933
|
|
|
46
46
|
utilities/orjson.py,sha256=T_0SlK811ysg46d3orvIPY3JpBa4FRMpP2wlPQo7-gU,41854
|
|
47
47
|
utilities/os.py,sha256=kjKKSQfnRqFTTZ315iavaaGd3gGuYNoSWlxVLCJjyQs,4852
|
|
48
48
|
utilities/parse.py,sha256=g7Qm9eBOIeDId2tGA021CIaeF6jp1TI8rx4srdvlyoo,17937
|
|
49
|
-
utilities/pathlib.py,sha256=
|
|
49
|
+
utilities/pathlib.py,sha256=N4Ip8R9eCM-6GfvxUJ3T9oQIle2C2P52F-13BCFRdTg,9345
|
|
50
50
|
utilities/permissions.py,sha256=vLXlWztSVYffbrxptne7ksj6dU1HLekm4fEvS4ny_4Q,8944
|
|
51
51
|
utilities/pickle.py,sha256=MBT2xZCsv0pH868IXLGKnlcqNx2IRVKYNpRcqiQQqxw,653
|
|
52
|
-
utilities/platform.py,sha256=
|
|
52
|
+
utilities/platform.py,sha256=Grov52WxNOViJEZyRcm-b2m_Dp1T0waPjDCusR_9oqs,2791
|
|
53
53
|
utilities/polars.py,sha256=cNFBLWgOMUAp_Sz4xtlto17uZswZRrcfQYC95QKyaY4,87483
|
|
54
54
|
utilities/polars_ols.py,sha256=LNTFNLPuYW7fcAHymlbnams_DhitToblYvib3mhKbwI,5615
|
|
55
55
|
utilities/postgres.py,sha256=g3tEwTI8TdmiCbRME61ffQ0xaibdpXPu8mJOOHvjPKc,12532
|
|
@@ -81,7 +81,7 @@ utilities/sqlalchemy.py,sha256=HQYpd7LFxdTF5WYVWYtCJeEBI71EJm7ytvCGyAH9B-U,37163
|
|
|
81
81
|
utilities/sqlalchemy_polars.py,sha256=JCGhB37raSR7fqeWV5dTsciRTMVzIdVT9YSqKT0piT0,13370
|
|
82
82
|
utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
|
|
83
83
|
utilities/string.py,sha256=shmBK87zZwzGyixuNuXCiUbqzfeZ9xlrFwz6JTaRvDk,582
|
|
84
|
-
utilities/subprocess.py,sha256=
|
|
84
|
+
utilities/subprocess.py,sha256=FzVd1evvhaJR2U_tATJ37Y6YjF8O61XPeqYo8NLonG4,33123
|
|
85
85
|
utilities/tempfile.py,sha256=Lx6qa16lL1XVH6WdmD_G9vlN6gLI8nrIurxmsFkPKvg,3022
|
|
86
86
|
utilities/testbook.py,sha256=j1KmaVbrX9VrbeMgtPh5gk55myAsn3dyRUn7jGbPbRk,1294
|
|
87
87
|
utilities/text.py,sha256=7SvwcSR2l_5cOrm1samGnR4C-ZI6qyFLHLzSpO1zeHQ,13958
|
|
@@ -98,7 +98,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
|
|
98
98
|
utilities/whenever.py,sha256=F4ek0-OBWxHYrZdmoZt76N2RnNyKY5KrEHt7rqO4AQE,60183
|
|
99
99
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
|
100
100
|
utilities/zoneinfo.py,sha256=tdIScrTB2-B-LH0ukb1HUXKooLknOfJNwHk10MuMYvA,3619
|
|
101
|
-
dycw_utilities-0.174.
|
|
102
|
-
dycw_utilities-0.174.
|
|
103
|
-
dycw_utilities-0.174.
|
|
104
|
-
dycw_utilities-0.174.
|
|
101
|
+
dycw_utilities-0.174.17.dist-info/WHEEL,sha256=RRVLqVugUmFOqBedBFAmA4bsgFcROUBiSUKlERi0Hcg,79
|
|
102
|
+
dycw_utilities-0.174.17.dist-info/entry_points.txt,sha256=ykGI1ArwOPHqm2g5Cqh3ENdMxEej_a_FcOUov5EM5Oc,155
|
|
103
|
+
dycw_utilities-0.174.17.dist-info/METADATA,sha256=vF_qKrCXt5r90r7OjWFLitGHfDgcAcVUDj6Y47YMvEQ,1710
|
|
104
|
+
dycw_utilities-0.174.17.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/click.py
CHANGED
|
@@ -210,8 +210,7 @@ class EnumPartial[E: enum.Enum](ParamType):
|
|
|
210
210
|
self.fail(str(error), param, ctx)
|
|
211
211
|
if enum in self._members:
|
|
212
212
|
return enum
|
|
213
|
-
self.fail(f"{enum.value!r} is not a selected member")
|
|
214
|
-
return None
|
|
213
|
+
return self.fail(f"{enum.value!r} is not a selected member")
|
|
215
214
|
|
|
216
215
|
@override
|
|
217
216
|
def get_metavar(self, param: Parameter, ctx: Context) -> str | None:
|
utilities/docker.py
CHANGED
|
@@ -47,7 +47,7 @@ def docker_cp(
|
|
|
47
47
|
sudo: bool = False,
|
|
48
48
|
logger: LoggerLike | None = None,
|
|
49
49
|
) -> None:
|
|
50
|
-
match src, dest:
|
|
50
|
+
match src, dest: # skipif-ci
|
|
51
51
|
case Path() | str(), (str() as cont, Path() | str() as dest_path):
|
|
52
52
|
docker_exec(
|
|
53
53
|
cont, *maybe_sudo_cmd(*mkdir_cmd(dest_path, parent=True), sudo=sudo)
|
utilities/functions.py
CHANGED
|
@@ -693,7 +693,7 @@ def second[U](pair: tuple[Any, U], /) -> U:
|
|
|
693
693
|
|
|
694
694
|
def skip_if_optimize[**P](func: Callable[P, None], /) -> Callable[P, None]:
|
|
695
695
|
"""Skip a function if we are in the optimized mode."""
|
|
696
|
-
if __debug__:
|
|
696
|
+
if __debug__: # pragma: no cover
|
|
697
697
|
return func
|
|
698
698
|
|
|
699
699
|
@wraps(func)
|
utilities/hypothesis.py
CHANGED
|
@@ -1040,7 +1040,7 @@ def setup_hypothesis_profiles(
|
|
|
1040
1040
|
assert_never(never)
|
|
1041
1041
|
|
|
1042
1042
|
phases = {Phase.explicit, Phase.reuse, Phase.generate, Phase.target}
|
|
1043
|
-
if "HYPOTHESIS_NO_SHRINK" not in environ:
|
|
1043
|
+
if "HYPOTHESIS_NO_SHRINK" not in environ: # pragma: no cover
|
|
1044
1044
|
phases.add(Phase.shrink)
|
|
1045
1045
|
for profile in Profile:
|
|
1046
1046
|
try:
|
utilities/pathlib.py
CHANGED
|
@@ -127,7 +127,7 @@ class GetRepoRootError(Exception): ...
|
|
|
127
127
|
class _GetRepoRootGitNotFoundError(GetRepoRootError):
|
|
128
128
|
@override
|
|
129
129
|
def __str__(self) -> str:
|
|
130
|
-
return "'git' not found"
|
|
130
|
+
return "'git' not found" # pragma: no cover
|
|
131
131
|
|
|
132
132
|
|
|
133
133
|
@dataclass(kw_only=True, slots=True)
|
utilities/platform.py
CHANGED
|
@@ -16,7 +16,7 @@ System = Literal["windows", "mac", "linux"]
|
|
|
16
16
|
def get_system() -> System:
|
|
17
17
|
"""Get the system/OS name."""
|
|
18
18
|
sys = system()
|
|
19
|
-
if sys == "Windows":
|
|
19
|
+
if sys == "Windows": # skipif-ci
|
|
20
20
|
return "windows"
|
|
21
21
|
if sys == "Darwin": # skipif-not-macos
|
|
22
22
|
return "mac"
|
utilities/subprocess.py
CHANGED
|
@@ -17,7 +17,8 @@ from typing import IO, TYPE_CHECKING, Literal, assert_never, overload, override
|
|
|
17
17
|
from utilities.errors import ImpossibleCaseError
|
|
18
18
|
from utilities.iterables import always_iterable
|
|
19
19
|
from utilities.logging import to_logger
|
|
20
|
-
from utilities.permissions import ensure_perms
|
|
20
|
+
from utilities.permissions import Permissions, ensure_perms
|
|
21
|
+
from utilities.tempfile import TemporaryDirectory
|
|
21
22
|
from utilities.text import strip_and_dedent
|
|
22
23
|
from utilities.whenever import to_seconds
|
|
23
24
|
|
|
@@ -164,7 +165,7 @@ def cp(
|
|
|
164
165
|
) -> None:
|
|
165
166
|
"""Copy a file/directory."""
|
|
166
167
|
mkdir(dest, sudo=sudo, parent=True)
|
|
167
|
-
if sudo:
|
|
168
|
+
if sudo: # pragma: no cover
|
|
168
169
|
run(*sudo_cmd(*cp_cmd(src, dest)))
|
|
169
170
|
else:
|
|
170
171
|
src, dest = map(Path, [src, dest])
|
|
@@ -277,7 +278,7 @@ def mv(
|
|
|
277
278
|
) -> None:
|
|
278
279
|
"""Move a file/directory."""
|
|
279
280
|
mkdir(dest, sudo=sudo, parent=True)
|
|
280
|
-
if sudo:
|
|
281
|
+
if sudo: # pragma: no cover
|
|
281
282
|
run(*sudo_cmd(*cp_cmd(src, dest)))
|
|
282
283
|
else:
|
|
283
284
|
src, dest = map(Path, [src, dest])
|
|
@@ -346,7 +347,7 @@ def rsync(
|
|
|
346
347
|
chown_user: str | None = None,
|
|
347
348
|
chown_group: str | None = None,
|
|
348
349
|
exclude: MaybeIterable[str] | None = None,
|
|
349
|
-
chmod:
|
|
350
|
+
chmod: PermissionsLike | None = None,
|
|
350
351
|
) -> None:
|
|
351
352
|
"""Remote & local file copying."""
|
|
352
353
|
mkdir_args = maybe_sudo_cmd(*mkdir_cmd(dest, parent=True), sudo=sudo) # skipif-ci
|
|
@@ -361,13 +362,13 @@ def rsync(
|
|
|
361
362
|
retry=retry,
|
|
362
363
|
logger=logger,
|
|
363
364
|
)
|
|
364
|
-
|
|
365
|
+
srcs = list(always_iterable(src_or_srcs)) # skipif-ci
|
|
365
366
|
rsync_args = rsync_cmd( # skipif-ci
|
|
366
|
-
|
|
367
|
+
srcs,
|
|
367
368
|
user,
|
|
368
369
|
hostname,
|
|
369
370
|
dest,
|
|
370
|
-
archive=is_dir,
|
|
371
|
+
archive=any(Path(s).is_dir() for s in srcs),
|
|
371
372
|
chown_user=chown_user,
|
|
372
373
|
chown_group=chown_group,
|
|
373
374
|
exclude=exclude,
|
|
@@ -375,7 +376,6 @@ def rsync(
|
|
|
375
376
|
host_key_algorithms=host_key_algorithms,
|
|
376
377
|
strict_host_key_checking=strict_host_key_checking,
|
|
377
378
|
sudo=sudo,
|
|
378
|
-
parent=is_dir,
|
|
379
379
|
)
|
|
380
380
|
run(*rsync_args, print=print, retry=retry, logger=logger) # skipif-ci
|
|
381
381
|
if chmod is not None: # skipif-ci
|
|
@@ -408,7 +408,6 @@ def rsync_cmd(
|
|
|
408
408
|
host_key_algorithms: list[str] = _HOST_KEY_ALGORITHMS,
|
|
409
409
|
strict_host_key_checking: bool = True,
|
|
410
410
|
sudo: bool = False,
|
|
411
|
-
parent: bool = False,
|
|
412
411
|
) -> list[str]:
|
|
413
412
|
"""Command to use 'rsync' to do remote & local file copying."""
|
|
414
413
|
args: list[str] = ["rsync"]
|
|
@@ -438,12 +437,141 @@ def rsync_cmd(
|
|
|
438
437
|
args.extend(["--rsh", join(rsh_args)])
|
|
439
438
|
if sudo:
|
|
440
439
|
args.extend(["--rsync-path", join(sudo_cmd("rsync"))])
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
440
|
+
srcs = list(always_iterable(src_or_srcs)) # do not Path()
|
|
441
|
+
if len(srcs) == 0:
|
|
442
|
+
raise RsyncCmdNoSourcesError(user=user, hostname=hostname, dest=dest)
|
|
443
|
+
missing = [s for s in srcs if not Path(s).exists()]
|
|
444
|
+
if len(missing) >= 1:
|
|
445
|
+
raise RsyncCmdSourcesNotFoundError(
|
|
446
|
+
sources=missing, user=user, hostname=hostname, dest=dest
|
|
447
|
+
)
|
|
448
|
+
return [*args, *map(str, srcs), f"{user}@{hostname}:{dest}"]
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
@dataclass(kw_only=True, slots=True)
|
|
452
|
+
class RsyncCmdError(Exception):
|
|
453
|
+
user: str
|
|
454
|
+
hostname: str
|
|
455
|
+
dest: PathLike
|
|
456
|
+
|
|
457
|
+
@override
|
|
458
|
+
def __str__(self) -> str:
|
|
459
|
+
return f"No sources selected to send to {self.user}@{self.hostname}:{self.dest}"
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
@dataclass(kw_only=True, slots=True)
|
|
463
|
+
class RsyncCmdNoSourcesError(RsyncCmdError):
|
|
464
|
+
@override
|
|
465
|
+
def __str__(self) -> str:
|
|
466
|
+
return f"No sources selected to send to {self.user}@{self.hostname}:{self.dest}"
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
@dataclass(kw_only=True, slots=True)
|
|
470
|
+
class RsyncCmdSourcesNotFoundError(RsyncCmdError):
|
|
471
|
+
sources: list[PathLike]
|
|
472
|
+
|
|
473
|
+
@override
|
|
474
|
+
def __str__(self) -> str:
|
|
475
|
+
desc = ", ".join(map(repr, map(str, self.sources)))
|
|
476
|
+
return f"Sources selected to send to {self.user}@{self.hostname}:{self.dest} but not found: {desc}"
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
##
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def rsync_many(
|
|
483
|
+
user: str,
|
|
484
|
+
hostname: str,
|
|
485
|
+
/,
|
|
486
|
+
*items: tuple[PathLike, PathLike]
|
|
487
|
+
| tuple[Literal["sudo"], PathLike, PathLike]
|
|
488
|
+
| tuple[PathLike, PathLike, PermissionsLike],
|
|
489
|
+
retry: Retry | None = None,
|
|
490
|
+
logger: LoggerLike | None = None,
|
|
491
|
+
keep: bool = False,
|
|
492
|
+
batch_mode: bool = True,
|
|
493
|
+
host_key_algorithms: list[str] = _HOST_KEY_ALGORITHMS,
|
|
494
|
+
strict_host_key_checking: bool = True,
|
|
495
|
+
print: bool = False, # noqa: A002
|
|
496
|
+
) -> None:
|
|
497
|
+
cmds: list[list[str]] = [] # skipif-ci
|
|
498
|
+
with ( # skipif-ci
|
|
499
|
+
TemporaryDirectory() as temp_src,
|
|
500
|
+
yield_ssh_temp_dir(
|
|
501
|
+
user, hostname, retry=retry, logger=logger, keep=keep
|
|
502
|
+
) as temp_dest,
|
|
503
|
+
):
|
|
504
|
+
for item in items:
|
|
505
|
+
match item:
|
|
506
|
+
case Path() | str() as src, Path() | str() as dest:
|
|
507
|
+
cmds.extend(_rsync_many_prepare(src, dest, temp_src, temp_dest))
|
|
508
|
+
case "sudo", Path() | str() as src, Path() | str() as dest:
|
|
509
|
+
cmds.extend(
|
|
510
|
+
_rsync_many_prepare(src, dest, temp_src, temp_dest, sudo=True)
|
|
511
|
+
)
|
|
512
|
+
case (
|
|
513
|
+
Path() | str() as src,
|
|
514
|
+
Path() | str() as dest,
|
|
515
|
+
Permissions() | int() | str() as perms,
|
|
516
|
+
):
|
|
517
|
+
cmds.extend(
|
|
518
|
+
_rsync_many_prepare(src, dest, temp_src, temp_dest, perms=perms)
|
|
519
|
+
)
|
|
520
|
+
case never:
|
|
521
|
+
assert_never(never)
|
|
522
|
+
rsync(
|
|
523
|
+
f"{temp_src}/",
|
|
524
|
+
user,
|
|
525
|
+
hostname,
|
|
526
|
+
temp_dest,
|
|
527
|
+
batch_mode=batch_mode,
|
|
528
|
+
host_key_algorithms=host_key_algorithms,
|
|
529
|
+
strict_host_key_checking=strict_host_key_checking,
|
|
530
|
+
print=print,
|
|
531
|
+
retry=retry,
|
|
532
|
+
logger=logger,
|
|
533
|
+
)
|
|
534
|
+
ssh(
|
|
535
|
+
user,
|
|
536
|
+
hostname,
|
|
537
|
+
*BASH_LS,
|
|
538
|
+
input="\n".join(map(join, cmds)),
|
|
539
|
+
print=print,
|
|
540
|
+
retry=retry,
|
|
541
|
+
logger=logger,
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
def _rsync_many_prepare(
|
|
546
|
+
src: PathLike,
|
|
547
|
+
dest: PathLike,
|
|
548
|
+
temp_src: PathLike,
|
|
549
|
+
temp_dest: PathLike,
|
|
550
|
+
/,
|
|
551
|
+
*,
|
|
552
|
+
sudo: bool = False,
|
|
553
|
+
perms: PermissionsLike | None = None,
|
|
554
|
+
) -> list[list[str]]:
|
|
555
|
+
dest, temp_src, temp_dest = map(Path, [dest, temp_src, temp_dest])
|
|
556
|
+
n = len(list(temp_src.iterdir()))
|
|
557
|
+
name = str(n)
|
|
558
|
+
match src:
|
|
559
|
+
case Path():
|
|
560
|
+
cp(src, temp_src / name)
|
|
561
|
+
case str():
|
|
562
|
+
if Path(src).exists():
|
|
563
|
+
cp(src, temp_src / name)
|
|
564
|
+
else:
|
|
565
|
+
tee(temp_src / name, src)
|
|
566
|
+
case never:
|
|
567
|
+
assert_never(never)
|
|
568
|
+
cmds: list[list[str]] = [
|
|
569
|
+
maybe_sudo_cmd(*mkdir_cmd(dest, parent=True), sudo=sudo),
|
|
570
|
+
maybe_sudo_cmd(*cp_cmd(temp_dest / name, dest), sudo=sudo),
|
|
446
571
|
]
|
|
572
|
+
if perms is not None:
|
|
573
|
+
cmds.append(maybe_sudo_cmd(*chmod_cmd(dest, perms), sudo=sudo))
|
|
574
|
+
return cmds
|
|
447
575
|
|
|
448
576
|
|
|
449
577
|
##
|
|
@@ -1019,6 +1147,9 @@ __all__ = [
|
|
|
1019
1147
|
"ChownCmdError",
|
|
1020
1148
|
"CpError",
|
|
1021
1149
|
"MvFileError",
|
|
1150
|
+
"RsyncCmdError",
|
|
1151
|
+
"RsyncCmdNoSourcesError",
|
|
1152
|
+
"RsyncCmdSourcesNotFoundError",
|
|
1022
1153
|
"apt_install_cmd",
|
|
1023
1154
|
"cd_cmd",
|
|
1024
1155
|
"chmod",
|
|
@@ -1041,6 +1172,7 @@ __all__ = [
|
|
|
1041
1172
|
"rm_cmd",
|
|
1042
1173
|
"rsync",
|
|
1043
1174
|
"rsync_cmd",
|
|
1175
|
+
"rsync_many",
|
|
1044
1176
|
"run",
|
|
1045
1177
|
"set_hostname_cmd",
|
|
1046
1178
|
"ssh",
|
|
File without changes
|