Add sudo escalation for root protected files
This commit is contained in:
@@ -2,7 +2,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import time
|
import time
|
||||||
@@ -14,10 +13,14 @@ def read_file(path: Path) -> str:
|
|||||||
return ""
|
return ""
|
||||||
return path.read_text(encoding="utf-8", errors="replace")
|
return path.read_text(encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def write_file(path: Path, content: str):
|
def write_file(path: Path, content: str):
|
||||||
path.write_text(content, encoding="utf-8")
|
path.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
def backup_original(original_path: Path, original_content: str, backup_dir: Path) -> Path:
|
|
||||||
|
def backup_original(
|
||||||
|
original_path: Path, original_content: str, backup_dir: Path
|
||||||
|
) -> Path:
|
||||||
backup_dir.mkdir(parents=True, exist_ok=True)
|
backup_dir.mkdir(parents=True, exist_ok=True)
|
||||||
timestamp = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
|
timestamp = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
|
||||||
uid = uuid.uuid4().hex[:8]
|
uid = uuid.uuid4().hex[:8]
|
||||||
@@ -26,11 +29,24 @@ def backup_original(original_path: Path, original_content: str, backup_dir: Path
|
|||||||
backup_path.write_text(original_content, encoding="utf-8")
|
backup_path.write_text(original_content, encoding="utf-8")
|
||||||
return backup_path
|
return backup_path
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="Safely edit a file with automatic original backup if changed.")
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Safely edit a file with automatic original backup if changed."
|
||||||
|
)
|
||||||
parser.add_argument("file", type=str, help="Path to file to edit")
|
parser.add_argument("file", type=str, help="Path to file to edit")
|
||||||
parser.add_argument("--backup-dir", type=str, default=str(Path.home() / ".local/share/mirro"), help="Backup directory")
|
parser.add_argument(
|
||||||
parser.add_argument("--editor", type=str, default=os.environ.get("EDITOR", "nano"), help="Editor to use")
|
"--backup-dir",
|
||||||
|
type=str,
|
||||||
|
default=str(Path.home() / ".local/share/mirro"),
|
||||||
|
help="Backup directory",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--editor",
|
||||||
|
type=str,
|
||||||
|
default=os.environ.get("EDITOR", "nano"),
|
||||||
|
help="Editor to use",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@@ -38,24 +54,32 @@ def main():
|
|||||||
backup_dir = Path(args.backup_dir).expanduser().resolve()
|
backup_dir = Path(args.backup_dir).expanduser().resolve()
|
||||||
editor_cmd = args.editor.split()
|
editor_cmd = args.editor.split()
|
||||||
|
|
||||||
|
# Permission checks
|
||||||
|
parent = target.parent
|
||||||
|
if target.exists() and not os.access(target, os.W_OK):
|
||||||
|
print(f"Need elevated privileges to open {target}")
|
||||||
|
return 1
|
||||||
|
if not target.exists() and not os.access(parent, os.W_OK):
|
||||||
|
print(f"Need elevated privileges to create {target}")
|
||||||
|
return 1
|
||||||
|
|
||||||
# Read original
|
# Read original
|
||||||
original_content = read_file(target)
|
original_content = read_file(target)
|
||||||
|
|
||||||
# Temp file for editing
|
# Temp file for editing
|
||||||
with tempfile.NamedTemporaryFile(delete=False, prefix="mirro-", suffix=target.suffix) as tf:
|
with tempfile.NamedTemporaryFile(
|
||||||
|
delete=False, prefix="mirro-", suffix=target.suffix
|
||||||
|
) as tf:
|
||||||
temp_path = Path(tf.name)
|
temp_path = Path(tf.name)
|
||||||
write_file(temp_path, original_content)
|
write_file(temp_path, original_content)
|
||||||
|
|
||||||
|
|
||||||
# Launch editor
|
# Launch editor
|
||||||
subprocess.call(editor_cmd + [str(temp_path)])
|
subprocess.call(editor_cmd + [str(temp_path)])
|
||||||
|
|
||||||
|
|
||||||
# Read edited
|
# Read edited
|
||||||
edited_content = read_file(temp_path)
|
edited_content = read_file(temp_path)
|
||||||
temp_path.unlink(missing_ok=True)
|
temp_path.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
if edited_content == original_content:
|
if edited_content == original_content:
|
||||||
print("file hasn't changed")
|
print("file hasn't changed")
|
||||||
return
|
return
|
||||||
@@ -67,5 +91,6 @@ def main():
|
|||||||
# Overwrite target
|
# Overwrite target
|
||||||
target.write_text(edited_content, encoding="utf-8")
|
target.write_text(edited_content, encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
Reference in New Issue
Block a user