Browse code

boobank-cacher now handles several commands.

Before this commit, boobank-cacher could only cache the output of "boobank
list". From now on, the configuration file is expected to describe a list of
commands that will be fed to a single boobank process. Commands may or may not
have a cache file, depending on whether their output is relevant. Each command
may have its own set of additions.

Xavier G authored on08/11/2017 16:02:22
Showing2 changed files

... ...
@@ -2,8 +2,10 @@
2 2
 # -*- coding: utf-8 -*-
3 3
 
4 4
 import os
5
+import re
5 6
 import sys
6 7
 import json
8
+import copy
7 9
 import time
8 10
 import errno
9 11
 import subprocess
... ...
@@ -26,41 +28,66 @@ def mkdir(path, mode):
26 28
         else:
27 29
             raise
28 30
 
29
-def get_cache_path(conf):
30
-    cache_path = conf.get('cache_path', '~/.cache/boobank-cacher/cache.json')
31
-    return os.path.expanduser(cache_path)
32
-
33 31
 def run_boobank(conf):
32
+    results = copy.deepcopy(conf)
33
+    # Ensure there is at least one command to run:
34
+    commands = results.get('commands', [])
35
+    if not commands:
36
+        return results
34 37
     boobank_path = os.path.expanduser(conf.get('boobank_path', 'boobank'))
35
-    boobank_command = [boobank_path, 'list', '--formatter=json']
36
-    boobank_output = subprocess.check_output(boobank_command)
37
-    boobank_data = json.loads(boobank_output)
38
-    return {'timestamp': time.time(), 'data': boobank_data}
38
+    boobank_command = [boobank_path, '--formatter=json']
39
+    boobank_process = subprocess.Popen(boobank_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True, bufsize=-1)
40
+    # Send all commands at once:
41
+    for command in commands:
42
+        boobank_process.stdin.write(command['command'] + "\n")
43
+    boobank_process.stdin.write("quit\n")
44
+    boobank_process.stdin.flush()
45
+    boobank_process.stdin.close()
46
+    # Parse output to extract relevant lines only:
47
+    out_time = time.time()
48
+    out_lines = []
49
+    while True:
50
+        out_line = boobank_process.stdout.readline()
51
+        if not out_line:
52
+            break
53
+        rem = re.search(r'^boobank>\s*(.+)$', out_line)
54
+        if rem:
55
+            out_lines.append(rem.group(1))
56
+    for i in xrange(len(commands)):
57
+        out_data = json.loads(out_lines[i])
58
+        commands[i]['result'] = {'timestamp': out_time, 'data': out_data}
59
+    return results
39 60
 
40
-def process_additions(conf, accounts):
41
-    additions = conf.get('additions', {})
42
-    if not additions:
43
-        return accounts
61
+def process_additions(results):
62
+    for command in results.get('commands', []):
63
+        additions = command.get('additions', {})
64
+        result = command.get('result', {})
65
+        if not additions or not result or 'data' not in result:
66
+            continue
44 67
 
45
-    processed_accounts = []
46
-    for account in accounts:
47
-        processed_accounts.append(account)
48
-        account_id = account.get('id')
49
-        if account_id is not None and account_id in additions:
50
-            processed_accounts.append(additions.get(account_id))
51
-    return processed_accounts
68
+        processed_items = []
69
+        for item in result.get('data', []):
70
+            processed_items.append(item)
71
+            item_id = item.get('id')
72
+            if item_id is not None and item_id in additions:
73
+                processed_items.append(additions.get(item_id))
74
+        result['data'] = processed_items
75
+    return results
52 76
 
53
-def write_cache(conf, accounts):
54
-    cache_path = get_cache_path(conf)
55
-    mkdir(os.path.dirname(cache_path), 0700)
56
-    with open(cache_path, 'w') as filedesc:
57
-        json.dump(accounts, filedesc, indent=4)
77
+def write_cache(results):
78
+    for command in results.get('commands', []):
79
+        if 'result' not in command or 'cache_path' not in command:
80
+            continue
81
+        cache_path = os.path.expanduser(command['cache_path'])
82
+        mkdir(os.path.dirname(cache_path), 0700)
83
+        with open(cache_path, 'w') as filedesc:
84
+            json.dump(command['result'], filedesc, indent=4)
58 85
 
59 86
 def main():
60 87
     conf = get_conf()
61
-    accounts = run_boobank(conf)
62
-    accounts['data'] = process_additions(conf, accounts['data'])
63
-    write_cache(conf, accounts)
88
+    results = run_boobank(conf)
89
+    process_additions(results)
90
+    write_cache(results)
64 91
 
65 92
 if __name__ == '__main__':
66 93
     main()
... ...
@@ -1,12 +1,24 @@
1 1
 {
2 2
     "boobank_path": "boobank",
3
-    "cache_path": "~/.cache/boobank-cacher/cache.json",
4
-    "additions": {
5
-        "accountid@bank": {
6
-            "id": "",
7
-            "balance": 42.00,
8
-            "currency": "EUR",
9
-            "label": "Ninja interest"
3
+    "commands": [
4
+        {
5
+            "command": "list",
6
+            "cache_path": "~/.cache/boobank-cacher/list.json",
7
+            "additions": {
8
+                "accountid@bank": {
9
+                    "id": "",
10
+                    "balance": 42.00,
11
+                    "currency": "EUR",
12
+                    "label": "Ninja interest"
13
+                }
14
+            }
15
+        },
16
+        {
17
+            "command": "count 50"
18
+        },
19
+        {
20
+            "cache_path": "~/.cache/boobank-cacher/history.json",
21
+            "command": "history current-account-id@yourbank"
10 22
         }
11
-    }
23
+    ]
12 24
 }