From 75169bb51854ec32d147976ac4381c6011c5320d Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Sun, 19 Nov 2023 00:08:56 +0100
Subject: [PATCH] Improve ledger.py.

---
 ledger.py | 51 ++++++++++++++++++++++-----------------------------
 1 file changed, 22 insertions(+), 29 deletions(-)

diff --git a/ledger.py b/ledger.py
index 4a6a071..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
@@ -108,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:
@@ -279,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
@@ -325,7 +318,7 @@ 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);
@@ -564,20 +557,20 @@ input[type=number] { text-align: right; font-family: monospace; }
                 _, _ = parse_lines(lines)
             # if saving, process where to and where to redirect after
             if 'save' in postvars.keys():
-                last_date = str(datetime.datetime.now())[:10]
+                last_date = str(datetime.now())[:10]
                 if len(db.bookings) > 0:
                     last_date = db.bookings[-1].date_string
                 target_date = last_date[:] 
                 first_line_tokens = lines[0].split() if len(lines) > 0 else ''
                 first_token = first_line_tokens[0] if len(first_line_tokens) > 0 else ''
                 try:
-                    datetime.datetime.strptime(first_token, '%Y-%m-%d')
+                    datetime.strptime(first_token, '%Y-%m-%d')
                     target_date = first_token
                 except ValueError:
                      pass
                 if start == end == 0:
-                        start = db.insert_at_date(lines, target_date)
-                        nth = db.get_nth_for_booking_of_start_line(start) 
+                    start = db.insert_at_date(lines, target_date)
+                    nth = db.get_nth_for_booking_of_start_line(start) 
                 else:
                     new_start = db.update(start, end, lines, target_date)
                     nth = db.get_nth_for_booking_of_start_line(new_start)
@@ -811,7 +804,7 @@ input[type=number] { text-align: right; font-family: monospace; }
                 for currency in moneys.keys():
                     datalist_sets['currencies'].add(currency)
         content = ''
-        today = str(datetime.datetime.now())[:10]
+        today = str(datetime.now())[:10]
         booking_lines = []
         if copy:
             start = end = 0
-- 
2.30.2