intake/intake/crontab.py

94 lines
3.1 KiB
Python

from pathlib import Path
import os
import subprocess
import sys
from intake.source import LocalSource
INTAKE_CRON_BEGIN = "### begin intake-managed crontab entries"
INTAKE_CRON_END = "### end intake-managed crontab entries"
def get_desired_crons(data_path: Path):
"""
Get a list of sources and crontab specs from the data directory.
"""
for child in data_path.iterdir():
if not (child / "intake.json").exists():
continue
source = LocalSource(data_path, child.name)
config = source.get_config()
if cron := config.get("cron"):
yield f"{cron} . /etc/profile; intake update -s {source.source_name}"
def update_crontab_entries(data_path: Path):
"""
Update the intake-managed section of the user's crontab.
"""
# If there is no crontab command available, quit early.
cmd = ("command", "-v", "crontab")
print("Executing", *cmd, file=sys.stderr)
crontab_exists = subprocess.run(cmd, shell=True)
if crontab_exists.returncode:
print("Could not update crontab", file=sys.stderr)
return
# Get the current crontab
cmd = ["crontab", "-e"]
print("Executing", *cmd, file=sys.stderr)
get_crontab = subprocess.run(
cmd,
env={**os.environ, "EDITOR": "cat"},
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
for line in get_crontab.stderr.decode("utf8").splitlines():
print("[stderr]", line, file=sys.stderr)
crontab_lines = get_crontab.stdout.decode("utf-8").splitlines()
# Splice the intake crons into the crontab
new_crontab_lines = []
section_found = False
in_section = False
for i in range(len(crontab_lines)):
if not section_found and crontab_lines[i] == INTAKE_CRON_BEGIN:
section_found = True
in_section = True
# Open the section and add everything
new_crontab_lines.append(INTAKE_CRON_BEGIN)
new_crontab_lines.extend(get_desired_crons(data_path))
elif crontab_lines[i] == INTAKE_CRON_END:
new_crontab_lines.append(INTAKE_CRON_END)
in_section = False
elif not in_section:
new_crontab_lines.append(crontab_lines[i])
# If the splice mark was never found, append the whole section to the end
if not section_found:
new_crontab_lines.append(INTAKE_CRON_BEGIN)
new_crontab_lines.extend(get_desired_crons(data_path))
new_crontab_lines.append(INTAKE_CRON_END)
print("Updating", len(new_crontab_lines) - 2, "crontab entries", file=sys.stderr)
# Save the updated crontab
cmd = ["crontab", "-"]
print("Executing", *cmd, file=sys.stderr)
new_crontab: bytes = "\n".join(new_crontab_lines).encode("utf8")
save_crontab = subprocess.Popen(
cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
(stdout, stderr) = save_crontab.communicate(new_crontab)
for line in stdout.decode("utf8").splitlines():
print("[stdout]", line, file=sys.stderr)
for line in stderr.decode("utf8").splitlines():
print("[stderr]", line, file=sys.stderr)