Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 11 additions & 21 deletions src/pyinfra/operations/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -1925,7 +1925,8 @@ def block(
+ line: regex before or after which the content should be added if it doesn't exist.
+ backup: whether to backup the file (see ``files.line``). Default False.
+ escape_regex_characters: whether to escape regex characters from the matching line
+ try_prevent_shell_expansion: tries to prevent shell expanding by values like `$`
+ try_prevent_shell_expansion: deprecated and ignored; ``content`` is always written
literally (no shell expansion) and is safely shell-quoted
+ marker: the base string used to mark the text. Default is ``# {mark} PYINFRA BLOCK``
+ begin: the value for ``{mark}`` in the marker before the content. Default is ``BEGIN``
+ end: the value for ``{mark}`` in the marker after the content. Default is ``END``
Expand All @@ -1945,8 +1946,9 @@ def block(

Removal ignores ``content`` and ``line``

Preventing shell expansion works by wrapping the content in '`' before passing to `awk`.
WARNING: This will break if the content contains raw single quotes.
``content`` is written to the file verbatim. It is shell-quoted before being passed to
``awk``, so shell metacharacters (``$(...)``, quotes, backticks) are kept literal and never
expanded on the remote host.

**Examples:**

Expand Down Expand Up @@ -1987,11 +1989,10 @@ def block(
marker="<!-- {mark} PYINFRA BLOCK -->",
)

# put complex alias into .zshrc
# put complex alias into .zshrc (written literally, no shell expansion)
files.block(
path="/home/user/.zshrc",
content="eval $(thef -a)",
try_prevent_shell_expansion=True,
marker="## {mark} ALIASES ##"
)
"""
Expand Down Expand Up @@ -2068,15 +2069,8 @@ def block(
# convert string to list of lines
content = content.split("\n")

the_block = "\n".join([mark_1, *content, mark_2])
if try_prevent_shell_expansion:
the_block = f"'{the_block}'"
if any("'" in line for line in content):
logger.warning(
"content contains single quotes, shell expansion prevention may fail"
)
else:
the_block = f'"{the_block}"'
block_with_markers = "\n".join([mark_1, *content, mark_2])
block_content = "\n".join(content)

if (current is None) or ((current == []) and (before == after)):
# a) no file or b) file but no markers and we're adding at start or end.
Expand All @@ -2090,7 +2084,7 @@ def block(
original if not before else " - ",
original if before else " - ",
'> "$OUT"',
f"<<{here}\n{the_block[1:-1]}\n{here}\n",
f"<<'{here}'\n{block_with_markers}\n{here}\n",
")",
real_out,
)
Expand All @@ -2109,7 +2103,7 @@ def block(
out_prep,
prog,
q_path,
the_block,
QuoteString(block_with_markers),
'> "$OUT"',
real_out,
)
Expand All @@ -2125,11 +2119,7 @@ def block(
out_prep,
prog,
q_path,
(
'"' + "\n".join(content) + '"'
if not try_prevent_shell_expansion
else "'" + "\n".join(content) + "'"
),
QuoteString(block_content),
'> "$OUT"',
real_out,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
}
},
"commands": [
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && MODE=\"$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && awk 'BEGIN {{f=1; x=ARGV[2]; ARGV[2]=\"\"}}/# BEGIN PYINFRA BLOCK/ {print; print x; f=0} /# END PYINFRA BLOCK/ {print; f=1; next} f' /home/someone/something \"should be this\" > \"$OUT\" && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something && chmod \"$MODE\" /home/someone/something"
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && MODE=\"$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && awk 'BEGIN {{f=1; x=ARGV[2]; ARGV[2]=\"\"}}/# BEGIN PYINFRA BLOCK/ {print; print x; f=0} /# END PYINFRA BLOCK/ {print; f=1; next} f' /home/someone/something 'should be this' > \"$OUT\" && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something && chmod \"$MODE\" /home/someone/something"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
}
},
"commands": [
"cp /home/someone/something /home/someone/something.a-timestamp && OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && MODE=\"$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && awk 'BEGIN {{f=1; x=ARGV[2]; ARGV[2]=\"\"}}/# BEGIN PYINFRA BLOCK/ {print; print x; f=0} /# END PYINFRA BLOCK/ {print; f=1; next} f' /home/someone/something \"should be this\" > \"$OUT\" && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something && chmod \"$MODE\" /home/someone/something"
"cp /home/someone/something /home/someone/something.a-timestamp && OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && MODE=\"$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && awk 'BEGIN {{f=1; x=ARGV[2]; ARGV[2]=\"\"}}/# BEGIN PYINFRA BLOCK/ {print; print x; f=0} /# END PYINFRA BLOCK/ {print; f=1; next} f' /home/someone/something 'should be this' > \"$OUT\" && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something && chmod \"$MODE\" /home/someone/something"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@
}
},
"commands": [
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && MODE=\"$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && awk 'BEGIN {{f=1; x=ARGV[2]; ARGV[2]=\"\"}}/# BEGIN PYINFRA BLOCK/ {print; print x; f=0} /# END PYINFRA BLOCK/ {print; f=1; next} f' /home/someone/something \"should be this\nand this\nand even this\" > \"$OUT\" && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something && chmod \"$MODE\" /home/someone/something"
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && MODE=\"$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && awk 'BEGIN {{f=1; x=ARGV[2]; ARGV[2]=\"\"}}/# BEGIN PYINFRA BLOCK/ {print; print x; f=0} /# END PYINFRA BLOCK/ {print; f=1; next} f' /home/someone/something 'should be this\nand this\nand even this' > \"$OUT\" && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something && chmod \"$MODE\" /home/someone/something"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
}
},
"commands": [
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && ( awk '{{print}}' - /dev/null > \"$OUT\" <<PYINFRAHERE\n# BEGIN PYINFRA BLOCK\nplease add this\n# END PYINFRA BLOCK\nPYINFRAHERE\n ) && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something /home/someone/something"
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && ( awk '{{print}}' - /dev/null > \"$OUT\" <<'PYINFRAHERE'\n# BEGIN PYINFRA BLOCK\nplease add this\n# END PYINFRA BLOCK\nPYINFRAHERE\n ) && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something /home/someone/something"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
}
},
"commands": [
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && MODE=\"$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && awk 'BEGIN {x=ARGV[2]; ARGV[2]=\"\"} f!=1 && /^.*before this.*$/ { print x; f=1} END {if (f==0) print x } { print }' /home/someone/something \"# BEGIN PYINFRA BLOCK\nplease add this\n# END PYINFRA BLOCK\" > \"$OUT\" && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something && chmod \"$MODE\" /home/someone/something"
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && MODE=\"$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && awk 'BEGIN {x=ARGV[2]; ARGV[2]=\"\"} f!=1 && /^.*before this.*$/ { print x; f=1} END {if (f==0) print x } { print }' /home/someone/something '# BEGIN PYINFRA BLOCK\nplease add this\n# END PYINFRA BLOCK' > \"$OUT\" && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something && chmod \"$MODE\" /home/someone/something"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
}
},
"commands": [
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && MODE=\"$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && awk 'BEGIN {x=ARGV[2]; ARGV[2]=\"\"} f!=1 && /^.*before this \\*.*$/ { print x; f=1} END {if (f==0) print x } { print }' /home/someone/something \"# BEGIN PYINFRA BLOCK\nplease add this\n# END PYINFRA BLOCK\" > \"$OUT\" && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something && chmod \"$MODE\" /home/someone/something"
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && MODE=\"$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && awk 'BEGIN {x=ARGV[2]; ARGV[2]=\"\"} f!=1 && /^.*before this \\*.*$/ { print x; f=1} END {if (f==0) print x } { print }' /home/someone/something '# BEGIN PYINFRA BLOCK\nplease add this\n# END PYINFRA BLOCK' > \"$OUT\" && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something && chmod \"$MODE\" /home/someone/something"
]
}
2 changes: 1 addition & 1 deletion tests/operations/files.block/add_no_existing_file.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
}
},
"commands": [
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && ( awk '{{print}}' /dev/null - > \"$OUT\" <<PYINFRAHERE\n# BEGIN PYINFRA BLOCK\nplease add this\n# END PYINFRA BLOCK\nPYINFRAHERE\n ) && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something /home/someone/something"
"OUT=\"$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)\" && OWNER=\"$(stat -c \"%u:%g\" /home/someone/something 2>/dev/null || stat -f \"%u:%g\" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))\" && ( awk '{{print}}' /dev/null - > \"$OUT\" <<'PYINFRAHERE'\n# BEGIN PYINFRA BLOCK\nplease add this\n# END PYINFRA BLOCK\nPYINFRAHERE\n ) && mv \"$OUT\" /home/someone/something && chown \"$OWNER\" /home/someone/something /home/someone/something"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require_platform:
- Darwin
- Linux
args:
- /home/someone/something
kwargs:
content: |-
alias l="lsd -la"
export _ZO_ECHO='1'
eval "$(zoxide init --cmd cd bash)"
line: before this
before: true
facts:
files.Block:
begin=None, end=None, marker=None, path=/home/someone/something: []
commands:
- |-
OUT="$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)" && MODE="$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)" && OWNER="$(stat -c "%u:%g" /home/someone/something 2>/dev/null || stat -f "%u:%g" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))" && awk 'BEGIN {x=ARGV[2]; ARGV[2]=""} f!=1 && /^.*before this.*$/ { print x; f=1} END {if (f==0) print x } { print }' /home/someone/something '# BEGIN PYINFRA BLOCK
alias l="lsd -la"
export _ZO_ECHO='"'"'1'"'"'
eval "$(zoxide init --cmd cd bash)"
# END PYINFRA BLOCK' > "$OUT" && mv "$OUT" /home/someone/something && chown "$OWNER" /home/someone/something && chmod "$MODE" /home/someone/something
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require_platform:
- Darwin
- Linux
args:
- /home/someone/something
kwargs:
content: |-
alias l="lsd -la"
export _ZO_ECHO='1'
eval "$(zoxide init --cmd cd bash)"
before: false
after: false
facts:
files.Block:
begin=None, end=None, marker=None, path=/home/someone/something: null
commands:
- |-
OUT="$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)" && OWNER="$(stat -c "%u:%g" /home/someone/something 2>/dev/null || stat -f "%u:%g" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))" && ( awk '{{print}}' /dev/null - > "$OUT" <<'PYINFRAHERE'
# BEGIN PYINFRA BLOCK
alias l="lsd -la"
export _ZO_ECHO='1'
eval "$(zoxide init --cmd cd bash)"
# END PYINFRA BLOCK
PYINFRAHERE
) && mv "$OUT" /home/someone/something && chown "$OWNER" /home/someone/something /home/someone/something
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require_platform:
- Darwin
- Linux
args:
- /home/someone/something
kwargs:
content: |-
alias l="lsd -la"
export _ZO_ECHO='1'
eval "$(zoxide init --cmd cd bash)"
line: before this
before: true
facts:
files.Block:
begin=None, end=None, marker=None, path=/home/someone/something:
- previously was something else
commands:
- |-
OUT="$(TMPDIR=_tempdir_ mktemp -t pyinfra.XXXXXX)" && MODE="$(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something 2>/dev/null)" && OWNER="$(stat -c "%u:%g" /home/someone/something 2>/dev/null || stat -f "%u:%g" /home/someone/something 2>/dev/null || echo $(id -un):$(id -gn))" && awk 'BEGIN {{f=1; x=ARGV[2]; ARGV[2]=""}}/# BEGIN PYINFRA BLOCK/ {print; print x; f=0} /# END PYINFRA BLOCK/ {print; f=1; next} f' /home/someone/something 'alias l="lsd -la"
export _ZO_ECHO='"'"'1'"'"'
eval "$(zoxide init --cmd cd bash)"' > "$OUT" && mv "$OUT" /home/someone/something && chown "$OWNER" /home/someone/something && chmod "$MODE" /home/someone/something
Loading