halig/halig/commands/edit.py
cătălin bdb5c984fa
All checks were successful
checks / pre-commit (push) Successful in 1m39s
checks / tests-10 (push) Successful in 1m17s
checks / tests-11 (push) Successful in 1m10s
checks / tests-12 (push) Successful in 1m13s
ci: add pre-commit and tests workflows
2024-08-04 15:23:55 +02:00

76 lines
2.7 KiB
Python

import os
import subprocess
import tempfile
from pathlib import Path
from halig import utils
from halig.commands.base import BaseCommand
from halig.encryption import Encryptor
from halig.settings import Settings
class EditCommand(BaseCommand):
"""*The* edit command, which also encompasses creating a new file when needed,
that is, when `note_path` is a folder, a new YYYY-MM-DD.age file will be created
if it does not exist and filled with an encrypted empty string
Attributes:
note_path (Path): The path to a specific .age note or a notebook.
Note that the input note_path will be modified in order to append it
to the notebooks root path defined by `Settings.notebooks_root_path`
attribute. This means that the input path is relative to the mentioned
root path
settings (Settings): Settings object
encryptor (Encryptor): Encryptor object
"""
def __init__(self, note_path: Path, settings: Settings):
super().__init__(settings)
self.note_path = self.settings.notebooks_root_path / note_path
self.encryptor = Encryptor(self.settings)
if self.note_path.is_dir():
self.note_path /= f"{utils.now_as_date()}.age"
if not self.note_path.name.endswith(".age"):
err = f"File {self.note_path.name} is not a valid AGE file"
raise ValueError(err)
if not self.note_path.exists():
empty_encrypted = self.encryptor.encrypt("")
with self.note_path.open("wb") as f:
f.write(empty_encrypted)
def edit_contents(self, original_contents: bytes) -> bytes:
"""Let the user edit the contents by opening an in-memory tempfile
using $EDITOR and encrypt the new contents
Args:
original_contents (bytes): original data that will be dumped into the
tempfile for the user to modify
Returns:
modified data as bytes
"""
with tempfile.NamedTemporaryFile(delete=False, suffix=".md") as tf:
tf.write(original_contents)
temp_path = Path(tf.name)
editor = os.environ.get("EDITOR", "vim")
subprocess.call([editor, temp_path]) # noqa: S603
with temp_path.open("rb") as f:
new_contents = f.read()
encrypted_contents = self.encryptor.encrypt(new_contents)
temp_path.unlink()
return encrypted_contents
def run(self):
with self.note_path.open("rb") as f:
original_contents = f.read()
original_contents = self.encryptor.decrypt(original_contents)
new_contents = self.edit_contents(original_contents)
with self.note_path.open("wb") as f:
f.write(new_contents)