Fix record command funky timekeeping

This commit is contained in:
Jacob Hinkle 2022-10-11 13:43:43 -04:00
parent e76489b1c0
commit c3dd418c8c
5 changed files with 75 additions and 46 deletions

View File

@ -6,6 +6,7 @@ from .. import store
from .common import confirm from .common import confirm
from .diff import print_diff from .diff import print_diff
from datetime import datetime
import os import os
import sys import sys
from typing import Any, Optional, Union from typing import Any, Optional, Union
@ -21,6 +22,7 @@ def record(
skip_confirm: bool = False, skip_confirm: bool = False,
) -> None: ) -> None:
"""Unwrapped record command""" """Unwrapped record command"""
start_time = datetime.now()
if store_path is None: if store_path is None:
curdir = os.path.realpath(os.getcwd()) curdir = os.path.realpath(os.getcwd())
@ -36,21 +38,34 @@ def record(
else: # this is an existing store else: # this is an existing store
s = store.Store(store_path) s = store.Store(store_path)
fsdiff = s.diff() with s.new_program("RECORD", message) as p:
p.start_time = start_time # reset start to actual start of command
with s.committing() as cur: # entire record operation should be one transaction
# create a task for this operation
task = p.new_task(name="Store._record_recursive", cur=cur)
if show_diff: fsdiff = s.diff()
print_diff(fsdiff, show_hashes=show_hashes, use_color=use_color)
logger.info("Recording with message: {}", message) if show_diff:
print_diff(fsdiff, show_hashes=show_hashes, use_color=use_color)
if skip_confirm or confirm("Record the values above into the database?"): logger.info("Recording with message: {}", message)
s.record(fsdiff, message=message)
else: if skip_confirm or confirm(f"Record to {s.db_path}?"):
logger.info("Cancelled!") # descend the diff, tracking parent filedir IDs, creating them and
sys.exit(1) # recording new versions of each, when necessary
fsdiff.persist(cur=cur, source_task=task)
else:
logger.info("Cancelled!")
sys.exit(1)
@click.command() @click.command()
@click.option(
"--no-show",
is_flag=True,
help="Do not show what is about to be recorded.",
)
@click.option( @click.option(
"-H", "-H",
"--show-hashes", "--show-hashes",
@ -62,6 +77,12 @@ def record(
is_flag=True, is_flag=True,
help="If given, do not print any color output.", help="If given, do not print any color output.",
) )
@click.option(
"-y",
"--yes",
is_flag=True,
help="Do not ask for confirmation.",
)
@click.option( @click.option(
"-m", "-m",
"--message", "--message",
@ -78,7 +99,14 @@ def record(
"of given paths. If given the path to a non-store directory, a new " "of given paths. If given the path to a non-store directory, a new "
"store is initialized there.", "store is initialized there.",
) )
def record_cli(show_hashes: bool, no_color: bool, message: str, store: str) -> None: def record_cli(
no_show: bool,
show_hashes: bool,
yes: bool,
no_color: bool,
message: str,
store: str,
) -> None:
""" """
Initialize tracking or record changes to a tracked directory. Initialize tracking or record changes to a tracked directory.
""" """
@ -87,4 +115,6 @@ def record_cli(show_hashes: bool, no_color: bool, message: str, store: str) -> N
show_hashes=show_hashes, show_hashes=show_hashes,
use_color=not no_color, use_color=not no_color,
store_path=store, store_path=store,
skip_confirm=yes,
show_diff=not no_show,
) )

View File

@ -154,7 +154,7 @@ class FSEntry:
cls: Type[_FSEntryT], cls: Type[_FSEntryT],
store: Optional["Store"] = None, store: Optional["Store"] = None,
relpath: Optional[str] = None, relpath: Optional[str] = None,
exclude: List[str] = ["nancy.db"], exclude_prefixes: List[str] = ["nancy.db", "."],
parent: Optional[_FSEntryT] = None, parent: Optional[_FSEntryT] = None,
direntry: Optional["os.DirEntry[str]"] = None, direntry: Optional["os.DirEntry[str]"] = None,
) -> _FSEntryT: ) -> _FSEntryT:
@ -206,15 +206,23 @@ class FSEntry:
for e in direntries for e in direntries
) )
children = [ children = []
cls.from_path( for rp, e in zip(childrenrelpaths, direntries):
store=store, skip = False
relpath=rp, for p in exclude_prefixes:
direntry=e, if os.path.basename(rp).startswith(p):
skip = True
break
if skip:
continue
children.append(
cls.from_path(
store=store,
relpath=rp,
direntry=e,
)
) )
for rp, e in zip(childrenrelpaths, direntries)
if rp not in exclude
]
for c in children: # now hash concatenated sorted hashes for c in children: # now hash concatenated sorted hashes
# hash on perms+sha256 to enable recursively detecting perm # hash on perms+sha256 to enable recursively detecting perm
# changes without modifying the hashes of individual files, # changes without modifying the hashes of individual files,

View File

@ -129,7 +129,7 @@ class Program:
name: str name: str
message: str message: str
start_time: Optional[datetime.datetime] = None start_time: datetime.datetime = datetime.datetime.fromtimestamp(0)
evaluated: bool = False evaluated: bool = False
uuid: str = "" uuid: str = ""
@ -195,7 +195,7 @@ class Program:
WHERE WHERE
uuid = ? uuid = ?
""", """,
(self.start_time, end_time, self.uuid), (self.start_time.timestamp(), end_time.timestamp(), self.uuid),
) )
self.evaluated = True # prevent re-running self.evaluated = True # prevent re-running
assert self.start_time is not None assert self.start_time is not None

View File

@ -78,7 +78,6 @@ class Store:
@classmethod @classmethod
def init(cls: Type[_StoreT], message: str, directory: fs.PathStr) -> _StoreT: def init(cls: Type[_StoreT], message: str, directory: fs.PathStr) -> _StoreT:
start_time = datetime.datetime.now()
if not os.path.isdir(directory): if not os.path.isdir(directory):
raise FileNotFoundError( raise FileNotFoundError(
f"Directory {directory} must exist before initializing a store there.", f"Directory {directory} must exist before initializing a store there.",
@ -107,10 +106,6 @@ class Store:
(new_store.uuid,), (new_store.uuid,),
) )
with new_store.new_program("INIT", message) as p:
# set the timing to the actual times it took to initialize the db
p.start_time = start_time
return new_store return new_store
def filedir_root_key(self, cur: Optional[sqlite3.Cursor] = None) -> Optional[str]: def filedir_root_key(self, cur: Optional[sqlite3.Cursor] = None) -> Optional[str]:
@ -188,26 +183,6 @@ class Store:
return fs.FSDiff.compute(recorded, current) return fs.FSDiff.compute(recorded, current)
def record(
self,
diff: fs.FSDiff,
message: str,
parent_id: Optional[str] = None,
cur: Optional[sqlite3.Cursor] = None,
) -> None:
if cur is None:
assert self.conn is not None
cur = self.conn.cursor()
with self.new_program("RECORD", message) as p:
with self.committing() as cur: # entire record operation is one transaction
# create a task for this operation
task = p.new_task(name="Store._record_recursive", cur=cur)
# descend the diff, tracking parent filedir IDs, creating them and
# recording new versions of each, when necessary
diff.persist(cur=cur, source_task=task)
def find_store(path: Union[str, "os.PathLike[str]"]) -> Optional[str]: def find_store(path: Union[str, "os.PathLike[str]"]) -> Optional[str]:
""" """

View File

@ -22,6 +22,22 @@ def junk_dir() -> Iterator[Path]:
def test_record(junk_dir: Path) -> None: def test_record(junk_dir: Path) -> None:
runner = CliRunner() runner = CliRunner()
result = runner.invoke(
main,
[
"record",
"-s",
str(junk_dir),
"-m",
"This is just a test recording",
"--yes", # don't ask for confirmation
],
)
print(result.output)
assert result.exit_code == 0
assert "ERROR" not in result.output
# test again with confirmation
result = runner.invoke( result = runner.invoke(
main, main,
[ [