dycw-utilities 0.174.13__py3-none-any.whl → 0.174.15__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.13.dist-info → dycw_utilities-0.174.15.dist-info}/METADATA +1 -1
- {dycw_utilities-0.174.13.dist-info → dycw_utilities-0.174.15.dist-info}/RECORD +6 -6
- utilities/__init__.py +1 -1
- utilities/subprocess.py +87 -42
- {dycw_utilities-0.174.13.dist-info → dycw_utilities-0.174.15.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.174.13.dist-info → dycw_utilities-0.174.15.dist-info}/entry_points.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
utilities/__init__.py,sha256=
|
|
1
|
+
utilities/__init__.py,sha256=e_rDHgJr89spnVGWmvxwmI_TbjZtP1QsasPjzzI3FTs,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
|
|
@@ -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=gsRaeBzUSINUBuMZTSz7F7rMdAmhUFCEhMQOEpS5Ro4,28897
|
|
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.15.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
|
|
102
|
+
dycw_utilities-0.174.15.dist-info/entry_points.txt,sha256=ykGI1ArwOPHqm2g5Cqh3ENdMxEej_a_FcOUov5EM5Oc,155
|
|
103
|
+
dycw_utilities-0.174.15.dist-info/METADATA,sha256=-vZ1ta-ZjRzQ0WaZ7uRspE0DJQCqajno8r1UEp8gF2Y,1710
|
|
104
|
+
dycw_utilities-0.174.15.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/subprocess.py
CHANGED
|
@@ -48,6 +48,7 @@ UPDATE_CA_CERTIFICATES: str = "update-ca-certificates"
|
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
def apt_install_cmd(package: str, /) -> list[str]:
|
|
51
|
+
"""Command to use 'apt' to install a package."""
|
|
51
52
|
return ["apt", "install", "-y", package]
|
|
52
53
|
|
|
53
54
|
|
|
@@ -55,6 +56,7 @@ def apt_install_cmd(package: str, /) -> list[str]:
|
|
|
55
56
|
|
|
56
57
|
|
|
57
58
|
def cat_cmd(path: PathLike, /) -> list[str]:
|
|
59
|
+
"""Command to use 'cat' to concatenate and print files."""
|
|
58
60
|
return ["cat", str(path)]
|
|
59
61
|
|
|
60
62
|
|
|
@@ -62,6 +64,7 @@ def cat_cmd(path: PathLike, /) -> list[str]:
|
|
|
62
64
|
|
|
63
65
|
|
|
64
66
|
def cd_cmd(path: PathLike, /) -> list[str]:
|
|
67
|
+
"""Command to use 'cd' to change working directory."""
|
|
65
68
|
return ["cd", str(path)]
|
|
66
69
|
|
|
67
70
|
|
|
@@ -69,6 +72,7 @@ def cd_cmd(path: PathLike, /) -> list[str]:
|
|
|
69
72
|
|
|
70
73
|
|
|
71
74
|
def chmod(path: PathLike, perms: PermissionsLike, /, *, sudo: bool = False) -> None:
|
|
75
|
+
"""Change file mode."""
|
|
72
76
|
if sudo: # pragma: no cover
|
|
73
77
|
run(*sudo_cmd(*chmod_cmd(path, perms)))
|
|
74
78
|
else:
|
|
@@ -79,6 +83,7 @@ def chmod(path: PathLike, perms: PermissionsLike, /, *, sudo: bool = False) -> N
|
|
|
79
83
|
|
|
80
84
|
|
|
81
85
|
def chmod_cmd(path: PathLike, perms: PermissionsLike, /) -> list[str]:
|
|
86
|
+
"""Command to use 'chmod' to change file mode."""
|
|
82
87
|
return ["chmod", str(ensure_perms(perms)), str(path)]
|
|
83
88
|
|
|
84
89
|
|
|
@@ -93,6 +98,7 @@ def chown(
|
|
|
93
98
|
user: str | int | None = None,
|
|
94
99
|
group: str | int | None = None,
|
|
95
100
|
) -> None:
|
|
101
|
+
"""Change file owner and/or group."""
|
|
96
102
|
if sudo: # pragma: no cover
|
|
97
103
|
match user, group:
|
|
98
104
|
case None, None:
|
|
@@ -121,6 +127,7 @@ def chown(
|
|
|
121
127
|
def chown_cmd(
|
|
122
128
|
path: PathLike, /, *, user: str | int | None = None, group: str | int | None = None
|
|
123
129
|
) -> list[str]:
|
|
130
|
+
"""Command to use 'chown' to change file owner and/or group."""
|
|
124
131
|
match user, group:
|
|
125
132
|
case None, None:
|
|
126
133
|
raise ChownCmdError
|
|
@@ -145,7 +152,7 @@ class ChownCmdError(Exception):
|
|
|
145
152
|
##
|
|
146
153
|
|
|
147
154
|
|
|
148
|
-
def
|
|
155
|
+
def cp(
|
|
149
156
|
src: PathLike,
|
|
150
157
|
dest: PathLike,
|
|
151
158
|
/,
|
|
@@ -155,7 +162,7 @@ def copy_file(
|
|
|
155
162
|
owner: str | int | None = None,
|
|
156
163
|
group: str | int | None = None,
|
|
157
164
|
) -> None:
|
|
158
|
-
"""Copy a file/directory
|
|
165
|
+
"""Copy a file/directory."""
|
|
159
166
|
mkdir(dest, sudo=sudo, parent=True)
|
|
160
167
|
if sudo:
|
|
161
168
|
run(*sudo_cmd(*cp_cmd(src, dest)))
|
|
@@ -166,7 +173,7 @@ def copy_file(
|
|
|
166
173
|
elif src.is_dir():
|
|
167
174
|
_ = copytree(src, dest, dirs_exist_ok=True)
|
|
168
175
|
else:
|
|
169
|
-
raise
|
|
176
|
+
raise CpError(src=src, dest=dest)
|
|
170
177
|
if perms is not None:
|
|
171
178
|
chmod(dest, perms, sudo=sudo)
|
|
172
179
|
if (owner is not None) or (group is not None):
|
|
@@ -174,7 +181,7 @@ def copy_file(
|
|
|
174
181
|
|
|
175
182
|
|
|
176
183
|
@dataclass(kw_only=True, slots=True)
|
|
177
|
-
class
|
|
184
|
+
class CpError(Exception):
|
|
178
185
|
src: Path
|
|
179
186
|
dest: Path
|
|
180
187
|
|
|
@@ -183,10 +190,8 @@ class CopyFileError(Exception):
|
|
|
183
190
|
return f"Unable to copy {str(self.src)!r} to {str(self.dest)!r}; source does not exist"
|
|
184
191
|
|
|
185
192
|
|
|
186
|
-
##
|
|
187
|
-
|
|
188
|
-
|
|
189
193
|
def cp_cmd(src: PathLike, dest: PathLike, /) -> list[str]:
|
|
194
|
+
"""Command to use 'cp' to copy a file/directory."""
|
|
190
195
|
return ["cp", "-r", str(src), str(dest)]
|
|
191
196
|
|
|
192
197
|
|
|
@@ -194,6 +199,7 @@ def cp_cmd(src: PathLike, dest: PathLike, /) -> list[str]:
|
|
|
194
199
|
|
|
195
200
|
|
|
196
201
|
def echo_cmd(text: str, /) -> list[str]:
|
|
202
|
+
"""Command to use 'echo' to write arguments to the standard output."""
|
|
197
203
|
return ["echo", text]
|
|
198
204
|
|
|
199
205
|
|
|
@@ -203,6 +209,7 @@ def echo_cmd(text: str, /) -> list[str]:
|
|
|
203
209
|
def expand_path(
|
|
204
210
|
path: PathLike, /, *, subs: StrMapping | None = None, sudo: bool = False
|
|
205
211
|
) -> Path:
|
|
212
|
+
"""Expand a path using `subprocess`."""
|
|
206
213
|
if subs is not None:
|
|
207
214
|
path = Template(str(path)).substitute(**subs)
|
|
208
215
|
if sudo: # pragma: no cover
|
|
@@ -214,6 +221,7 @@ def expand_path(
|
|
|
214
221
|
|
|
215
222
|
|
|
216
223
|
def git_clone_cmd(url: str, path: PathLike, /) -> list[str]:
|
|
224
|
+
"""Command to use 'git clone' to clone a repository."""
|
|
217
225
|
return ["git", "clone", "--recurse-submodules", url, str(path)]
|
|
218
226
|
|
|
219
227
|
|
|
@@ -221,6 +229,7 @@ def git_clone_cmd(url: str, path: PathLike, /) -> list[str]:
|
|
|
221
229
|
|
|
222
230
|
|
|
223
231
|
def git_hard_reset_cmd(*, branch: str | None = None) -> list[str]:
|
|
232
|
+
"""Command to use 'git hard-reset' to hard reset a repository."""
|
|
224
233
|
branch_use = "master" if branch is None else branch
|
|
225
234
|
return ["git", "hard-reset", branch_use]
|
|
226
235
|
|
|
@@ -229,6 +238,7 @@ def git_hard_reset_cmd(*, branch: str | None = None) -> list[str]:
|
|
|
229
238
|
|
|
230
239
|
|
|
231
240
|
def maybe_parent(path: PathLike, /, *, parent: bool = False) -> Path:
|
|
241
|
+
"""Get the parent of a path, if required."""
|
|
232
242
|
path = Path(path)
|
|
233
243
|
return path.parent if parent else path
|
|
234
244
|
|
|
@@ -236,15 +246,8 @@ def maybe_parent(path: PathLike, /, *, parent: bool = False) -> Path:
|
|
|
236
246
|
##
|
|
237
247
|
|
|
238
248
|
|
|
239
|
-
def maybe_sudo_cmd(cmd: str, /, *args: str, sudo: bool = False) -> list[str]:
|
|
240
|
-
parts: list[str] = [cmd, *args]
|
|
241
|
-
return sudo_cmd(*parts) if sudo else parts
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
##
|
|
245
|
-
|
|
246
|
-
|
|
247
249
|
def mkdir(path: PathLike, /, *, sudo: bool = False, parent: bool = False) -> None:
|
|
250
|
+
"""Make a directory."""
|
|
248
251
|
if sudo: # pragma: no cover
|
|
249
252
|
run(*sudo_cmd(*mkdir_cmd(path, parent=parent)))
|
|
250
253
|
else:
|
|
@@ -255,13 +258,14 @@ def mkdir(path: PathLike, /, *, sudo: bool = False, parent: bool = False) -> Non
|
|
|
255
258
|
|
|
256
259
|
|
|
257
260
|
def mkdir_cmd(path: PathLike, /, *, parent: bool = False) -> list[str]:
|
|
261
|
+
"""Command to use 'mv' to make a directory."""
|
|
258
262
|
return ["mkdir", "-p", str(maybe_parent(path, parent=parent))]
|
|
259
263
|
|
|
260
264
|
|
|
261
265
|
##
|
|
262
266
|
|
|
263
267
|
|
|
264
|
-
def
|
|
268
|
+
def mv(
|
|
265
269
|
src: PathLike,
|
|
266
270
|
dest: PathLike,
|
|
267
271
|
/,
|
|
@@ -271,7 +275,7 @@ def move_file(
|
|
|
271
275
|
owner: str | int | None = None,
|
|
272
276
|
group: str | int | None = None,
|
|
273
277
|
) -> None:
|
|
274
|
-
"""Move a file/directory
|
|
278
|
+
"""Move a file/directory."""
|
|
275
279
|
mkdir(dest, sudo=sudo, parent=True)
|
|
276
280
|
if sudo:
|
|
277
281
|
run(*sudo_cmd(*cp_cmd(src, dest)))
|
|
@@ -280,7 +284,7 @@ def move_file(
|
|
|
280
284
|
if src.exists():
|
|
281
285
|
_ = move(src, dest)
|
|
282
286
|
else:
|
|
283
|
-
raise
|
|
287
|
+
raise MvFileError(src=src, dest=dest)
|
|
284
288
|
if perms is not None:
|
|
285
289
|
chmod(dest, perms, sudo=sudo)
|
|
286
290
|
if (owner is not None) or (group is not None):
|
|
@@ -288,7 +292,7 @@ def move_file(
|
|
|
288
292
|
|
|
289
293
|
|
|
290
294
|
@dataclass(kw_only=True, slots=True)
|
|
291
|
-
class
|
|
295
|
+
class MvFileError(Exception):
|
|
292
296
|
src: Path
|
|
293
297
|
dest: Path
|
|
294
298
|
|
|
@@ -297,17 +301,16 @@ class MoveFileError(Exception):
|
|
|
297
301
|
return f"Unable to move {str(self.src)!r} to {str(self.dest)!r}; source does not exist"
|
|
298
302
|
|
|
299
303
|
|
|
300
|
-
##
|
|
301
|
-
|
|
302
|
-
|
|
303
304
|
def mv_cmd(src: PathLike, dest: PathLike, /) -> list[str]:
|
|
305
|
+
"""Command to use 'mv' to move a file/directory."""
|
|
304
306
|
return ["mv", str(src), str(dest)]
|
|
305
307
|
|
|
306
308
|
|
|
307
309
|
##
|
|
308
310
|
|
|
309
311
|
|
|
310
|
-
def
|
|
312
|
+
def rm(path: PathLike, /, *, sudo: bool = False) -> None:
|
|
313
|
+
"""Remove a file/directory."""
|
|
311
314
|
if sudo: # pragma: no cover
|
|
312
315
|
run(*sudo_cmd(*rm_cmd(path)))
|
|
313
316
|
else:
|
|
@@ -318,10 +321,8 @@ def remove(path: PathLike, /, *, sudo: bool = False) -> None:
|
|
|
318
321
|
rmtree(path, ignore_errors=True)
|
|
319
322
|
|
|
320
323
|
|
|
321
|
-
##
|
|
322
|
-
|
|
323
|
-
|
|
324
324
|
def rm_cmd(path: PathLike, /) -> list[str]:
|
|
325
|
+
"""Command to use 'rm' to remove a file/directory."""
|
|
325
326
|
return ["rm", "-rf", str(path)]
|
|
326
327
|
|
|
327
328
|
|
|
@@ -347,6 +348,7 @@ def rsync(
|
|
|
347
348
|
exclude: MaybeIterable[str] | None = None,
|
|
348
349
|
chmod: str | None = None,
|
|
349
350
|
) -> None:
|
|
351
|
+
"""Remote & local file copying."""
|
|
350
352
|
mkdir_args = maybe_sudo_cmd(*mkdir_cmd(dest, parent=True), sudo=sudo) # skipif-ci
|
|
351
353
|
ssh( # skipif-ci
|
|
352
354
|
user,
|
|
@@ -391,9 +393,6 @@ def rsync(
|
|
|
391
393
|
)
|
|
392
394
|
|
|
393
395
|
|
|
394
|
-
##
|
|
395
|
-
|
|
396
|
-
|
|
397
396
|
def rsync_cmd(
|
|
398
397
|
src_or_srcs: MaybeIterable[PathLike],
|
|
399
398
|
user: str,
|
|
@@ -411,6 +410,7 @@ def rsync_cmd(
|
|
|
411
410
|
sudo: bool = False,
|
|
412
411
|
parent: bool = False,
|
|
413
412
|
) -> list[str]:
|
|
413
|
+
"""Command to use 'rsync' to do remote & local file copying."""
|
|
414
414
|
args: list[str] = ["rsync"]
|
|
415
415
|
if archive:
|
|
416
416
|
args.append("--archive")
|
|
@@ -568,6 +568,7 @@ def run(
|
|
|
568
568
|
retry: Retry | None = None,
|
|
569
569
|
logger: LoggerLike | None = None,
|
|
570
570
|
) -> str | None:
|
|
571
|
+
"""Run a command in a subprocess."""
|
|
571
572
|
args: list[str] = []
|
|
572
573
|
if user is not None: # pragma: no cover
|
|
573
574
|
args.extend(["su", "-", str(user)])
|
|
@@ -708,6 +709,7 @@ def _run_write_to_streams(text: str, /, *outputs: IO[str]) -> None:
|
|
|
708
709
|
|
|
709
710
|
|
|
710
711
|
def set_hostname_cmd(hostname: str, /) -> list[str]:
|
|
712
|
+
"""Command to set the system hostname."""
|
|
711
713
|
return ["hostnamectl", "set-hostname", hostname]
|
|
712
714
|
|
|
713
715
|
|
|
@@ -827,6 +829,7 @@ def ssh(
|
|
|
827
829
|
retry: Retry | None = None,
|
|
828
830
|
logger: LoggerLike | None = None,
|
|
829
831
|
) -> str | None:
|
|
832
|
+
"""Execute a command on a remote machine."""
|
|
830
833
|
cmd_and_args = ssh_cmd( # skipif-ci
|
|
831
834
|
user,
|
|
832
835
|
hostname,
|
|
@@ -849,9 +852,6 @@ def ssh(
|
|
|
849
852
|
)
|
|
850
853
|
|
|
851
854
|
|
|
852
|
-
##
|
|
853
|
-
|
|
854
|
-
|
|
855
855
|
def ssh_cmd(
|
|
856
856
|
user: str,
|
|
857
857
|
hostname: str,
|
|
@@ -861,6 +861,7 @@ def ssh_cmd(
|
|
|
861
861
|
host_key_algorithms: list[str] = _HOST_KEY_ALGORITHMS,
|
|
862
862
|
strict_host_key_checking: bool = True,
|
|
863
863
|
) -> list[str]:
|
|
864
|
+
"""Command to use 'ssh' to execute a command on a remote machine."""
|
|
864
865
|
args: list[str] = ssh_opts_cmd(
|
|
865
866
|
batch_mode=batch_mode,
|
|
866
867
|
host_key_algorithms=host_key_algorithms,
|
|
@@ -869,15 +870,13 @@ def ssh_cmd(
|
|
|
869
870
|
return [*args, f"{user}@{hostname}", *cmd_and_cmds_or_args]
|
|
870
871
|
|
|
871
872
|
|
|
872
|
-
##
|
|
873
|
-
|
|
874
|
-
|
|
875
873
|
def ssh_opts_cmd(
|
|
876
874
|
*,
|
|
877
875
|
batch_mode: bool = True,
|
|
878
876
|
host_key_algorithms: list[str] = _HOST_KEY_ALGORITHMS,
|
|
879
877
|
strict_host_key_checking: bool = True,
|
|
880
878
|
) -> list[str]:
|
|
879
|
+
"""Command to use prepare 'ssh' to execute a command on a remote machine."""
|
|
881
880
|
args: list[str] = ["ssh"]
|
|
882
881
|
if batch_mode:
|
|
883
882
|
args.extend(["-o", "BatchMode=yes"])
|
|
@@ -891,6 +890,7 @@ def ssh_opts_cmd(
|
|
|
891
890
|
|
|
892
891
|
|
|
893
892
|
def ssh_keygen_cmd(hostname: str, /) -> list[str]:
|
|
893
|
+
"""Command to use 'ssh-keygen' to add a known host."""
|
|
894
894
|
return ["ssh-keygen", "-f", "~/.ssh/known_hosts", "-R", hostname]
|
|
895
895
|
|
|
896
896
|
|
|
@@ -898,21 +898,64 @@ def ssh_keygen_cmd(hostname: str, /) -> list[str]:
|
|
|
898
898
|
|
|
899
899
|
|
|
900
900
|
def sudo_cmd(cmd: str, /, *args: str) -> list[str]:
|
|
901
|
+
"""Command to use 'sudo' to execute a command as another user."""
|
|
901
902
|
return ["sudo", cmd, *args]
|
|
902
903
|
|
|
903
904
|
|
|
905
|
+
def maybe_sudo_cmd(cmd: str, /, *args: str, sudo: bool = False) -> list[str]:
|
|
906
|
+
"""Command to use 'sudo' to execute a command as another user, if required."""
|
|
907
|
+
parts: list[str] = [cmd, *args]
|
|
908
|
+
return sudo_cmd(*parts) if sudo else parts
|
|
909
|
+
|
|
910
|
+
|
|
904
911
|
##
|
|
905
912
|
|
|
906
913
|
|
|
907
914
|
def sudo_nopasswd_cmd(user: str, /) -> str:
|
|
915
|
+
"""Command to allow a user to use password-free `sudo`."""
|
|
908
916
|
return f"{user} ALL=(ALL) NOPASSWD: ALL"
|
|
909
917
|
|
|
910
918
|
|
|
911
919
|
##
|
|
912
920
|
|
|
913
921
|
|
|
914
|
-
def
|
|
915
|
-
|
|
922
|
+
def symlink(targret: PathLike, link: PathLike, /, *, sudo: bool = False) -> None:
|
|
923
|
+
"""Make a symbolic link."""
|
|
924
|
+
rm(link, sudo=sudo)
|
|
925
|
+
mkdir(link, sudo=sudo, parent=True)
|
|
926
|
+
if sudo: # pragma: no cover
|
|
927
|
+
run(*sudo_cmd(*symlink_cmd(targret, link)))
|
|
928
|
+
else:
|
|
929
|
+
targret, link = map(Path, [targret, link])
|
|
930
|
+
link.symlink_to(targret)
|
|
931
|
+
|
|
932
|
+
|
|
933
|
+
def symlink_cmd(target: PathLike, link: PathLike, /) -> list[str]:
|
|
934
|
+
"""Command to use 'symlink' to make a symbolic link."""
|
|
935
|
+
return ["ln", "-s", str(target), str(link)]
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
##
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
def tee(
|
|
942
|
+
path: PathLike, text: str, /, *, sudo: bool = False, append: bool = False
|
|
943
|
+
) -> None:
|
|
944
|
+
"""Use 'tee' to duplicate standard input."""
|
|
945
|
+
if sudo: # pragma: no cover
|
|
946
|
+
run(*sudo_cmd(*tee_cmd(path, append=append)), input=text)
|
|
947
|
+
else:
|
|
948
|
+
path = Path(path)
|
|
949
|
+
with path.open(mode="a" if append else "w") as fh:
|
|
950
|
+
_ = fh.write(text)
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
def tee_cmd(path: PathLike, /, *, append: bool = False) -> list[str]:
|
|
954
|
+
"""Command to use 'tee' to duplicate standard input."""
|
|
955
|
+
args: list[str] = ["tee"]
|
|
956
|
+
if append:
|
|
957
|
+
args.append("-a")
|
|
958
|
+
return [*args, str(path)]
|
|
916
959
|
|
|
917
960
|
|
|
918
961
|
##
|
|
@@ -974,15 +1017,15 @@ __all__ = [
|
|
|
974
1017
|
"RESTART_SSHD",
|
|
975
1018
|
"UPDATE_CA_CERTIFICATES",
|
|
976
1019
|
"ChownCmdError",
|
|
977
|
-
"
|
|
978
|
-
"
|
|
1020
|
+
"CpError",
|
|
1021
|
+
"MvFileError",
|
|
979
1022
|
"apt_install_cmd",
|
|
980
1023
|
"cd_cmd",
|
|
981
1024
|
"chmod",
|
|
982
1025
|
"chmod_cmd",
|
|
983
1026
|
"chown",
|
|
984
1027
|
"chown_cmd",
|
|
985
|
-
"
|
|
1028
|
+
"cp",
|
|
986
1029
|
"cp_cmd",
|
|
987
1030
|
"echo_cmd",
|
|
988
1031
|
"expand_path",
|
|
@@ -992,9 +1035,9 @@ __all__ = [
|
|
|
992
1035
|
"maybe_sudo_cmd",
|
|
993
1036
|
"mkdir",
|
|
994
1037
|
"mkdir_cmd",
|
|
995
|
-
"
|
|
1038
|
+
"mv",
|
|
996
1039
|
"mv_cmd",
|
|
997
|
-
"
|
|
1040
|
+
"rm",
|
|
998
1041
|
"rm_cmd",
|
|
999
1042
|
"rsync",
|
|
1000
1043
|
"rsync_cmd",
|
|
@@ -1005,7 +1048,9 @@ __all__ = [
|
|
|
1005
1048
|
"ssh_opts_cmd",
|
|
1006
1049
|
"sudo_cmd",
|
|
1007
1050
|
"sudo_nopasswd_cmd",
|
|
1051
|
+
"symlink",
|
|
1008
1052
|
"symlink_cmd",
|
|
1053
|
+
"tee_cmd",
|
|
1009
1054
|
"touch_cmd",
|
|
1010
1055
|
"uv_run_cmd",
|
|
1011
1056
|
"yield_ssh_temp_dir",
|
|
File without changes
|
|
File without changes
|