dycw-utilities 0.174.6__py3-none-any.whl → 0.174.8__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.6.dist-info → dycw_utilities-0.174.8.dist-info}/METADATA +1 -1
- {dycw_utilities-0.174.6.dist-info → dycw_utilities-0.174.8.dist-info}/RECORD +6 -6
- utilities/__init__.py +1 -1
- utilities/subprocess.py +244 -10
- {dycw_utilities-0.174.6.dist-info → dycw_utilities-0.174.8.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.174.6.dist-info → dycw_utilities-0.174.8.dist-info}/entry_points.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
utilities/__init__.py,sha256=
|
|
1
|
+
utilities/__init__.py,sha256=n95VfhS7rnwwdfXlNQHT0VSWZoAJAyyrDnWLplcWMZ8,60
|
|
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
|
|
@@ -80,7 +80,7 @@ utilities/sqlalchemy.py,sha256=HQYpd7LFxdTF5WYVWYtCJeEBI71EJm7ytvCGyAH9B-U,37163
|
|
|
80
80
|
utilities/sqlalchemy_polars.py,sha256=JCGhB37raSR7fqeWV5dTsciRTMVzIdVT9YSqKT0piT0,13370
|
|
81
81
|
utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
|
|
82
82
|
utilities/string.py,sha256=shmBK87zZwzGyixuNuXCiUbqzfeZ9xlrFwz6JTaRvDk,582
|
|
83
|
-
utilities/subprocess.py,sha256=
|
|
83
|
+
utilities/subprocess.py,sha256=dIBguvLB0WepJKqgBxlzF6r8z9HW5JiGKLg-eslpuec,22549
|
|
84
84
|
utilities/tempfile.py,sha256=Lx6qa16lL1XVH6WdmD_G9vlN6gLI8nrIurxmsFkPKvg,3022
|
|
85
85
|
utilities/testbook.py,sha256=j1KmaVbrX9VrbeMgtPh5gk55myAsn3dyRUn7jGbPbRk,1294
|
|
86
86
|
utilities/text.py,sha256=7SvwcSR2l_5cOrm1samGnR4C-ZI6qyFLHLzSpO1zeHQ,13958
|
|
@@ -97,7 +97,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
|
|
97
97
|
utilities/whenever.py,sha256=F4ek0-OBWxHYrZdmoZt76N2RnNyKY5KrEHt7rqO4AQE,60183
|
|
98
98
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
|
99
99
|
utilities/zoneinfo.py,sha256=tdIScrTB2-B-LH0ukb1HUXKooLknOfJNwHk10MuMYvA,3619
|
|
100
|
-
dycw_utilities-0.174.
|
|
101
|
-
dycw_utilities-0.174.
|
|
102
|
-
dycw_utilities-0.174.
|
|
103
|
-
dycw_utilities-0.174.
|
|
100
|
+
dycw_utilities-0.174.8.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
|
|
101
|
+
dycw_utilities-0.174.8.dist-info/entry_points.txt,sha256=ykGI1ArwOPHqm2g5Cqh3ENdMxEej_a_FcOUov5EM5Oc,155
|
|
102
|
+
dycw_utilities-0.174.8.dist-info/METADATA,sha256=Y6jmazzTFERRUb55Cbl5cwt3sCw5yThYY7Rrcn1llw0,1709
|
|
103
|
+
dycw_utilities-0.174.8.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/subprocess.py
CHANGED
|
@@ -5,6 +5,7 @@ from contextlib import contextmanager
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from io import StringIO
|
|
7
7
|
from pathlib import Path
|
|
8
|
+
from shlex import join
|
|
8
9
|
from string import Template
|
|
9
10
|
from subprocess import PIPE, CalledProcessError, Popen
|
|
10
11
|
from threading import Thread
|
|
@@ -12,6 +13,7 @@ from time import sleep
|
|
|
12
13
|
from typing import IO, TYPE_CHECKING, Literal, assert_never, overload, override
|
|
13
14
|
|
|
14
15
|
from utilities.errors import ImpossibleCaseError
|
|
16
|
+
from utilities.iterables import always_iterable
|
|
15
17
|
from utilities.logging import to_logger
|
|
16
18
|
from utilities.text import strip_and_dedent
|
|
17
19
|
from utilities.whenever import to_seconds
|
|
@@ -19,7 +21,14 @@ from utilities.whenever import to_seconds
|
|
|
19
21
|
if TYPE_CHECKING:
|
|
20
22
|
from collections.abc import Iterator
|
|
21
23
|
|
|
22
|
-
from utilities.types import
|
|
24
|
+
from utilities.types import (
|
|
25
|
+
LoggerLike,
|
|
26
|
+
MaybeIterable,
|
|
27
|
+
PathLike,
|
|
28
|
+
Retry,
|
|
29
|
+
StrMapping,
|
|
30
|
+
StrStrMapping,
|
|
31
|
+
)
|
|
23
32
|
|
|
24
33
|
|
|
25
34
|
_HOST_KEY_ALGORITHMS = ["ssh-ed25519"]
|
|
@@ -31,22 +40,37 @@ RESTART_SSHD = ["systemctl", "restart", "sshd"]
|
|
|
31
40
|
UPDATE_CA_CERTIFICATES: str = "update-ca-certificates"
|
|
32
41
|
|
|
33
42
|
|
|
43
|
+
##
|
|
44
|
+
|
|
45
|
+
|
|
34
46
|
def apt_install_cmd(package: str, /) -> list[str]:
|
|
35
47
|
return ["apt", "install", "-y", package]
|
|
36
48
|
|
|
37
49
|
|
|
50
|
+
##
|
|
51
|
+
|
|
52
|
+
|
|
38
53
|
def cat_cmd(path: PathLike, /) -> list[str]:
|
|
39
54
|
return ["cat", str(path)]
|
|
40
55
|
|
|
41
56
|
|
|
57
|
+
##
|
|
58
|
+
|
|
59
|
+
|
|
42
60
|
def cd_cmd(path: PathLike, /) -> list[str]:
|
|
43
61
|
return ["cd", str(path)]
|
|
44
62
|
|
|
45
63
|
|
|
64
|
+
##
|
|
65
|
+
|
|
66
|
+
|
|
46
67
|
def chmod_cmd(path: PathLike, mode: str, /) -> list[str]:
|
|
47
68
|
return ["chmod", mode, str(path)]
|
|
48
69
|
|
|
49
70
|
|
|
71
|
+
##
|
|
72
|
+
|
|
73
|
+
|
|
50
74
|
def chown_cmd(
|
|
51
75
|
path: PathLike, /, *, user: str | None = None, group: str | None = None
|
|
52
76
|
) -> list[str]:
|
|
@@ -71,14 +95,23 @@ class ChownCmdError(Exception):
|
|
|
71
95
|
return "At least one of 'user' and/or 'group' must be given; got None"
|
|
72
96
|
|
|
73
97
|
|
|
98
|
+
##
|
|
99
|
+
|
|
100
|
+
|
|
74
101
|
def cp_cmd(src: PathLike, dest: PathLike, /) -> list[str]:
|
|
75
102
|
return ["cp", "-r", str(src), str(dest)]
|
|
76
103
|
|
|
77
104
|
|
|
105
|
+
##
|
|
106
|
+
|
|
107
|
+
|
|
78
108
|
def echo_cmd(text: str, /) -> list[str]:
|
|
79
109
|
return ["echo", text]
|
|
80
110
|
|
|
81
111
|
|
|
112
|
+
##
|
|
113
|
+
|
|
114
|
+
|
|
82
115
|
def expand_path(
|
|
83
116
|
path: PathLike, /, *, subs: StrMapping | None = None, sudo: bool = False
|
|
84
117
|
) -> Path:
|
|
@@ -89,42 +122,192 @@ def expand_path(
|
|
|
89
122
|
return Path(path).expanduser()
|
|
90
123
|
|
|
91
124
|
|
|
125
|
+
##
|
|
126
|
+
|
|
127
|
+
|
|
92
128
|
def git_clone_cmd(url: str, path: PathLike, /) -> list[str]:
|
|
93
129
|
return ["git", "clone", "--recurse-submodules", url, str(path)]
|
|
94
130
|
|
|
95
131
|
|
|
132
|
+
##
|
|
133
|
+
|
|
134
|
+
|
|
96
135
|
def git_hard_reset_cmd(*, branch: str | None = None) -> list[str]:
|
|
97
136
|
branch_use = "master" if branch is None else branch
|
|
98
137
|
return ["git", "hard-reset", branch_use]
|
|
99
138
|
|
|
100
139
|
|
|
140
|
+
##
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def maybe_parent(path: PathLike, /, *, parent: bool = False) -> Path:
|
|
144
|
+
path = Path(path)
|
|
145
|
+
return path.parent if parent else path
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
##
|
|
149
|
+
|
|
150
|
+
|
|
101
151
|
def maybe_sudo_cmd(cmd: str, /, *args: str, sudo: bool = False) -> list[str]:
|
|
102
152
|
parts: list[str] = [cmd, *args]
|
|
103
153
|
return sudo_cmd(*parts) if sudo else parts
|
|
104
154
|
|
|
105
155
|
|
|
156
|
+
##
|
|
157
|
+
|
|
158
|
+
|
|
106
159
|
def mkdir(path: PathLike, /, *, sudo: bool = False, parent: bool = False) -> None:
|
|
107
160
|
if sudo: # pragma: no cover
|
|
108
161
|
run(*sudo_cmd(*mkdir_cmd(path, parent=parent)))
|
|
109
162
|
else:
|
|
110
|
-
path =
|
|
111
|
-
|
|
112
|
-
|
|
163
|
+
maybe_parent(path, parent=parent).mkdir(parents=True, exist_ok=True)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
##
|
|
113
167
|
|
|
114
168
|
|
|
115
169
|
def mkdir_cmd(path: PathLike, /, *, parent: bool = False) -> list[str]:
|
|
116
|
-
|
|
117
|
-
|
|
170
|
+
return ["mkdir", "-p", str(maybe_parent(path, parent=parent))]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
##
|
|
118
174
|
|
|
119
175
|
|
|
120
176
|
def mv_cmd(src: PathLike, dest: PathLike, /) -> list[str]:
|
|
121
177
|
return ["mv", str(src), str(dest)]
|
|
122
178
|
|
|
123
179
|
|
|
180
|
+
##
|
|
181
|
+
|
|
182
|
+
|
|
124
183
|
def rm_cmd(path: PathLike, /) -> list[str]:
|
|
125
184
|
return ["rm", "-rf", str(path)]
|
|
126
185
|
|
|
127
186
|
|
|
187
|
+
##
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def rsync(
|
|
191
|
+
src_or_srcs: MaybeIterable[PathLike],
|
|
192
|
+
user: str,
|
|
193
|
+
hostname: str,
|
|
194
|
+
dest: PathLike,
|
|
195
|
+
/,
|
|
196
|
+
*,
|
|
197
|
+
sudo: bool = False,
|
|
198
|
+
batch_mode: bool = True,
|
|
199
|
+
host_key_algorithms: list[str] = _HOST_KEY_ALGORITHMS,
|
|
200
|
+
strict_host_key_checking: bool = True,
|
|
201
|
+
print: bool = False, # noqa: A002
|
|
202
|
+
retry: Retry | None = None,
|
|
203
|
+
logger: LoggerLike | None = None,
|
|
204
|
+
chown_user: str | None = None,
|
|
205
|
+
chown_group: str | None = None,
|
|
206
|
+
exclude: MaybeIterable[str] | None = None,
|
|
207
|
+
chmod: str | None = None,
|
|
208
|
+
) -> None:
|
|
209
|
+
mkdir_args = maybe_sudo_cmd(*mkdir_cmd(dest, parent=True), sudo=sudo) # skipif-ci
|
|
210
|
+
ssh( # skipif-ci
|
|
211
|
+
user,
|
|
212
|
+
hostname,
|
|
213
|
+
*mkdir_args,
|
|
214
|
+
batch_mode=batch_mode,
|
|
215
|
+
host_key_algorithms=host_key_algorithms,
|
|
216
|
+
strict_host_key_checking=strict_host_key_checking,
|
|
217
|
+
print=print,
|
|
218
|
+
retry=retry,
|
|
219
|
+
logger=logger,
|
|
220
|
+
)
|
|
221
|
+
is_dir = any(Path(s).is_dir() for s in always_iterable(src_or_srcs)) # skipif-ci
|
|
222
|
+
rsync_args = rsync_cmd( # skipif-ci
|
|
223
|
+
src_or_srcs,
|
|
224
|
+
user,
|
|
225
|
+
hostname,
|
|
226
|
+
dest,
|
|
227
|
+
archive=is_dir,
|
|
228
|
+
chown_user=chown_user,
|
|
229
|
+
chown_group=chown_group,
|
|
230
|
+
exclude=exclude,
|
|
231
|
+
batch_mode=batch_mode,
|
|
232
|
+
host_key_algorithms=host_key_algorithms,
|
|
233
|
+
strict_host_key_checking=strict_host_key_checking,
|
|
234
|
+
sudo=sudo,
|
|
235
|
+
parent=is_dir,
|
|
236
|
+
)
|
|
237
|
+
run(*rsync_args, print=print, retry=retry, logger=logger) # skipif-ci
|
|
238
|
+
if chmod is not None: # skipif-ci
|
|
239
|
+
chmod_args = maybe_sudo_cmd(*chmod_cmd(dest, chmod), sudo=sudo)
|
|
240
|
+
ssh(
|
|
241
|
+
user,
|
|
242
|
+
hostname,
|
|
243
|
+
*chmod_args,
|
|
244
|
+
batch_mode=batch_mode,
|
|
245
|
+
host_key_algorithms=host_key_algorithms,
|
|
246
|
+
strict_host_key_checking=strict_host_key_checking,
|
|
247
|
+
print=print,
|
|
248
|
+
retry=retry,
|
|
249
|
+
logger=logger,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
##
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def rsync_cmd(
|
|
257
|
+
src_or_srcs: MaybeIterable[PathLike],
|
|
258
|
+
user: str,
|
|
259
|
+
hostname: str,
|
|
260
|
+
dest: PathLike,
|
|
261
|
+
/,
|
|
262
|
+
*,
|
|
263
|
+
archive: bool = False,
|
|
264
|
+
chown_user: str | None = None,
|
|
265
|
+
chown_group: str | None = None,
|
|
266
|
+
exclude: MaybeIterable[str] | None = None,
|
|
267
|
+
batch_mode: bool = True,
|
|
268
|
+
host_key_algorithms: list[str] = _HOST_KEY_ALGORITHMS,
|
|
269
|
+
strict_host_key_checking: bool = True,
|
|
270
|
+
sudo: bool = False,
|
|
271
|
+
parent: bool = False,
|
|
272
|
+
) -> list[str]:
|
|
273
|
+
args: list[str] = ["rsync"]
|
|
274
|
+
if archive:
|
|
275
|
+
args.append("--archive")
|
|
276
|
+
args.append("--checksum")
|
|
277
|
+
match chown_user, chown_group:
|
|
278
|
+
case None, None:
|
|
279
|
+
...
|
|
280
|
+
case str(), None:
|
|
281
|
+
args.extend(["--chown", chown_user])
|
|
282
|
+
case None, str():
|
|
283
|
+
args.extend(["--chown", f":{chown_group}"])
|
|
284
|
+
case str(), str():
|
|
285
|
+
args.extend(["--chown", f"{chown_user}:{chown_group}"])
|
|
286
|
+
case never:
|
|
287
|
+
assert_never(never)
|
|
288
|
+
args.append("--compress")
|
|
289
|
+
if exclude is not None:
|
|
290
|
+
for exclude_i in always_iterable(exclude):
|
|
291
|
+
args.extend(["--exclude", exclude_i])
|
|
292
|
+
rsh_args: list[str] = ssh_opts_cmd(
|
|
293
|
+
batch_mode=batch_mode,
|
|
294
|
+
host_key_algorithms=host_key_algorithms,
|
|
295
|
+
strict_host_key_checking=strict_host_key_checking,
|
|
296
|
+
)
|
|
297
|
+
args.extend(["--rsh", join(rsh_args)])
|
|
298
|
+
if sudo:
|
|
299
|
+
args.extend(["--rsync-path", join(sudo_cmd("rsync"))])
|
|
300
|
+
dest_use = maybe_parent(dest, parent=parent)
|
|
301
|
+
return [
|
|
302
|
+
*args,
|
|
303
|
+
*map(str, always_iterable(src_or_srcs)),
|
|
304
|
+
f"{user}@{hostname}:{dest_use}",
|
|
305
|
+
]
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
##
|
|
309
|
+
|
|
310
|
+
|
|
128
311
|
@overload
|
|
129
312
|
def run(
|
|
130
313
|
cmd: str,
|
|
@@ -380,10 +563,16 @@ def _run_write_to_streams(text: str, /, *outputs: IO[str]) -> None:
|
|
|
380
563
|
_ = output.write(text)
|
|
381
564
|
|
|
382
565
|
|
|
566
|
+
##
|
|
567
|
+
|
|
568
|
+
|
|
383
569
|
def set_hostname_cmd(hostname: str, /) -> list[str]:
|
|
384
570
|
return ["hostnamectl", "set-hostname", hostname]
|
|
385
571
|
|
|
386
572
|
|
|
573
|
+
##
|
|
574
|
+
|
|
575
|
+
|
|
387
576
|
@overload
|
|
388
577
|
def ssh(
|
|
389
578
|
user: str,
|
|
@@ -519,6 +708,9 @@ def ssh(
|
|
|
519
708
|
)
|
|
520
709
|
|
|
521
710
|
|
|
711
|
+
##
|
|
712
|
+
|
|
713
|
+
|
|
522
714
|
def ssh_cmd(
|
|
523
715
|
user: str,
|
|
524
716
|
hostname: str,
|
|
@@ -527,6 +719,23 @@ def ssh_cmd(
|
|
|
527
719
|
batch_mode: bool = True,
|
|
528
720
|
host_key_algorithms: list[str] = _HOST_KEY_ALGORITHMS,
|
|
529
721
|
strict_host_key_checking: bool = True,
|
|
722
|
+
) -> list[str]:
|
|
723
|
+
args: list[str] = ssh_opts_cmd(
|
|
724
|
+
batch_mode=batch_mode,
|
|
725
|
+
host_key_algorithms=host_key_algorithms,
|
|
726
|
+
strict_host_key_checking=strict_host_key_checking,
|
|
727
|
+
)
|
|
728
|
+
return [*args, f"{user}@{hostname}", *cmd_and_cmds_or_args]
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
##
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
def ssh_opts_cmd(
|
|
735
|
+
*,
|
|
736
|
+
batch_mode: bool = True,
|
|
737
|
+
host_key_algorithms: list[str] = _HOST_KEY_ALGORITHMS,
|
|
738
|
+
strict_host_key_checking: bool = True,
|
|
530
739
|
) -> list[str]:
|
|
531
740
|
args: list[str] = ["ssh"]
|
|
532
741
|
if batch_mode:
|
|
@@ -534,29 +743,47 @@ def ssh_cmd(
|
|
|
534
743
|
args.extend(["-o", f"HostKeyAlgorithms={','.join(host_key_algorithms)}"])
|
|
535
744
|
if strict_host_key_checking:
|
|
536
745
|
args.extend(["-o", "StrictHostKeyChecking=yes"])
|
|
537
|
-
return [*args, "-T"
|
|
746
|
+
return [*args, "-T"]
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
##
|
|
538
750
|
|
|
539
751
|
|
|
540
752
|
def ssh_keygen_cmd(hostname: str, /) -> list[str]:
|
|
541
753
|
return ["ssh-keygen", "-f", "~/.ssh/known_hosts", "-R", hostname]
|
|
542
754
|
|
|
543
755
|
|
|
756
|
+
##
|
|
757
|
+
|
|
758
|
+
|
|
544
759
|
def sudo_cmd(cmd: str, /, *args: str) -> list[str]:
|
|
545
760
|
return ["sudo", cmd, *args]
|
|
546
761
|
|
|
547
762
|
|
|
763
|
+
##
|
|
764
|
+
|
|
765
|
+
|
|
548
766
|
def sudo_nopasswd_cmd(user: str, /) -> str:
|
|
549
767
|
return f"{user} ALL=(ALL) NOPASSWD: ALL"
|
|
550
768
|
|
|
551
769
|
|
|
770
|
+
##
|
|
771
|
+
|
|
772
|
+
|
|
552
773
|
def symlink_cmd(src: PathLike, dest: PathLike, /) -> list[str]:
|
|
553
774
|
return ["ln", "-s", str(src), str(dest)]
|
|
554
775
|
|
|
555
776
|
|
|
777
|
+
##
|
|
778
|
+
|
|
779
|
+
|
|
556
780
|
def touch_cmd(path: PathLike, /) -> list[str]:
|
|
557
781
|
return ["touch", str(path)]
|
|
558
782
|
|
|
559
783
|
|
|
784
|
+
##
|
|
785
|
+
|
|
786
|
+
|
|
560
787
|
def uv_run_cmd(module: str, /, *args: str) -> list[str]:
|
|
561
788
|
return [
|
|
562
789
|
"uv",
|
|
@@ -572,6 +799,9 @@ def uv_run_cmd(module: str, /, *args: str) -> list[str]:
|
|
|
572
799
|
]
|
|
573
800
|
|
|
574
801
|
|
|
802
|
+
##
|
|
803
|
+
|
|
804
|
+
|
|
575
805
|
@contextmanager
|
|
576
806
|
def yield_ssh_temp_dir(
|
|
577
807
|
user: str,
|
|
@@ -582,12 +812,12 @@ def yield_ssh_temp_dir(
|
|
|
582
812
|
logger: LoggerLike | None = None,
|
|
583
813
|
keep: bool = False,
|
|
584
814
|
) -> Iterator[Path]:
|
|
585
|
-
path = Path(
|
|
815
|
+
path = Path( # skipif-ci
|
|
586
816
|
ssh(user, hostname, *MKTEMP_DIR_CMD, return_=True, retry=retry, logger=logger)
|
|
587
817
|
)
|
|
588
|
-
try:
|
|
818
|
+
try: # skipif-ci
|
|
589
819
|
yield path
|
|
590
|
-
finally:
|
|
820
|
+
finally: # skipif-ci
|
|
591
821
|
if keep:
|
|
592
822
|
if logger is not None:
|
|
593
823
|
to_logger(logger).info("Keeping temporary directory '%s'...", path)
|
|
@@ -612,15 +842,19 @@ __all__ = [
|
|
|
612
842
|
"expand_path",
|
|
613
843
|
"git_clone_cmd",
|
|
614
844
|
"git_hard_reset_cmd",
|
|
845
|
+
"maybe_parent",
|
|
615
846
|
"maybe_sudo_cmd",
|
|
616
847
|
"mkdir",
|
|
617
848
|
"mkdir_cmd",
|
|
618
849
|
"mv_cmd",
|
|
619
850
|
"rm_cmd",
|
|
851
|
+
"rsync",
|
|
852
|
+
"rsync_cmd",
|
|
620
853
|
"run",
|
|
621
854
|
"set_hostname_cmd",
|
|
622
855
|
"ssh",
|
|
623
856
|
"ssh_cmd",
|
|
857
|
+
"ssh_opts_cmd",
|
|
624
858
|
"sudo_cmd",
|
|
625
859
|
"sudo_nopasswd_cmd",
|
|
626
860
|
"symlink_cmd",
|
|
File without changes
|
|
File without changes
|