Files

75 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Проект: /root/WORK/memo (Kotlin/JVM). Заказ по слежению за файлами.
Создать РОВНО ДВА новых файла:
memo-watch/build.gradle.kts (плагин kotlin("jvm") + зависимость на :memo-core)
memo-watch/src/main/kotlin/memo/watch/Watcher.kt
memo-watch/src/main/kotlin/memo/watch/WatchMain.kt
и ОДИН тестовый:
memo-watch/src/test/kotlin/memo/watch/WatcherTest.kt
## Watcher.kt
package memo.watch
class Watcher(
private val collections: List<java.io.File>, // каталоги-коллекции
private val index: (java.io.File) -> Unit, // функция индексации одной коллекции
private val debounceMillis: Long = 500,
private val reconcileMillis: Long = 10 * 60 * 1000,
) : AutoCloseable {
/** Запускает фоновый поток: WatchService на каждый каталог рекурсивно,
* debounce, плюс периодическая полная реконсиляция по mtime. */
fun start()
/** Останавливает поток, закрывает WatchService. Идемпотентно. */
override fun close()
/** Количество выполненных вызовов index(...) — для тестов. */
val indexCalls: Int
}
Требования:
1. Регистрировать каждый каталог через FileSystems.getDefault().newWatchService() с ENTRY_CREATE,
ENTRY_MODIFY, ENTRY_DELETE и при регистрации рекурсивно обойти подкаталоги (WatchService не рекурсивен).
Каталоги, начинающиеся с '.', не обходить и не регистрировать.
2. События собирать в Set<File> (какие коллекции затронуты). Поток: take() с таймаутом debounceMillis;
при накоплении — по истечении debounce вызвать index(коллекция) для каждой затронутой коллекции.
Не вызывать index десятки раз на одно сохранение файла.
3. Раз в reconcileMillis — полная реконсиляция: обойти все файлы *.md во всех коллекциях,
сравнить (path, mtime, size) со таблицей files, при расхождении вызвать index(коллекция).
Реализацию сравнения НЕ дублировать: у :memo-core уже есть Indexer.indexFile, который сам
пропускает неизменённые файлы и возвращает Boolean. Использовать его: index(коллекция) должен
внутри вызывать Indexer.indexTree(коллекция).
4. Все исключения в рабочем потоке не должны убивать поток: ловить, печатать в stderr, продолжать.
5. close(): interrupt + закрыть WatchService, поток завершается не дольше 2 секунд.
## WatchMain.kt
fun main(args: Array<String>)
- Аргумент: корень, содержащий коллекции (или одну коллекцию).
- Определение коллекций — как в CLI (каталог с *.md на глубине до 2).
- Создаёт Db(коллекция/.memo/index.db), .init(), Indexer(db, embedder) — по одному на коллекцию,
Watcher с index = { коллекция -> indexer.indexTree(коллекция) }.
- Печатает `наблюдаю: <коллекция>` по строке на каждую, затем блокируется навсегда до SIGINT.
- Модель: MEMO_MODEL_DIR, иначе /root/WORK/memo/models/siglip2.
## WatcherTest.kt — ровно 3 теста, имена ровно такие
1. `modifyTriggersSingleIndexCall` — временный каталог с note.md; Watcher с index-счётчиком и
debounce 200 мс; start(); правка файла; подождать 1.5 с; indexCalls == 1 (не больше!);
close(). (Перед стартом дать watcher 300 мс прогреться.)
2. `unchangedFileDoesNotTriggerIndex` — после прогрева ничего не менять 1.5 с → indexCalls == 0.
3. `closeIsIdempotentAndStopsThread` — start(); close(); close(); повторный вызов не бросает исключение.
Тесты должны быть устойчивыми: ждать не фиксированным sleep, а опросом условия с таймаутом
(например, до 5 с с шагом 100 мс), чтобы не флапать на медленной машине.
После: ./gradlew :memo-watch:test --rerun-tasks — зелёные; ./gradlew build -x test компилируется.
Коммит: git add -A && git commit -m "watch: слежение за файлами (WatchService + debounce + реконсиляция)"
СТРОГИЕ ЗАПРЕТЫ:
- Не выводить план текстом; сразу создавай файлы.
- Не трогать memo-core и memo-cli.
- Не добавлять зависимости, кроме :memo-core.