X-Git-Url: https://plomlompom.com/repos/process?a=blobdiff_plain;f=ledger.py;h=c004d22126846415a916e02a6bc4aad6052df9bf;hb=75169bb51854ec32d147976ac4381c6011c5320d;hp=02e0273c74f26590e426e7860d72576e0721073f;hpb=c8e39d2444ae290dba713c542a5f95a47ab67ba9;p=misc diff --git a/ledger.py b/ledger.py index 02e0273..c004d22 100755 --- a/ledger.py +++ b/ledger.py @@ -3,7 +3,7 @@ import os import html import jinja2 import decimal -import datetime +from datetime import datetime, timedelta from urllib.parse import parse_qs, urlparse hostName = "localhost" serverPort = 8082 @@ -67,7 +67,6 @@ def bookings_to_account_tree(bookings): def parse_lines(lines, validate_bookings=True): - import datetime inside_booking = False date_string, description = None, None booking_lines = [] @@ -109,7 +108,7 @@ def parse_lines(lines, validate_bookings=True): toks = non_comment.split(maxsplit=1) date_string = toks[0] try: - datetime.datetime.strptime(date_string, '%Y-%m-%d') + datetime.strptime(date_string, '%Y-%m-%d') except ValueError: raise HandledException(f"{prefix} bad date string: {date_string}") if last_date > date_string: @@ -280,37 +279,30 @@ class Database: f = open(self.lock_file, 'w+') f.close() - # always back up most recent to .bak - bakpath = f'{self.db_file}.bak' - shutil.copy(self.db_file, bakpath) - # collect modification times of numbered .bak files - bak_prefix = f'{bakpath}.' + bak_prefix = f'{self.db_file}.bak.' backup_dates = [] i = 0 bak_as = f'{bak_prefix}{i}' while os.path.exists(bak_as): mod_time = os.path.getmtime(bak_as) - backup_dates += [str(datetime.datetime.fromtimestamp(mod_time))] + backup_dates += [str(datetime.fromtimestamp(mod_time))] i += 1 bak_as = f'{bak_prefix}{i}' - # collect what numbered .bak files to save: - # shrink datetime string right to left character by character, - # on each step add the oldest file whose mtime still fits the pattern - # (privilege older files to keep existing longer) + # collect what numbered .bak files to save: the older, the fewer; for each + # timedelta, keep the newest file that's older + ages_to_keep = [timedelta(minutes=4**i) for i in range(0, 8)] + now = datetime.now() to_save = [] - datetime_len = 19 - now = str(datetime.datetime.now())[:datetime_len] - while datetime_len > 2: - # assume backup_dates starts with oldest dates - for i, date in enumerate(backup_dates): - if date[:datetime_len] == now: - if i not in to_save: - to_save += [i] - break - datetime_len -= 1 - now = now[:datetime_len] + for age in ages_to_keep: + limit = now - age + for i, date in enumerate(reversed(backup_dates)): + if datetime.strptime(date, '%Y-%m-%d %H:%M:%S.%f') < limit: + unreversed_i = len(backup_dates) - i - 1 + if unreversed_i not in to_save: + to_save += [unreversed_i] + break # remove redundant backup files j = 0 @@ -326,25 +318,51 @@ class Database: except FileNotFoundError: pass - # put second backup copy of current state at end of bak list + # put copy of current state at end of bak list shutil.copy(self.db_file, f'{bak_prefix}{j}') with open(self.db_file, mode) as f: f.write(text); os.remove(self.lock_file) - def replace(self, start, end, lines): - total_lines = self.real_lines[:start] + lines + self.real_lines[end:] + def insert_at_date(self, lines, date): + start_at = len(self.real_lines) + for b in self.bookings: + if b.date_string == date: + start_at = b.start_line + break + elif b.date_string > date: + break + if start_at == len(self.real_lines): + lines = [''] + lines + return self.write_lines_in_total_lines_at(self.real_lines, start_at, lines) + + def update(self, start, end, lines, date): + total_lines = self.real_lines[:start] + self.real_lines[end:] + n_original_lines = end - start + start_at = len(total_lines) + for b in self.bookings: + if b.date_string == date: + if start_at == len(total_lines) or b.start_line == start: + start_at = b.start_line + if b.start_line > start: + start_at -= n_original_lines + elif b.date_string > date: + break + if start_at == len(total_lines): + lines = [''] + lines + return self.write_lines_in_total_lines_at(total_lines, start_at, lines) + + def write_lines_in_total_lines_at(self, total_lines, start_at, lines): + total_lines = total_lines[:start_at] + lines + [''] + total_lines[start_at:] + _, _ = parse_lines(lines) text = '\n'.join(total_lines) self.write_db(text) - - def append(self, lines): - text = '\n\n' + '\n'.join(lines) + '\n\n' - self.write_db(text, 'a') + return start_at def get_nth_for_booking_of_start_line(self, start_line): nth = 0 for b in self.bookings: - if b.start_line == start_line: + if b.start_line >= start_line: break nth += 1 return nth @@ -494,6 +512,7 @@ input[type=number] { text-align: right; font-family: monospace; } / free | copy:structured / free +| move {% if move_up %}up{% else %}up{% endif %}/{% if move_down %}down{% else %}down{% endif %} | balance after ]