Repository: pyinfra-dev/pyinfra

Issue:
files.block is not working as expected when path exists and line missing
files.block is not working as expected

## Describe the bug
The document (both 2x and next) says:
```
Content appended if line not found in the file
If content is not in the file but is required (present=True) and line is not found in the file, content (surrounded by markers) will be appended to the file. The file is created if necessary.
```
**But in the case of the actual empty file, there is no addition.**

## To Reproduce
Steps to reproduce the behavior, please include where possible:

```python
from pyinfra.operations import files

files.block(
    name="Block Test",
    path="test.txt",
    line="foo",
    content="bar",
    present=True,
    after=True,
)
```

```shell
$ rm test.txt
$ touch test.txt
$ pyinfra @local test.py
```

```
$ cat test.txt #just empty line

```

## Expected behavior

```
$ cat test.txt
# BEGIN PYINFRA BLOCK
bar
# END PYINFRA BLOCK
```

## Meta
+ Include output of `pyinfra --support`.
```

    If you are having issues with pyinfra or wish to make feature requests, please
    check out the GitHub issues at https://github.com/Fizzadar/pyinfra/issues .
    When adding an issue, be sure to include the following:

    System: Darwin
      Platform: macOS-14.0-x86_64-i386-64bit
      Release: 23.0.0
      Machine: x86_64
    pyinfra: v3.0b0
    Executable: /Users/who/OneClick/LunaticDaemon/.venv/bin/pyinfra
    Python: 3.11.7 (CPython, Clang 15.0.0 (clang-1500.1.0.2.5))
```
+ How was pyinfra installed (source/pip)?
`pip`
+ Include pyinfra-debug.log (if one was created)
`None`
+ Consider including output with `-vv` and `--debug`.



Discussion:

Patch:
diff --git a/pyinfra/operations/files.py b/pyinfra/operations/files.py
index b17c55626..0b47a22ec 100644
--- a/pyinfra/operations/files.py
+++ b/pyinfra/operations/files.py
@@ -1789,6 +1789,7 @@ def block(
     )
 
     current = host.get_fact(Block, path=path, marker=marker, begin=begin, end=end)
+    # None means file didn't exist, empty list means marker was not found
     cmd = None
     if present:
         if not content:
@@ -1830,7 +1831,7 @@ def block(
             prog = (
                 'awk \'BEGIN {x=ARGV[2]; ARGV[2]=""} '
                 f"{print_after} f!=1 && /{regex}/ {{ print x; f=1}} "
-                f"END {{if (f==0) print ARGV[2] }} {print_before}'"
+                f"END {{if (f==0) print x }} {print_before}'"
             )
             cmd = StringCommand(
                 out_prep,


Test patch:
diff --git a/tests/operations/files.block/add_no_existing_block_line_provided.json b/tests/operations/files.block/add_no_existing_block_line_provided.json
index d3e1fe3c8..1320296d5 100644
--- a/tests/operations/files.block/add_no_existing_block_line_provided.json
+++ b/tests/operations/files.block/add_no_existing_block_line_provided.json
@@ -12,6 +12,6 @@
         }
     },
     "commands": [
-        "OUT=\"$(TMPDIR=/tmp mktemp -t pyinfra.XXXXXX)\" &&  awk 'BEGIN {x=ARGV[2]; ARGV[2]=\"\"}  f!=1 && /^.*before this.*$/ { print x; f=1} END {if (f==0) print ARGV[2] } { print }' /home/someone/something \"# BEGIN PYINFRA BLOCK\nplease add this\n# END PYINFRA BLOCK\" > $OUT && chmod $(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something ) $OUT &&  (chown $(stat -c \"%u:%g\" /home/someone/something 2>/dev/null ||  stat -f \"%u:%g\" /home/someone/something 2>/dev/null ) $OUT) && mv \"$OUT\" /home/someone/something"
+        "OUT=\"$(TMPDIR=/tmp mktemp -t pyinfra.XXXXXX)\" &&  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 && chmod $(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something ) $OUT &&  (chown $(stat -c \"%u:%g\" /home/someone/something 2>/dev/null ||  stat -f \"%u:%g\" /home/someone/something 2>/dev/null ) $OUT) && mv \"$OUT\" /home/someone/something"
     ]
 }
diff --git a/tests/operations/files.block/add_no_existing_block_line_provided_escape_regex.json b/tests/operations/files.block/add_no_existing_block_line_provided_escape_regex.json
index fca4d4d76..8632c4537 100644
--- a/tests/operations/files.block/add_no_existing_block_line_provided_escape_regex.json
+++ b/tests/operations/files.block/add_no_existing_block_line_provided_escape_regex.json
@@ -13,6 +13,6 @@
         }
     },
     "commands": [
-        "OUT=\"$(TMPDIR=/tmp mktemp -t pyinfra.XXXXXX)\" &&  awk 'BEGIN {x=ARGV[2]; ARGV[2]=\"\"}  f!=1 && /^.*before this \\*.*$/ { print x; f=1} END {if (f==0) print ARGV[2] } { print }' /home/someone/something \"# BEGIN PYINFRA BLOCK\nplease add this\n# END PYINFRA BLOCK\" > $OUT && chmod $(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something ) $OUT &&  (chown $(stat -c \"%u:%g\" /home/someone/something 2>/dev/null ||  stat -f \"%u:%g\" /home/someone/something 2>/dev/null ) $OUT) && mv \"$OUT\" /home/someone/something"
+        "OUT=\"$(TMPDIR=/tmp mktemp -t pyinfra.XXXXXX)\" &&  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 && chmod $(stat -c %a /home/someone/something 2>/dev/null || stat -f %Lp /home/someone/something ) $OUT &&  (chown $(stat -c \"%u:%g\" /home/someone/something 2>/dev/null ||  stat -f \"%u:%g\" /home/someone/something 2>/dev/null ) $OUT) && mv \"$OUT\" /home/someone/something"
     ]
 }