From f3023525023f1b0933bf677e4b80dd43d09ff8ec Mon Sep 17 00:00:00 2001 From: buenosairesam Date: Tue, 13 May 2025 07:39:44 -0300 Subject: [PATCH] filetime check --- dmapp/dmcore/main.py | 24 +++++++++++- dmapp/dmcore/sample_task_file | 72 ++++++++++++++++------------------- dmapp/dmcore/state.py | 20 +++++++++- dmapp/dmcore/task.py | 44 ++++++++++++++++----- 4 files changed, 107 insertions(+), 53 deletions(-) diff --git a/dmapp/dmcore/main.py b/dmapp/dmcore/main.py index 5d1efae..05dd8a2 100644 --- a/dmapp/dmcore/main.py +++ b/dmapp/dmcore/main.py @@ -57,6 +57,16 @@ switch = { switches.insert_one(switch) while True: + current_mtime = state.retrieve("current").get("filetime") + file_mtime = task.get_file_mtime(None) + + logger.debug(f"current_mtime: {current_mtime}, file_mtime:{file_mtime}") + if current_mtime != file_mtime: + task_id = task.read_and_extract(None) + logger.debug(f"task_id:{task_id}") + task.file_to_db(None) + state.save("current", task=task_id) + current_task = state.retrieve("current").get("task") current_workspace = active_workspace() state.save("current", workspace=current_workspace) @@ -67,11 +77,21 @@ while True: if current_workspace in work_desktops.keys(): work_states = state.retrieve_work_state() current_work_task = work_states[work_desktops[current_workspace]] - logger.debug(f"current_work_task: {current_work_task}") - if current_task != current_work_task: + + # Get all task IDs under current workspace path + workspace_tasks = task.get_tasks_tree( + f"work/{work_desktops[current_workspace]}" + ) + work_task_ids = {t["task_id"] for t in workspace_tasks if "task_id" in t} + logger.debug( + f"work_task_ids:{work_task_ids}, current_work_task: {current_work_task}" + ) + + if current_task in work_task_ids and current_task != current_work_task: state.save("current", task=current_work_task) task.db_to_file_as_is(None) current_task = current_work_task + state.update_work_state(work_desktops[current_workspace], current_task) # regular flow if ( diff --git a/dmapp/dmcore/sample_task_file b/dmapp/dmcore/sample_task_file index fb5b2b4..5b513ee 100644 --- a/dmapp/dmcore/sample_task_file +++ b/dmapp/dmcore/sample_task_file @@ -1,7 +1,8 @@ -work - default |ffbe198e * - vhs |c851ce32 - dlt |b4378ac5 +work + default |ffbe198e * + dm |77532dd4 + vhs |c851ce32 + dlt |b4378ac5 @@ -33,17 +34,17 @@ work think lectura - guitarra + guitarra design patterns - data structures - politica + data structures + politica cursos code microsaas soft oratoria - memoria |1dc8a7c2 + memoria |1dc8a7c2 video blender @@ -54,30 +55,28 @@ think plan entrevistas - rapid fort |00799f93 - calestino |f58a2919 - celara |64898a2f + rapid fort |00799f93 + calestino |f58a2919 + celara |64898a2f -work boat - spots |5fc751ec + spots |5fc751ec dani: si mejor extraer dl y sfr manual revisar ami publisher - mapear codigo |462682ac - credentials - completar lista |d602b2d8 + mapear codigo |462682ac + credentials + completar lista |d602b2d8 simulations reunion caro - OCIO class |f6f23db6 + OCIO class |f6f23db6 generar cache dani: tracker, entity - graph? - averiguar opciones |9d794a0b + graph? + averiguar opciones |9d794a0b - default - deskmeter |ec01a5a8 + deskmeter |ec01a5a8 autoweekcal frontend apps qt, wxwidgets, c @@ -100,9 +99,9 @@ work configurar hydrogen - musica + musica piano - liebestraum + liebestraum arpegios and scales AbM course exercises @@ -126,24 +125,18 @@ work elegir videos -plan hablar con kimda para actualizar sombrero - habilitar obsidian j + habilitar obsidian j -work - default config aws cli for boat,mcrn just start stop ecs - default spoty -think design patterns algos and ds -work maxi alinear month,date scroll, recenter (today) @@ -151,13 +144,12 @@ work show 3M before 9M after - dlt - whatsapp |f217b606 - seo and analytics |7422cfe3 - dockerizar |acbd9f7f - landing page |9719a462 - documento |c6b0af75 - carga |be7e496f - update look |51c5b6d6 - instagram ads |76e7b629 - wrap up |92014034 + whatsapp |f217b606 + seo and analytics |7422cfe3 + dockerizar |acbd9f7f + landing page |9719a462 + documento |c6b0af75 + carga |be7e496f + update look |51c5b6d6 + instagram ads |76e7b629 + wrap up |92014034 diff --git a/dmapp/dmcore/state.py b/dmapp/dmcore/state.py index 5948c2e..fb50263 100644 --- a/dmapp/dmcore/state.py +++ b/dmapp/dmcore/state.py @@ -1,7 +1,13 @@ from config import logger, states, tasks -def save(doc_id: str, *, task: str | None = None, workspace: str | None = None) -> None: +def save( + doc_id: str, + *, + task: str | None = None, + workspace: str | None = None, + filetime: str | None = None, +) -> None: """ Upsert a document with _id=doc_id, setting any of the provided fields. Leave fields you don’t pass unchanged. @@ -11,6 +17,9 @@ def save(doc_id: str, *, task: str | None = None, workspace: str | None = None) updates["task"] = task if workspace is not None: updates["workspace"] = workspace + if filetime is not None: + updates["filetime"] = filetime + if updates: states.update_one( {"_id": doc_id}, @@ -28,9 +37,18 @@ def retrieve(doc_id: str) -> dict[str, str | None]: return { "task": doc.get("task") if doc else None, "workspace": doc.get("workspace") if doc else None, + "filetime": doc.get("filetime") if doc else None, } +# just +def update_work_state(work: str, task_id: str): + """ + update work state + """ + states.update_one({"_id": "work"}, {"$set": {work: task_id}}) + + def init_work_state(wd: dict): """ init work states with default values diff --git a/dmapp/dmcore/task.py b/dmapp/dmcore/task.py index 1d98e81..db4d8ab 100644 --- a/dmapp/dmcore/task.py +++ b/dmapp/dmcore/task.py @@ -1,3 +1,4 @@ +import datetime import re from pathlib import Path from typing import Optional @@ -27,6 +28,9 @@ def parse_line(line: str) -> tuple[Optional[str], Optional[str]]: def file_to_db(filepath: str): """Convert task file to MongoDB entries.""" + if filepath is None: + filepath = task_file + current_path = [] tasks.delete_many({}) seen_paths = set() @@ -59,15 +63,6 @@ def file_to_db(filepath: str): seen_paths.add(full_path) - tasks.createIndex( - {"path": 1}, - { - name: "idx_tasks_path_ci", - background: true, - collation: {locale: "es", strength: 1}, - }, - ) - def format_task_line( path_parts: list, indent_level: int, task_id: str, current_task: str @@ -139,7 +134,6 @@ def extract(line: str) -> Optional[str]: # Extract everything between | and * and strip spaces id_part = line[pipe_index + 1 : -1].strip() if len(id_part) == 8: - state.save("current", task=id_part) return id_part return None @@ -149,9 +143,39 @@ def read_and_extract(filepath: str) -> Optional[str]: if filepath is None: filepath = task_file + mtime = get_file_mtime(filepath) + state.save("current", filetime=mtime) + with open(filepath, "r") as file: for line in file: task_id = extract(line) if task_id: return task_id return None + + +def get_file_mtime(filepath: str) -> str: + """Get file modification time as ISO format string.""" + if filepath is None: + filepath = task_file + return datetime.datetime.fromtimestamp(Path(filepath).stat().st_mtime).isoformat() + + +def get_tasks_tree(root_path: str, only_with_ids: bool = True) -> list[dict]: + """ + Get all tasks under a given path node, including the node itself. + """ + + query = {"path": {"$regex": root_path}} + + # Add task_id filter if requested + if only_with_ids: + query["task_id"] = {"$exists": True} + + # Query and sort by path to maintain hierarchy + cursor = tasks.find( + query, + {"path": 1, "task_id": 1, "_id": 0}, + ).sort("path", 1) + + return list(cursor)