Skip to content

Commit 581f1d5

Browse files
committed
FEAT: --update/overwrite option TODOed by #20,
- CLI options described in the 2nd case explained in #211, due to simplicity. - The precedence for deciding update/overwrite: env-var, --update/overwrite, --source exist? - Function defaults are false, as suggested in [#20](#20 (comment)). - Both index & demo updated. - Env-var now checks its value one of (update|overwrite). - All update/overwrite decision logic moved to __main_.
1 parent 4fb9cbd commit 581f1d5

File tree

2 files changed

+55
-20
lines changed

2 files changed

+55
-20
lines changed

src/promnesia/__main__.py

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import logging
44
import inspect
5+
import os
56
import sys
67
from typing import List, Tuple, Optional, Dict, Sequence, Iterable, Iterator
78
from pathlib import Path
@@ -66,7 +67,7 @@ def iter_all_visits(sources_subset: Iterable[str]=()) -> Iterator[Res[DbVisit]]:
6667
yield e
6768

6869

69-
def _do_index(dry: bool=False, sources_subset: Iterable[str]=()) -> Iterable[Exception]:
70+
def _do_index(dry: bool=False, sources_subset: Iterable[str]=(), overwrite_db=False) -> Iterable[Exception]:
7071
# also keep & return errors for further display
7172
errors: List[Exception] = []
7273
def it() -> Iterable[Res[DbVisit]]:
@@ -81,17 +82,23 @@ def it() -> Iterable[Res[DbVisit]]:
8182
for v in res:
8283
print(v)
8384
else:
84-
dump_errors = visits_to_sqlite(it())
85+
dump_errors = visits_to_sqlite(it(), overwrite_db)
8586
for e in dump_errors:
8687
logger.exception(e)
8788
errors.append(e)
8889
return errors
8990

9091

91-
def do_index(config_file: Path, dry: bool=False, sources_subset: Iterable[str]=()) -> None:
92+
def do_index(
93+
config_file: Path,
94+
dry: bool=False,
95+
sources_subset: Iterable[str]=(),
96+
overwrite: bool=None,
97+
overwrite_db=False,
98+
) -> None:
9299
config.load_from(config_file) # meh.. should be cleaner
93100
try:
94-
errors = list(_do_index(dry=dry, sources_subset=sources_subset))
101+
errors = list(_do_index(dry=dry, sources_subset=sources_subset, overwrite_db=overwrite_db))
95102
finally:
96103
config.reset()
97104
if len(errors) > 0:
@@ -131,6 +138,7 @@ def do_demo(*
131138
config_file: Optional[Path],
132139
name: str='demo',
133140
sources_subset: Iterable[str]=(),
141+
overwrite_db: bool=False,
134142
) -> None:
135143
from pprint import pprint
136144
with TemporaryDirectory() as tdir:
@@ -147,7 +155,7 @@ def do_demo(*
147155
)
148156
config.instance = cfg
149157

150-
errors = list(_do_index(sources_subset=sources_subset))
158+
errors = list(_do_index(sources_subset=sources_subset, overwrite_db=overwrite_db))
151159
if len(errors) > 0:
152160
logger.error('%d errors during indexing (see logs above for backtraces)', len(errors))
153161
for e in errors:
@@ -293,6 +301,22 @@ def main() -> None:
293301
ep.add_argument('--intermediate', required=False, help="Used for development, you don't need it")
294302
ep.add_argument('--sources', required=False, action="extend", nargs="+", type=_parse_ordinal_or_name,
295303
help="Subset of source(s) to run (name or 0-indexed position); use `promnisia --dry` to view sources")
304+
overwrite = ep.add_mutually_exclusive_group()
305+
overwrite.add_argument(
306+
'--update',
307+
required=False,
308+
action="store_const",
309+
const=True,
310+
dest="overwrite_db",
311+
help=
312+
"Keep existing visits in db and merge new ones collected."
313+
" If neither is given, --update assumed when --sources given (the default)"
314+
", unless PROMNESIA_INDEX_POLICY=(update|overwrite) env-var defined"
315+
", which takes precendance."
316+
" Conflicts with --update.%(default)0.0s"
317+
)
318+
overwrite.add_argument('--overwrite', required=False, action="store_const", const=False, dest="overwrite_db",
319+
help="The opposite of --update: recreate db with newly indexed visits%(default)0.0s")
296320

297321
sp = subp.add_parser('serve', help='Serve a link database', formatter_class=F) # type: ignore
298322
server.setup_parser(sp)
@@ -348,13 +372,33 @@ def main() -> None:
348372
p.print_help(sys.stderr)
349373
sys.exit(1)
350374

375+
overwrite_policy_var = os.environ.get("PROMNESIA_INDEX_POLICY")
376+
if overwrite_policy_var:
377+
overwrite_policy_var = overwrite_policy_var.lower()
378+
if overwrite_policy_var not in ("update", "overwrite"):
379+
print(
380+
f"Invalid value for PROMNESIA_INDEX_POLICY env-var: {overwrite_policy_var}"
381+
"\n Must be one of (update | overwrite).",
382+
file=sys.stderr)
383+
sys.exit(2)
384+
args.overwrite_db = overwrite_policy_var == "overwrite"
385+
if args.overwrite_db is None:
386+
args.overwrite_db = not bool(args.sources)
387+
388+
logger.info("CLI args: %s", args)
389+
351390
# TODO maybe, it's better for server to compute intermediate represetnation?
352391
# the only downside is storage. dunno.
353392
# worst case -- could use database?
354393

355394
with get_tmpdir() as tdir: # TODO??
356395
if args.mode == 'index':
357-
do_index(config_file=args.config, dry=args.dry, sources_subset=args.sources)
396+
do_index(
397+
config_file=args.config,
398+
dry=args.dry,
399+
sources_subset=args.sources,
400+
overwrite_db=args.overwrite_db,
401+
)
358402
elif args.mode == 'serve':
359403
server.run(args)
360404
elif args.mode == 'demo':
@@ -367,6 +411,7 @@ def main() -> None:
367411
config_file=args.config,
368412
name=args.name,
369413
sources_subset=args.sources,
414+
overwrite_db=args.overwrite_db,
370415
)
371416
elif args.mode == 'install-server': # todo rename to 'autostart' or something?
372417
install_server.install(args)

src/promnesia/dump.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import os
21
from pathlib import Path
32
import shutil
43
from typing import Dict, List, Tuple, Set, Iterable
@@ -14,14 +13,6 @@
1413
from . import config
1514

1615

17-
def update_policy_active() -> bool:
18-
# NOTE: experimental.. need to make it a proper cmdline argument later
19-
INDEX_POLICY = os.environ.get('PROMNESIA_INDEX_POLICY', 'overwrite_all')
20-
# if 'update' is passed, will run against the existing db and only tough the sources present in the current index run
21-
# not sue if a good name for this..
22-
return INDEX_POLICY == 'update'
23-
24-
2516
# NOTE: I guess the main performance benefit from this is not creating too many tmp lists and avoiding overhead
2617
# since as far as sql is concerned it should all be in the same transaction. only a guess
2718
# not sure it's the proper way to handle it
@@ -30,7 +21,7 @@ def update_policy_active() -> bool:
3021

3122

3223
# returns critical warnings
33-
def visits_to_sqlite(vit: Iterable[Res[DbVisit]]) -> List[Exception]:
24+
def visits_to_sqlite(vit: Iterable[Res[DbVisit]], overwrite_db: bool) -> List[Exception]:
3425
logger = get_logger()
3526
db_path = config.get().db
3627

@@ -58,8 +49,7 @@ def vit_ok() -> Iterable[DbVisit]:
5849
yield ev
5950

6051
tpath = Path(get_tmpdir().name) / 'promnesia.tmp.sqlite'
61-
policy_update = update_policy_active()
62-
if not policy_update:
52+
if overwrite_db:
6353
engine = create_engine(f'sqlite:///{tpath}')
6454
else:
6555
engine = create_engine(f'sqlite:///{db_path}')
@@ -82,12 +72,12 @@ def vit_ok() -> Iterable[DbVisit]:
8272
# pylint: disable=no-value-for-parameter
8373
conn.execute(table.insert().values(bound))
8474

85-
if not policy_update:
75+
if overwrite_db:
8676
shutil.move(str(tpath), str(db_path))
8777

8878
errs = '' if errors == 0 else f', {errors} ERRORS'
8979
total = ok + errors
90-
what = 'updated' if policy_update else 'overwritten'
80+
what = 'overwritten' if overwrite_db else 'updated'
9181
logger.info('%s database "%s". %d total (%d OK%s)', what, db_path, total, ok, errs)
9282
res: List[Exception] = []
9383
if total == 0:

0 commit comments

Comments
 (0)