pyinfra 2.9.2__py2.py3-none-any.whl → 3.0b1__py2.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.
- pyinfra/api/__init__.py +3 -0
- pyinfra/api/arguments.py +261 -255
- pyinfra/api/arguments_typed.py +77 -0
- pyinfra/api/command.py +66 -53
- pyinfra/api/config.py +27 -22
- pyinfra/api/connect.py +1 -1
- pyinfra/api/connectors.py +2 -24
- pyinfra/api/deploy.py +21 -52
- pyinfra/api/exceptions.py +33 -8
- pyinfra/api/facts.py +77 -113
- pyinfra/api/host.py +150 -82
- pyinfra/api/inventory.py +17 -25
- pyinfra/api/operation.py +232 -198
- pyinfra/api/operations.py +102 -148
- pyinfra/api/state.py +137 -79
- pyinfra/api/util.py +55 -70
- pyinfra/connectors/base.py +150 -0
- pyinfra/connectors/chroot.py +160 -169
- pyinfra/connectors/docker.py +227 -237
- pyinfra/connectors/dockerssh.py +231 -253
- pyinfra/connectors/local.py +195 -207
- pyinfra/connectors/ssh.py +528 -615
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +5 -3
- pyinfra/connectors/terraform.py +86 -65
- pyinfra/connectors/util.py +212 -137
- pyinfra/connectors/vagrant.py +55 -48
- pyinfra/context.py +3 -2
- pyinfra/facts/docker.py +1 -0
- pyinfra/facts/files.py +45 -32
- pyinfra/facts/git.py +3 -1
- pyinfra/facts/gpg.py +1 -1
- pyinfra/facts/hardware.py +4 -2
- pyinfra/facts/iptables.py +5 -3
- pyinfra/facts/mysql.py +1 -0
- pyinfra/facts/postgres.py +168 -0
- pyinfra/facts/postgresql.py +5 -161
- pyinfra/facts/selinux.py +3 -1
- pyinfra/facts/server.py +77 -30
- pyinfra/facts/systemd.py +29 -12
- pyinfra/facts/sysvinit.py +10 -10
- pyinfra/facts/util/packaging.py +4 -2
- pyinfra/local.py +4 -5
- pyinfra/operations/apk.py +3 -3
- pyinfra/operations/apt.py +25 -47
- pyinfra/operations/brew.py +7 -14
- pyinfra/operations/bsdinit.py +4 -4
- pyinfra/operations/cargo.py +1 -1
- pyinfra/operations/choco.py +1 -1
- pyinfra/operations/dnf.py +4 -4
- pyinfra/operations/files.py +108 -321
- pyinfra/operations/gem.py +1 -1
- pyinfra/operations/git.py +6 -37
- pyinfra/operations/iptables.py +2 -10
- pyinfra/operations/launchd.py +1 -1
- pyinfra/operations/lxd.py +1 -9
- pyinfra/operations/mysql.py +5 -28
- pyinfra/operations/npm.py +1 -1
- pyinfra/operations/openrc.py +1 -1
- pyinfra/operations/pacman.py +3 -3
- pyinfra/operations/pip.py +14 -15
- pyinfra/operations/pkg.py +1 -1
- pyinfra/operations/pkgin.py +3 -3
- pyinfra/operations/postgres.py +347 -0
- pyinfra/operations/postgresql.py +17 -380
- pyinfra/operations/python.py +2 -17
- pyinfra/operations/selinux.py +5 -28
- pyinfra/operations/server.py +59 -84
- pyinfra/operations/snap.py +1 -3
- pyinfra/operations/ssh.py +8 -23
- pyinfra/operations/systemd.py +7 -7
- pyinfra/operations/sysvinit.py +3 -12
- pyinfra/operations/upstart.py +4 -4
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/files.py +2 -2
- pyinfra/operations/util/packaging.py +6 -24
- pyinfra/operations/util/service.py +18 -37
- pyinfra/operations/vzctl.py +2 -2
- pyinfra/operations/xbps.py +3 -3
- pyinfra/operations/yum.py +4 -4
- pyinfra/operations/zypper.py +4 -4
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/METADATA +19 -22
- pyinfra-3.0b1.dist-info/RECORD +163 -0
- pyinfra-3.0b1.dist-info/entry_points.txt +11 -0
- pyinfra_cli/__main__.py +2 -0
- pyinfra_cli/commands.py +7 -2
- pyinfra_cli/exceptions.py +83 -42
- pyinfra_cli/inventory.py +19 -4
- pyinfra_cli/log.py +17 -3
- pyinfra_cli/main.py +133 -90
- pyinfra_cli/prints.py +93 -129
- pyinfra_cli/util.py +60 -29
- tests/test_api/test_api.py +2 -0
- tests/test_api/test_api_arguments.py +13 -13
- tests/test_api/test_api_deploys.py +28 -29
- tests/test_api/test_api_facts.py +60 -98
- tests/test_api/test_api_operations.py +100 -200
- tests/test_cli/test_cli.py +18 -49
- tests/test_cli/test_cli_deploy.py +11 -37
- tests/test_cli/test_cli_exceptions.py +50 -19
- tests/test_cli/util.py +1 -1
- tests/test_connectors/test_chroot.py +6 -6
- tests/test_connectors/test_docker.py +4 -4
- tests/test_connectors/test_dockerssh.py +38 -50
- tests/test_connectors/test_local.py +11 -12
- tests/test_connectors/test_ssh.py +66 -107
- tests/test_connectors/test_terraform.py +9 -15
- tests/test_connectors/test_util.py +24 -46
- tests/test_connectors/test_vagrant.py +4 -4
- pyinfra/api/operation.pyi +0 -117
- pyinfra/connectors/ansible.py +0 -171
- pyinfra/connectors/mech.py +0 -186
- pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
- pyinfra/connectors/winrm.py +0 -320
- pyinfra/facts/windows.py +0 -366
- pyinfra/facts/windows_files.py +0 -90
- pyinfra/operations/windows.py +0 -59
- pyinfra/operations/windows_files.py +0 -551
- pyinfra-2.9.2.dist-info/RECORD +0 -170
- pyinfra-2.9.2.dist-info/entry_points.txt +0 -14
- tests/test_connectors/test_ansible.py +0 -64
- tests/test_connectors/test_mech.py +0 -126
- tests/test_connectors/test_winrm.py +0 -76
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/LICENSE.md +0 -0
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/WHEEL +0 -0
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/top_level.txt +0 -0
pyinfra/operations/files.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
The files operations handles filesystem state, file uploads and template generation.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
import os
|
|
6
8
|
import posixpath
|
|
7
9
|
import sys
|
|
@@ -9,10 +11,11 @@ import traceback
|
|
|
9
11
|
from datetime import timedelta
|
|
10
12
|
from fnmatch import fnmatch
|
|
11
13
|
from io import StringIO
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Union
|
|
12
16
|
|
|
13
17
|
from jinja2 import TemplateRuntimeError, TemplateSyntaxError, UndefinedError
|
|
14
18
|
|
|
15
|
-
import pyinfra
|
|
16
19
|
from pyinfra import host, logger, state
|
|
17
20
|
from pyinfra.api import (
|
|
18
21
|
FileDownloadCommand,
|
|
@@ -28,6 +31,7 @@ from pyinfra.api import (
|
|
|
28
31
|
from pyinfra.api.command import make_formatted_string_command
|
|
29
32
|
from pyinfra.api.util import (
|
|
30
33
|
get_call_location,
|
|
34
|
+
get_file_io,
|
|
31
35
|
get_file_sha1,
|
|
32
36
|
get_path_permissions_mode,
|
|
33
37
|
get_template,
|
|
@@ -54,9 +58,7 @@ from .util import files as file_utils
|
|
|
54
58
|
from .util.files import adjust_regex, ensure_mode_int, get_timestamp, sed_replace, unix_path_join
|
|
55
59
|
|
|
56
60
|
|
|
57
|
-
@operation(
|
|
58
|
-
pipeline_facts={"file": "dest"},
|
|
59
|
-
)
|
|
61
|
+
@operation()
|
|
60
62
|
def download(
|
|
61
63
|
src,
|
|
62
64
|
dest,
|
|
@@ -101,7 +103,6 @@ def download(
|
|
|
101
103
|
"""
|
|
102
104
|
|
|
103
105
|
info = host.get_fact(File, path=dest)
|
|
104
|
-
host_datetime = host.get_fact(Date).replace(tzinfo=None)
|
|
105
106
|
|
|
106
107
|
# Destination is a directory?
|
|
107
108
|
if info is False:
|
|
@@ -140,11 +141,10 @@ def download(
|
|
|
140
141
|
|
|
141
142
|
# If we download, always do user/group/mode as SSH user may be different
|
|
142
143
|
if download:
|
|
143
|
-
temp_file =
|
|
144
|
+
temp_file = host.get_temp_filename(dest)
|
|
144
145
|
|
|
145
|
-
curl_args = ["-sSLf"]
|
|
146
|
-
|
|
147
|
-
wget_args = ["-q"]
|
|
146
|
+
curl_args: list[Union[str, StringCommand]] = ["-sSLf"]
|
|
147
|
+
wget_args: list[Union[str, StringCommand]] = ["-q"]
|
|
148
148
|
|
|
149
149
|
if proxy:
|
|
150
150
|
curl_args.append(f"--proxy {proxy}")
|
|
@@ -221,30 +221,11 @@ def download(
|
|
|
221
221
|
md5sum,
|
|
222
222
|
QuoteString("MD5 did not match!"),
|
|
223
223
|
)
|
|
224
|
-
|
|
225
|
-
host.create_fact(
|
|
226
|
-
File,
|
|
227
|
-
kwargs={"path": dest},
|
|
228
|
-
data={"mode": mode, "group": group, "user": user, "mtime": host_datetime},
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
# Remove any checksum facts as we don't know the correct values
|
|
232
|
-
for value, fact_cls in (
|
|
233
|
-
(sha1sum, Sha1File),
|
|
234
|
-
(sha256sum, Sha256File),
|
|
235
|
-
(md5sum, Md5File),
|
|
236
|
-
):
|
|
237
|
-
fact_kwargs = {"path": dest}
|
|
238
|
-
if value:
|
|
239
|
-
host.create_fact(fact_cls, kwargs=fact_kwargs, data=value)
|
|
240
|
-
else:
|
|
241
|
-
host.delete_fact(fact_cls, kwargs=fact_kwargs)
|
|
242
|
-
|
|
243
224
|
else:
|
|
244
225
|
host.noop("file {0} has already been downloaded".format(dest))
|
|
245
226
|
|
|
246
227
|
|
|
247
|
-
@operation
|
|
228
|
+
@operation()
|
|
248
229
|
def line(
|
|
249
230
|
path,
|
|
250
231
|
line,
|
|
@@ -254,7 +235,6 @@ def line(
|
|
|
254
235
|
backup=False,
|
|
255
236
|
interpolate_variables=False,
|
|
256
237
|
escape_regex_characters=False,
|
|
257
|
-
assume_present=False,
|
|
258
238
|
ensure_newline=False,
|
|
259
239
|
):
|
|
260
240
|
"""
|
|
@@ -267,7 +247,6 @@ def line(
|
|
|
267
247
|
+ flags: list of flags to pass to sed when replacing/deleting
|
|
268
248
|
+ backup: whether to backup the file (see below)
|
|
269
249
|
+ interpolate_variables: whether to interpolate variables in ``replace``
|
|
270
|
-
+ assume_present: whether to assume a matching line already exists in the file
|
|
271
250
|
+ escape_regex_characters: whether to escape regex characters from the matching line
|
|
272
251
|
+ ensure_newline: ensures that the appended line is on a new line
|
|
273
252
|
|
|
@@ -354,15 +333,12 @@ def line(
|
|
|
354
333
|
# match_line = "{0}.*$".format(match_line)
|
|
355
334
|
|
|
356
335
|
# Is there a matching line in this file?
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
pattern=match_line,
|
|
364
|
-
interpolate_variables=interpolate_variables,
|
|
365
|
-
)
|
|
336
|
+
present_lines = host.get_fact(
|
|
337
|
+
FindInFile,
|
|
338
|
+
path=path,
|
|
339
|
+
pattern=match_line,
|
|
340
|
+
interpolate_variables=interpolate_variables,
|
|
341
|
+
)
|
|
366
342
|
|
|
367
343
|
# If replace present, use that over the matching line
|
|
368
344
|
if replace:
|
|
@@ -407,58 +383,27 @@ def line(
|
|
|
407
383
|
|
|
408
384
|
# No line and we want it, append it
|
|
409
385
|
if not present_lines and present:
|
|
410
|
-
# If
|
|
411
|
-
#
|
|
412
|
-
if
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
echo_command=echo_command,
|
|
426
|
-
sed_replace_command=sed_replace_command,
|
|
386
|
+
# If we're doing replacement, only append if the *replacement* line
|
|
387
|
+
# does not exist (as we are appending the replacement).
|
|
388
|
+
if replace:
|
|
389
|
+
# Ensure replace explicitly matches a whole line
|
|
390
|
+
replace_line = replace
|
|
391
|
+
if not replace_line.startswith("^"):
|
|
392
|
+
replace_line = f"^{replace_line}"
|
|
393
|
+
if not replace_line.endswith("$"):
|
|
394
|
+
replace_line = f"{replace_line}$"
|
|
395
|
+
|
|
396
|
+
present_lines = host.get_fact(
|
|
397
|
+
FindInFile,
|
|
398
|
+
path=path,
|
|
399
|
+
pattern=replace_line,
|
|
400
|
+
interpolate_variables=interpolate_variables,
|
|
427
401
|
)
|
|
428
402
|
|
|
429
|
-
|
|
403
|
+
if not present_lines:
|
|
404
|
+
yield echo_command
|
|
430
405
|
else:
|
|
431
|
-
|
|
432
|
-
# does not exist (as we are appending the replacement).
|
|
433
|
-
if replace:
|
|
434
|
-
# Ensure replace explicitly matches a whole line
|
|
435
|
-
replace_line = replace
|
|
436
|
-
if not replace_line.startswith("^"):
|
|
437
|
-
replace_line = f"^{replace_line}"
|
|
438
|
-
if not replace_line.endswith("$"):
|
|
439
|
-
replace_line = f"{replace_line}$"
|
|
440
|
-
|
|
441
|
-
present_lines = host.get_fact(
|
|
442
|
-
FindInFile,
|
|
443
|
-
path=path,
|
|
444
|
-
pattern=replace_line,
|
|
445
|
-
interpolate_variables=interpolate_variables,
|
|
446
|
-
)
|
|
447
|
-
|
|
448
|
-
if not present_lines:
|
|
449
|
-
yield echo_command
|
|
450
|
-
else:
|
|
451
|
-
host.noop('line "{0}" exists in {1}'.format(replace or line, path))
|
|
452
|
-
|
|
453
|
-
host.create_fact(
|
|
454
|
-
FindInFile,
|
|
455
|
-
kwargs={
|
|
456
|
-
"path": path,
|
|
457
|
-
"pattern": match_line,
|
|
458
|
-
"interpolate_variables": interpolate_variables,
|
|
459
|
-
},
|
|
460
|
-
data=[replace or line],
|
|
461
|
-
)
|
|
406
|
+
host.noop('line "{0}" exists in {1}'.format(replace or line, path))
|
|
462
407
|
|
|
463
408
|
# Line(s) exists and we want to remove them, replace with nothing
|
|
464
409
|
elif present_lines and not present:
|
|
@@ -471,27 +416,16 @@ def line(
|
|
|
471
416
|
interpolate_variables=interpolate_variables,
|
|
472
417
|
)
|
|
473
418
|
|
|
474
|
-
host.delete_fact(
|
|
475
|
-
FindInFile,
|
|
476
|
-
kwargs={
|
|
477
|
-
"path": path,
|
|
478
|
-
"pattern": match_line,
|
|
479
|
-
"interpolate_variables": interpolate_variables,
|
|
480
|
-
},
|
|
481
|
-
)
|
|
482
|
-
|
|
483
419
|
# Line(s) exists and we have want to ensure they're correct
|
|
484
420
|
elif present_lines and present:
|
|
485
421
|
# If any of lines are different, sed replace them
|
|
486
422
|
if replace and any(line != replace for line in present_lines):
|
|
487
423
|
yield sed_replace_command
|
|
488
|
-
del present_lines[:] # TODO: use .clear() when py3+
|
|
489
|
-
present_lines.append(replace)
|
|
490
424
|
else:
|
|
491
425
|
host.noop('line "{0}" exists in {1}'.format(replace or line, path))
|
|
492
426
|
|
|
493
427
|
|
|
494
|
-
@operation
|
|
428
|
+
@operation()
|
|
495
429
|
def replace(
|
|
496
430
|
path,
|
|
497
431
|
text=None,
|
|
@@ -561,22 +495,11 @@ def replace(
|
|
|
561
495
|
backup=backup,
|
|
562
496
|
interpolate_variables=interpolate_variables,
|
|
563
497
|
)
|
|
564
|
-
host.create_fact(
|
|
565
|
-
FindInFile,
|
|
566
|
-
kwargs={
|
|
567
|
-
"path": path,
|
|
568
|
-
"pattern": text,
|
|
569
|
-
"interpolate_variables": interpolate_variables,
|
|
570
|
-
},
|
|
571
|
-
data=[],
|
|
572
|
-
)
|
|
573
498
|
else:
|
|
574
499
|
host.noop('string "{0}" does not exist in {1}'.format(text, path))
|
|
575
500
|
|
|
576
501
|
|
|
577
|
-
@operation(
|
|
578
|
-
pipeline_facts={"find_files": "destination"},
|
|
579
|
-
)
|
|
502
|
+
@operation()
|
|
580
503
|
def sync(
|
|
581
504
|
src,
|
|
582
505
|
dest,
|
|
@@ -648,7 +571,7 @@ def sync(
|
|
|
648
571
|
put_files = []
|
|
649
572
|
ensure_dirnames = []
|
|
650
573
|
for dirpath, dirnames, filenames in os.walk(src, topdown=True):
|
|
651
|
-
remote_dirpath = os.path.normpath(os.path.relpath(dirpath, src))
|
|
574
|
+
remote_dirpath = Path(os.path.normpath(os.path.relpath(dirpath, src))).as_posix()
|
|
652
575
|
|
|
653
576
|
# Filter excluded dirs
|
|
654
577
|
for child_dir in dirnames[:]:
|
|
@@ -682,8 +605,8 @@ def sync(
|
|
|
682
605
|
if dest_link_info:
|
|
683
606
|
dest_to_ensure = dest_link_info["link_target"]
|
|
684
607
|
|
|
685
|
-
yield from directory(
|
|
686
|
-
dest_to_ensure,
|
|
608
|
+
yield from directory._inner(
|
|
609
|
+
path=dest_to_ensure,
|
|
687
610
|
user=user,
|
|
688
611
|
group=group,
|
|
689
612
|
mode=dir_mode or get_path_permissions_mode(src),
|
|
@@ -691,8 +614,8 @@ def sync(
|
|
|
691
614
|
|
|
692
615
|
# Ensure any remote dirnames
|
|
693
616
|
for dir_path_curr, dir_mode_curr in ensure_dirnames:
|
|
694
|
-
yield from directory(
|
|
695
|
-
unix_path_join(dest, dir_path_curr),
|
|
617
|
+
yield from directory._inner(
|
|
618
|
+
path=unix_path_join(dest, dir_path_curr),
|
|
696
619
|
user=user,
|
|
697
620
|
group=group,
|
|
698
621
|
mode=dir_mode or dir_mode_curr,
|
|
@@ -700,9 +623,9 @@ def sync(
|
|
|
700
623
|
|
|
701
624
|
# Put each file combination
|
|
702
625
|
for local_filename, remote_filename in put_files:
|
|
703
|
-
yield from put(
|
|
704
|
-
local_filename,
|
|
705
|
-
remote_filename,
|
|
626
|
+
yield from put._inner(
|
|
627
|
+
src=local_filename,
|
|
628
|
+
dest=remote_filename,
|
|
706
629
|
user=user,
|
|
707
630
|
group=group,
|
|
708
631
|
mode=mode or get_path_permissions_mode(local_filename),
|
|
@@ -720,7 +643,7 @@ def sync(
|
|
|
720
643
|
if exclude and any(fnmatch(filename, match) for match in exclude):
|
|
721
644
|
continue
|
|
722
645
|
|
|
723
|
-
yield from file(filename, present=False)
|
|
646
|
+
yield from file._inner(path=filename, present=False)
|
|
724
647
|
|
|
725
648
|
|
|
726
649
|
@memoize
|
|
@@ -754,11 +677,11 @@ def rsync(src, dest, flags=["-ax", "--delete"]):
|
|
|
754
677
|
yield RsyncCommand(src, dest, flags)
|
|
755
678
|
|
|
756
679
|
|
|
757
|
-
def _create_remote_dir(
|
|
680
|
+
def _create_remote_dir(remote_filename, user, group):
|
|
758
681
|
# Always use POSIX style path as local might be Windows, remote always *nix
|
|
759
682
|
remote_dirname = posixpath.dirname(remote_filename)
|
|
760
683
|
if remote_dirname:
|
|
761
|
-
yield from directory(
|
|
684
|
+
yield from directory._inner(
|
|
762
685
|
path=remote_dirname,
|
|
763
686
|
user=user,
|
|
764
687
|
group=group,
|
|
@@ -771,10 +694,6 @@ def _create_remote_dir(state, host, remote_filename, user, group):
|
|
|
771
694
|
# We don't (currently) cache the local state, so there's nothing we can
|
|
772
695
|
# update to flag the local file as present.
|
|
773
696
|
is_idempotent=False,
|
|
774
|
-
pipeline_facts={
|
|
775
|
-
"file": "src",
|
|
776
|
-
"sha1_file": "src",
|
|
777
|
-
},
|
|
778
697
|
)
|
|
779
698
|
def get(
|
|
780
699
|
src,
|
|
@@ -819,11 +738,11 @@ def get(
|
|
|
819
738
|
|
|
820
739
|
# No remote file, so assume exists and download it "blind"
|
|
821
740
|
if not remote_file or force:
|
|
822
|
-
yield FileDownloadCommand(src, dest, remote_temp_filename=
|
|
741
|
+
yield FileDownloadCommand(src, dest, remote_temp_filename=host.get_temp_filename(dest))
|
|
823
742
|
|
|
824
743
|
# No local file, so always download
|
|
825
744
|
elif not os.path.exists(dest):
|
|
826
|
-
yield FileDownloadCommand(src, dest, remote_temp_filename=
|
|
745
|
+
yield FileDownloadCommand(src, dest, remote_temp_filename=host.get_temp_filename(dest))
|
|
827
746
|
|
|
828
747
|
# Remote file exists - check if it matches our local
|
|
829
748
|
else:
|
|
@@ -832,15 +751,10 @@ def get(
|
|
|
832
751
|
|
|
833
752
|
# Check sha1sum, upload if needed
|
|
834
753
|
if local_sum != remote_sum:
|
|
835
|
-
yield FileDownloadCommand(src, dest, remote_temp_filename=
|
|
754
|
+
yield FileDownloadCommand(src, dest, remote_temp_filename=host.get_temp_filename(dest))
|
|
836
755
|
|
|
837
756
|
|
|
838
|
-
@operation(
|
|
839
|
-
pipeline_facts={
|
|
840
|
-
"file": "dest",
|
|
841
|
-
"sha1_file": "dest",
|
|
842
|
-
},
|
|
843
|
-
)
|
|
757
|
+
@operation()
|
|
844
758
|
def put(
|
|
845
759
|
src,
|
|
846
760
|
dest,
|
|
@@ -934,19 +848,19 @@ def put(
|
|
|
934
848
|
|
|
935
849
|
remote_file = host.get_fact(File, path=dest)
|
|
936
850
|
|
|
937
|
-
if not remote_file and host.get_fact(Directory, path=dest):
|
|
851
|
+
if not remote_file and bool(host.get_fact(Directory, path=dest)):
|
|
938
852
|
dest = unix_path_join(dest, os.path.basename(src))
|
|
939
853
|
remote_file = host.get_fact(File, path=dest)
|
|
940
854
|
|
|
941
855
|
if create_remote_dir:
|
|
942
|
-
yield from _create_remote_dir(
|
|
856
|
+
yield from _create_remote_dir(dest, user, group)
|
|
943
857
|
|
|
944
858
|
# No remote file, always upload and user/group/mode if supplied
|
|
945
859
|
if not remote_file or force:
|
|
946
860
|
yield FileUploadCommand(
|
|
947
861
|
local_file,
|
|
948
862
|
dest,
|
|
949
|
-
remote_temp_filename=
|
|
863
|
+
remote_temp_filename=host.get_temp_filename(dest),
|
|
950
864
|
)
|
|
951
865
|
|
|
952
866
|
if user or group:
|
|
@@ -964,7 +878,7 @@ def put(
|
|
|
964
878
|
yield FileUploadCommand(
|
|
965
879
|
local_file,
|
|
966
880
|
dest,
|
|
967
|
-
remote_temp_filename=
|
|
881
|
+
remote_temp_filename=host.get_temp_filename(dest),
|
|
968
882
|
)
|
|
969
883
|
|
|
970
884
|
if user or group:
|
|
@@ -989,16 +903,8 @@ def put(
|
|
|
989
903
|
if not changed:
|
|
990
904
|
host.noop("file {0} is already uploaded".format(dest))
|
|
991
905
|
|
|
992
|
-
# Now we've uploaded the file and ensured user/group/mode, update the relevant fact data
|
|
993
|
-
host.create_fact(Sha1File, kwargs={"path": dest}, data=local_sum)
|
|
994
|
-
host.create_fact(
|
|
995
|
-
File,
|
|
996
|
-
kwargs={"path": dest},
|
|
997
|
-
data={"user": user, "group": group, "mode": mode},
|
|
998
|
-
)
|
|
999
|
-
|
|
1000
906
|
|
|
1001
|
-
@operation
|
|
907
|
+
@operation()
|
|
1002
908
|
def template(src, dest, user=None, group=None, mode=None, create_remote_dir=True, **data):
|
|
1003
909
|
'''
|
|
1004
910
|
Generate a template using jinja2 and write it to the remote system.
|
|
@@ -1081,23 +987,21 @@ def template(src, dest, user=None, group=None, mode=None, create_remote_dir=True
|
|
|
1081
987
|
data.setdefault("host", host)
|
|
1082
988
|
data.setdefault("state", state)
|
|
1083
989
|
data.setdefault("inventory", state.inventory)
|
|
1084
|
-
data.setdefault("facts", pyinfra.facts)
|
|
1085
990
|
|
|
1086
991
|
# Render and make file-like it's output
|
|
1087
992
|
try:
|
|
1088
993
|
output = get_template(src).render(data)
|
|
1089
994
|
except (TemplateRuntimeError, TemplateSyntaxError, UndefinedError) as e:
|
|
1090
|
-
trace_frames = traceback.extract_tb(sys.exc_info()[2])
|
|
1091
995
|
trace_frames = [
|
|
1092
996
|
frame
|
|
1093
|
-
for frame in
|
|
997
|
+
for frame in traceback.extract_tb(sys.exc_info()[2])
|
|
1094
998
|
if frame[2] in ("template", "<module>", "top-level template code")
|
|
1095
999
|
] # thank you https://github.com/saltstack/salt/blob/master/salt/utils/templates.py
|
|
1096
1000
|
|
|
1097
1001
|
line_number = trace_frames[-1][1]
|
|
1098
1002
|
|
|
1099
1003
|
# Quickly read the line in question and one above/below for nicer debugging
|
|
1100
|
-
with
|
|
1004
|
+
with get_file_io(src, "r") as f:
|
|
1101
1005
|
template_lines = f.readlines()
|
|
1102
1006
|
|
|
1103
1007
|
template_lines = [line.strip() for line in template_lines]
|
|
@@ -1110,16 +1014,16 @@ def template(src, dest, user=None, group=None, mode=None, create_remote_dir=True
|
|
|
1110
1014
|
e,
|
|
1111
1015
|
"\n".join(relevant_lines),
|
|
1112
1016
|
),
|
|
1113
|
-
)
|
|
1017
|
+
) from None
|
|
1114
1018
|
|
|
1115
1019
|
output_file = StringIO(output)
|
|
1116
1020
|
# Set the template attribute for nicer debugging
|
|
1117
|
-
output_file.template = src
|
|
1021
|
+
output_file.template = src # type: ignore[attr-defined]
|
|
1118
1022
|
|
|
1119
1023
|
# Pass to the put function
|
|
1120
|
-
yield from put(
|
|
1121
|
-
output_file,
|
|
1122
|
-
dest,
|
|
1024
|
+
yield from put._inner(
|
|
1025
|
+
src=output_file,
|
|
1026
|
+
dest=dest,
|
|
1123
1027
|
user=user,
|
|
1124
1028
|
group=group,
|
|
1125
1029
|
mode=mode,
|
|
@@ -1149,14 +1053,11 @@ def _raise_or_remove_invalid_path(fs_type, path, force, force_backup, force_back
|
|
|
1149
1053
|
raise OperationError("{0} exists and is not a {1}".format(path, fs_type))
|
|
1150
1054
|
|
|
1151
1055
|
|
|
1152
|
-
@operation(
|
|
1153
|
-
pipeline_facts={"link": "path"},
|
|
1154
|
-
)
|
|
1056
|
+
@operation()
|
|
1155
1057
|
def link(
|
|
1156
1058
|
path,
|
|
1157
1059
|
target=None,
|
|
1158
1060
|
present=True,
|
|
1159
|
-
assume_present=False,
|
|
1160
1061
|
user=None,
|
|
1161
1062
|
group=None,
|
|
1162
1063
|
symbolic=True,
|
|
@@ -1171,7 +1072,6 @@ def link(
|
|
|
1171
1072
|
+ path: the name of the link
|
|
1172
1073
|
+ target: the file/directory the link points to
|
|
1173
1074
|
+ present: whether the link should exist
|
|
1174
|
-
+ assume_present: whether to assume the link exists
|
|
1175
1075
|
+ user: user to own the link
|
|
1176
1076
|
+ group: group to own the link
|
|
1177
1077
|
+ symbolic: whether to make a symbolic link (vs hard link)
|
|
@@ -1198,22 +1098,6 @@ def link(
|
|
|
1198
1098
|
path="/etc/issue2",
|
|
1199
1099
|
target="/etc/issue",
|
|
1200
1100
|
)
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
# Complex example demonstrating the assume_present option
|
|
1204
|
-
from pyinfra.operations import apt, files
|
|
1205
|
-
|
|
1206
|
-
install_nginx = apt.packages(
|
|
1207
|
-
name="Install nginx",
|
|
1208
|
-
packages=["nginx"],
|
|
1209
|
-
)
|
|
1210
|
-
|
|
1211
|
-
files.link(
|
|
1212
|
-
name="Remove default nginx site",
|
|
1213
|
-
path="/etc/nginx/sites-enabled/default",
|
|
1214
|
-
present=False,
|
|
1215
|
-
assume_present=install_nginx.changed,
|
|
1216
|
-
)
|
|
1217
1101
|
"""
|
|
1218
1102
|
|
|
1219
1103
|
path = _validate_path(path)
|
|
@@ -1223,8 +1107,7 @@ def link(
|
|
|
1223
1107
|
|
|
1224
1108
|
info = host.get_fact(Link, path=path)
|
|
1225
1109
|
|
|
1226
|
-
#
|
|
1227
|
-
if info is False:
|
|
1110
|
+
if info is False: # not a link
|
|
1228
1111
|
yield from _raise_or_remove_invalid_path(
|
|
1229
1112
|
"link",
|
|
1230
1113
|
path,
|
|
@@ -1238,49 +1121,28 @@ def link(
|
|
|
1238
1121
|
if symbolic:
|
|
1239
1122
|
add_args.append("-s")
|
|
1240
1123
|
|
|
1241
|
-
add_cmd = StringCommand(" ".join(add_args), QuoteString(target), QuoteString(path))
|
|
1242
1124
|
remove_cmd = StringCommand("rm", "-f", QuoteString(path))
|
|
1243
1125
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1126
|
+
if not present:
|
|
1127
|
+
if info:
|
|
1128
|
+
yield remove_cmd
|
|
1129
|
+
else:
|
|
1130
|
+
host.noop("link {link} does not exist")
|
|
1131
|
+
return
|
|
1132
|
+
|
|
1133
|
+
assert target is not None # appease typing QuoteString below
|
|
1134
|
+
add_cmd = StringCommand(" ".join(add_args), QuoteString(target), QuoteString(path))
|
|
1135
|
+
|
|
1136
|
+
if info is None: # create
|
|
1246
1137
|
if create_remote_dir:
|
|
1247
|
-
yield from _create_remote_dir(
|
|
1138
|
+
yield from _create_remote_dir(path, user, group)
|
|
1248
1139
|
|
|
1249
1140
|
yield add_cmd
|
|
1250
1141
|
|
|
1251
1142
|
if user or group:
|
|
1252
1143
|
yield file_utils.chown(path, user, group, dereference=False)
|
|
1253
1144
|
|
|
1254
|
-
|
|
1255
|
-
Link,
|
|
1256
|
-
kwargs={"path": path},
|
|
1257
|
-
data={"link_target": target, "group": group, "user": user},
|
|
1258
|
-
)
|
|
1259
|
-
|
|
1260
|
-
# It exists and we don't want it
|
|
1261
|
-
elif (assume_present or info) and not present:
|
|
1262
|
-
yield remove_cmd
|
|
1263
|
-
host.delete_fact(Link, kwargs={"path": path})
|
|
1264
|
-
|
|
1265
|
-
# Exists and want to ensure it's state
|
|
1266
|
-
elif (assume_present or info) and present:
|
|
1267
|
-
if assume_present and not info:
|
|
1268
|
-
info = {"link_target": None, "group": None, "user": None}
|
|
1269
|
-
host.create_fact(Link, kwargs={"path": path}, data=info)
|
|
1270
|
-
|
|
1271
|
-
# If we have an absolute path - prepend to any non-absolute values from the fact
|
|
1272
|
-
# and/or the source.
|
|
1273
|
-
if os.path.isabs(path):
|
|
1274
|
-
link_dirname = os.path.dirname(path)
|
|
1275
|
-
|
|
1276
|
-
if not os.path.isabs(target):
|
|
1277
|
-
target = os.path.normpath(unix_path_join(link_dirname, target))
|
|
1278
|
-
|
|
1279
|
-
if info and not os.path.isabs(info["link_target"]):
|
|
1280
|
-
info["link_target"] = os.path.normpath(
|
|
1281
|
-
unix_path_join(link_dirname, info["link_target"]),
|
|
1282
|
-
)
|
|
1283
|
-
|
|
1145
|
+
else: # edit
|
|
1284
1146
|
changed = False
|
|
1285
1147
|
|
|
1286
1148
|
# If the target is wrong, remove & recreate the link
|
|
@@ -1288,32 +1150,20 @@ def link(
|
|
|
1288
1150
|
changed = True
|
|
1289
1151
|
yield remove_cmd
|
|
1290
1152
|
yield add_cmd
|
|
1291
|
-
info["link_target"] = target
|
|
1292
1153
|
|
|
1293
1154
|
# Check user/group
|
|
1294
|
-
if (
|
|
1295
|
-
(not info and (user or group))
|
|
1296
|
-
or (user and info["user"] != user)
|
|
1297
|
-
or (group and info["group"] != group)
|
|
1298
|
-
):
|
|
1155
|
+
if (user and info["user"] != user) or (group and info["group"] != group):
|
|
1299
1156
|
yield file_utils.chown(path, user, group, dereference=False)
|
|
1300
1157
|
changed = True
|
|
1301
|
-
if user:
|
|
1302
|
-
info["user"] = user
|
|
1303
|
-
if group:
|
|
1304
|
-
info["group"] = group
|
|
1305
1158
|
|
|
1306
1159
|
if not changed:
|
|
1307
1160
|
host.noop("link {0} already exists".format(path))
|
|
1308
1161
|
|
|
1309
1162
|
|
|
1310
|
-
@operation(
|
|
1311
|
-
pipeline_facts={"file": "path"},
|
|
1312
|
-
)
|
|
1163
|
+
@operation()
|
|
1313
1164
|
def file(
|
|
1314
1165
|
path,
|
|
1315
1166
|
present=True,
|
|
1316
|
-
assume_present=False,
|
|
1317
1167
|
user=None,
|
|
1318
1168
|
group=None,
|
|
1319
1169
|
mode=None,
|
|
@@ -1328,7 +1178,6 @@ def file(
|
|
|
1328
1178
|
|
|
1329
1179
|
+ path: name/path of the remote file
|
|
1330
1180
|
+ present: whether the file should exist
|
|
1331
|
-
+ assume_present: whether to assume the file exists
|
|
1332
1181
|
+ user: user to own the files
|
|
1333
1182
|
+ group: group to own the files
|
|
1334
1183
|
+ mode: permissions of the files as an integer, eg: 755
|
|
@@ -1364,8 +1213,7 @@ def file(
|
|
|
1364
1213
|
mode = ensure_mode_int(mode)
|
|
1365
1214
|
info = host.get_fact(File, path=path)
|
|
1366
1215
|
|
|
1367
|
-
#
|
|
1368
|
-
if info is False:
|
|
1216
|
+
if info is False: # not a file
|
|
1369
1217
|
yield from _raise_or_remove_invalid_path(
|
|
1370
1218
|
"file",
|
|
1371
1219
|
path,
|
|
@@ -1375,10 +1223,16 @@ def file(
|
|
|
1375
1223
|
)
|
|
1376
1224
|
info = None
|
|
1377
1225
|
|
|
1378
|
-
|
|
1379
|
-
|
|
1226
|
+
if not present:
|
|
1227
|
+
if info:
|
|
1228
|
+
yield StringCommand("rm", "-f", QuoteString(path))
|
|
1229
|
+
else:
|
|
1230
|
+
host.noop("file {0} does not exist")
|
|
1231
|
+
return
|
|
1232
|
+
|
|
1233
|
+
if info is None: # create
|
|
1380
1234
|
if create_remote_dir:
|
|
1381
|
-
yield from _create_remote_dir(
|
|
1235
|
+
yield from _create_remote_dir(path, user, group)
|
|
1382
1236
|
|
|
1383
1237
|
yield StringCommand("touch", QuoteString(path))
|
|
1384
1238
|
|
|
@@ -1387,23 +1241,7 @@ def file(
|
|
|
1387
1241
|
if user or group:
|
|
1388
1242
|
yield file_utils.chown(path, user, group)
|
|
1389
1243
|
|
|
1390
|
-
|
|
1391
|
-
File,
|
|
1392
|
-
kwargs={"path": path},
|
|
1393
|
-
data={"mode": mode, "group": group, "user": user},
|
|
1394
|
-
)
|
|
1395
|
-
|
|
1396
|
-
# It exists and we don't want it
|
|
1397
|
-
elif (assume_present or info) and not present:
|
|
1398
|
-
yield StringCommand("rm", "-f", QuoteString(path))
|
|
1399
|
-
host.delete_fact(File, kwargs={"path": path})
|
|
1400
|
-
|
|
1401
|
-
# It exists & we want to ensure its state
|
|
1402
|
-
elif (assume_present or info) and present:
|
|
1403
|
-
if assume_present and not info:
|
|
1404
|
-
info = {"mode": None, "group": None, "user": None}
|
|
1405
|
-
host.create_fact(File, kwargs={"path": path}, data=info)
|
|
1406
|
-
|
|
1244
|
+
else: # update
|
|
1407
1245
|
changed = False
|
|
1408
1246
|
|
|
1409
1247
|
if touch:
|
|
@@ -1413,33 +1251,21 @@ def file(
|
|
|
1413
1251
|
# Check mode
|
|
1414
1252
|
if mode and (not info or info["mode"] != mode):
|
|
1415
1253
|
yield file_utils.chmod(path, mode)
|
|
1416
|
-
info["mode"] = mode
|
|
1417
1254
|
changed = True
|
|
1418
1255
|
|
|
1419
1256
|
# Check user/group
|
|
1420
|
-
if (
|
|
1421
|
-
(not info and (user or group))
|
|
1422
|
-
or (user and info["user"] != user)
|
|
1423
|
-
or (group and info["group"] != group)
|
|
1424
|
-
):
|
|
1257
|
+
if (user and info["user"] != user) or (group and info["group"] != group):
|
|
1425
1258
|
yield file_utils.chown(path, user, group)
|
|
1426
1259
|
changed = True
|
|
1427
|
-
if user:
|
|
1428
|
-
info["user"] = user
|
|
1429
|
-
if group:
|
|
1430
|
-
info["group"] = group
|
|
1431
1260
|
|
|
1432
1261
|
if not changed:
|
|
1433
1262
|
host.noop("file {0} already exists".format(path))
|
|
1434
1263
|
|
|
1435
1264
|
|
|
1436
|
-
@operation(
|
|
1437
|
-
pipeline_facts={"directory": "path"},
|
|
1438
|
-
)
|
|
1265
|
+
@operation()
|
|
1439
1266
|
def directory(
|
|
1440
1267
|
path,
|
|
1441
1268
|
present=True,
|
|
1442
|
-
assume_present=False,
|
|
1443
1269
|
user=None,
|
|
1444
1270
|
group=None,
|
|
1445
1271
|
mode=None,
|
|
@@ -1455,7 +1281,6 @@ def directory(
|
|
|
1455
1281
|
|
|
1456
1282
|
+ path: path of the remote folder
|
|
1457
1283
|
+ present: whether the folder should exist
|
|
1458
|
-
+ assume_present: whether to assume the directory exists
|
|
1459
1284
|
+ user: user to own the folder
|
|
1460
1285
|
+ group: group to own the folder
|
|
1461
1286
|
+ mode: permissions of the folder
|
|
@@ -1494,8 +1319,7 @@ def directory(
|
|
|
1494
1319
|
mode = ensure_mode_int(mode)
|
|
1495
1320
|
info = host.get_fact(Directory, path=path)
|
|
1496
1321
|
|
|
1497
|
-
#
|
|
1498
|
-
if info is False:
|
|
1322
|
+
if info is False: # not a directory
|
|
1499
1323
|
if _no_fail_on_link and host.get_fact(Link, path=path):
|
|
1500
1324
|
host.noop("directory {0} already exists (as a link)".format(path))
|
|
1501
1325
|
return
|
|
@@ -1508,31 +1332,21 @@ def directory(
|
|
|
1508
1332
|
)
|
|
1509
1333
|
info = None
|
|
1510
1334
|
|
|
1511
|
-
|
|
1512
|
-
|
|
1335
|
+
if not present:
|
|
1336
|
+
if info:
|
|
1337
|
+
yield StringCommand("rm", "-rf", QuoteString(path))
|
|
1338
|
+
else:
|
|
1339
|
+
host.noop("directory {0} does not exist")
|
|
1340
|
+
return
|
|
1341
|
+
|
|
1342
|
+
if info is None: # create
|
|
1513
1343
|
yield StringCommand("mkdir", "-p", QuoteString(path))
|
|
1514
1344
|
if mode:
|
|
1515
1345
|
yield file_utils.chmod(path, mode, recursive=recursive)
|
|
1516
1346
|
if user or group:
|
|
1517
1347
|
yield file_utils.chown(path, user, group, recursive=recursive)
|
|
1518
1348
|
|
|
1519
|
-
|
|
1520
|
-
Directory,
|
|
1521
|
-
kwargs={"path": path},
|
|
1522
|
-
data={"mode": mode, "group": group, "user": user},
|
|
1523
|
-
)
|
|
1524
|
-
|
|
1525
|
-
# It exists and we don't want it
|
|
1526
|
-
elif (assume_present or info) and not present:
|
|
1527
|
-
yield StringCommand("rm", "-rf", QuoteString(path))
|
|
1528
|
-
host.delete_fact(Directory, kwargs={"path": path})
|
|
1529
|
-
|
|
1530
|
-
# It exists & we want to ensure its state
|
|
1531
|
-
elif (assume_present or info) and present:
|
|
1532
|
-
if assume_present and not info:
|
|
1533
|
-
info = {"mode": None, "group": None, "user": None}
|
|
1534
|
-
host.create_fact(Directory, kwargs={"path": path}, data=info)
|
|
1535
|
-
|
|
1349
|
+
else: # update
|
|
1536
1350
|
if _no_check_owner_mode:
|
|
1537
1351
|
return
|
|
1538
1352
|
|
|
@@ -1540,26 +1354,17 @@ def directory(
|
|
|
1540
1354
|
|
|
1541
1355
|
if mode and (not info or info["mode"] != mode):
|
|
1542
1356
|
yield file_utils.chmod(path, mode, recursive=recursive)
|
|
1543
|
-
info["mode"] = mode
|
|
1544
1357
|
changed = True
|
|
1545
1358
|
|
|
1546
|
-
if (
|
|
1547
|
-
(not info and (user or group))
|
|
1548
|
-
or (user and info["user"] != user)
|
|
1549
|
-
or (group and info["group"] != group)
|
|
1550
|
-
):
|
|
1359
|
+
if (user and info["user"] != user) or (group and info["group"] != group):
|
|
1551
1360
|
yield file_utils.chown(path, user, group, recursive=recursive)
|
|
1552
1361
|
changed = True
|
|
1553
|
-
if user:
|
|
1554
|
-
info["user"] = user
|
|
1555
|
-
if group:
|
|
1556
|
-
info["group"] = group
|
|
1557
1362
|
|
|
1558
1363
|
if not changed:
|
|
1559
1364
|
host.noop("directory {0} already exists".format(path))
|
|
1560
1365
|
|
|
1561
1366
|
|
|
1562
|
-
@operation(
|
|
1367
|
+
@operation()
|
|
1563
1368
|
def flags(path, flags=None, present=True):
|
|
1564
1369
|
"""
|
|
1565
1370
|
Set/clear file flags.
|
|
@@ -1601,22 +1406,13 @@ def flags(path, flags=None, present=True):
|
|
|
1601
1406
|
prefix = "" if present else "no"
|
|
1602
1407
|
new_flags = ",".join([prefix + flag for flag in sorted(to_change)])
|
|
1603
1408
|
yield StringCommand("chflags", new_flags, QuoteString(path))
|
|
1604
|
-
host.create_fact(
|
|
1605
|
-
Flags,
|
|
1606
|
-
kwargs={"path": path},
|
|
1607
|
-
data=list(current_set | set(to_change))
|
|
1608
|
-
if present
|
|
1609
|
-
else list(current_set - set(to_change)),
|
|
1610
|
-
)
|
|
1611
1409
|
else:
|
|
1612
1410
|
host.noop(
|
|
1613
1411
|
f'\'{path}\' already has \'{",".join(flags)}\' {"set" if present else "clear"}',
|
|
1614
1412
|
)
|
|
1615
1413
|
|
|
1616
1414
|
|
|
1617
|
-
@operation(
|
|
1618
|
-
pipeline_facts={"file": "path"},
|
|
1619
|
-
)
|
|
1415
|
+
@operation()
|
|
1620
1416
|
def block(
|
|
1621
1417
|
path,
|
|
1622
1418
|
content=None,
|
|
@@ -1718,7 +1514,7 @@ def block(
|
|
|
1718
1514
|
# standard awk doesn't have an "in-place edit" option so we write to a tempfile and
|
|
1719
1515
|
# if edits were successful move to dest i.e. we do: <out_prep> ... do some work ... <real_out>
|
|
1720
1516
|
q_path = QuoteString(path)
|
|
1721
|
-
out_prep = 'OUT="$(TMPDIR=/tmp mktemp -t pyinfra.XXXXXX)" && '
|
|
1517
|
+
out_prep = StringCommand('OUT="$(TMPDIR=/tmp mktemp -t pyinfra.XXXXXX)" && ')
|
|
1722
1518
|
if backup:
|
|
1723
1519
|
out_prep = StringCommand(
|
|
1724
1520
|
"cp",
|
|
@@ -1816,11 +1612,6 @@ def block(
|
|
|
1816
1612
|
|
|
1817
1613
|
if cmd:
|
|
1818
1614
|
yield cmd
|
|
1819
|
-
host.create_fact(
|
|
1820
|
-
Block,
|
|
1821
|
-
kwargs={"path": path, "marker": marker, "begin": begin, "end": end},
|
|
1822
|
-
data=content,
|
|
1823
|
-
)
|
|
1824
1615
|
else: # remove the marked_block
|
|
1825
1616
|
if content:
|
|
1826
1617
|
logger.warning("'content' ignored when removing a marked_block")
|
|
@@ -1829,9 +1620,5 @@ def block(
|
|
|
1829
1620
|
elif current == []:
|
|
1830
1621
|
host.noop("no remove required: markers not found")
|
|
1831
1622
|
else:
|
|
1832
|
-
cmd = f"awk '/{mark_1}/,/{mark_2}/ {{next}} 1'"
|
|
1623
|
+
cmd = StringCommand(f"awk '/{mark_1}/,/{mark_2}/ {{next}} 1'")
|
|
1833
1624
|
yield StringCommand(out_prep, cmd, q_path, "> $OUT &&", real_out)
|
|
1834
|
-
host.delete_fact(
|
|
1835
|
-
Block,
|
|
1836
|
-
kwargs={"path": path, "marker": marker, "begin": begin, "end": end},
|
|
1837
|
-
)
|