dnd/deadsands/site_tools/campaign.py

83 lines
2.4 KiB
Python
Raw Normal View History

2023-08-20 12:07:10 -07:00
from collections import defaultdict
from pathlib import Path
import shutil
import yaml
from telisar.reckoning import telisaran
def _string_to_date(date):
return telisaran.datetime.from_expression(f"on {date}", timeline={})
def _date_to_string(date):
return date.numeric
def _rotate_backups(path, max_backups=10):
oldest = None
if not path.exists():
return oldest
# move file.000 to file.001, file.001 to file.002, etc...
for i in range(max_backups - 2, -1, -1):
source = Path(f"{path}.{i:03d}")
target = Path(f"{path}.{i+1:03d}")
if not source.exists():
continue
if oldest is None:
oldest = i
if i == max_backups:
source.unlink()
shutil.move(source, target)
return oldest
def save(campaign, path='.', name='dnd_campaign'):
savedir = Path(path).expanduser()
savepath = savedir / f"{name}.yaml"
savedir.mkdir(exist_ok=True)
backup_count = _rotate_backups(savepath)
if savepath.exists():
target = Path(f"{savepath}.000")
shutil.move(savepath, target)
campaign['date'] = _date_to_string(campaign['date'])
campaign['start_date'] = _date_to_string(campaign['start_date'])
savepath.write_text(yaml.safe_dump(dict(campaign)))
return savepath, (backup_count or 0) + 2
def load(path=".", name='dnd_campaign', start_date='', backup=None, console=None):
ext = "" if backup is None else f".{backup:03d}"
default_date = _string_to_date(start_date)
campaign = defaultdict(str)
campaign['start_date'] = default_date
campaign['date'] = default_date
if console:
console.print(f"Loading campaign {name} from {path}...")
try:
target = Path(path).expanduser() / f"{name}.yaml{ext}"
with open(target, 'rb') as f:
loaded = yaml.safe_load(f)
loaded['start_date'] = _string_to_date(loaded['start_date'])
loaded['date'] = _string_to_date(loaded['date'])
campaign.update(loaded)
if console:
console.print(f"Successfully loaded Campaign {name} from {target}!")
return campaign
except FileNotFoundError:
console.print(f"No existing campaigns found in {path}.")
return campaign
except yaml.parser.ParserError as e:
if console:
console.print(f"{e}\nWill try an older backup.")
return load(path, 0 if backup is None else backup+1)