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.
... | ... |
@@ -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 |
} |