Skip to content

Починить сборку, вернуть CLI и сделать удаление безопасным - #1

Merged
maximkr merged 1 commit into
mainfrom
fix/cli-safety-and-readme
Aug 12, 2026
Merged

Починить сборку, вернуть CLI и сделать удаление безопасным#1
maximkr merged 1 commit into
mainfrom
fix/cli-safety-and-readme

Conversation

@maximkr

@maximkr maximkr commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Оформление репозитория плюс исправления, найденные при разборе кода.

Rust локально не установлен, поэтому сборку проверяет CI этой ветки — как раз потому, что первым делом чинится причина, по которой он не собирался.

Критичное

cargo.toml -> Cargo.toml. Cargo ищет манифест строго с большой буквы. На Windows и macOS файловая система регистронезависима и локально всё собиралось, а на ubuntu-latest — нет. Единственный запуск CI (17388393875) упал за 7 секунд.

Вернут CLI. Разбор args лежал закомментированным, вместо него было захардкожено:

let dir = Path::new("C:/projects/rust-hasher/m/");
let delete_count: usize = 20;

Теперь image-dedup <директория> [-n N] [-t D] [--strategy S] [--apply], разбор без внешних зависимостей, в стиле остального кода.

check_image больше не паникует. Было image::open(path).expect("Failed to open image") — один desktop.ini, .txt или битый файл в папке ронял программу. При этом функция возвращала Option<ImageHash>, но None не возвращала никогда. Теперь не-изображения пропускаются с сообщением в stderr.

Безопасность удаления

Удаление необратимое, в корзину не кладёт, поэтому:

Сухой прогон по умолчанию. Без --apply печатается только список того, что было бы удалено.

Порог похожести -t. Раньше удалялось ровно N файлов независимо от того, похожи они на самом деле или нет: в папке из 100 совершенно разных картинок всё равно удалялись бы 20 — просто наименее разные. Теперь работа прекращается, когда ближайшая пара оказывается дальше порога, а -n работает как верхний предел. Порог проверяется по расстоянию до ближайшего соседа, что осмысленно для обеих стратегий.

expect() на чтении директории и удалении файла заменены на возврат ошибки с внятным сообщением и ненулевым кодом выхода.

Прочее

  • find_most_similar_to_all_other() была мёртвым кодом — вызов закомментирован в main.rs:107. Теперь доступна как --strategy central, в отличие от pairwise она выбивает «центр масс» набора.
  • Обход директории отсортирован. read_dir отдаёт файлы в порядке файловой системы, а при равных расстояниях именно порядок решает, какой файл из пары удалить, — прогоны были невоспроизводимы.
  • Хешер создаётся один раз, а не заново на каждый файл.
  • Имя пакета phash_image_cleaner -> image-dedup, по имени репозитория. Меняет имя бинарника.
  • Добавлены README.md (задача, модель, стратегии, подбор порога, ограничения) и .gitignore для target/.
  • Добавлены тесты разбора аргументов — CI запускал cargo test при полном отсутствии тестов.

Что осознанно не трогал

  • Алгоритм хеширования. HasherConfig::new() даёт HashAlg::Gradient, а не pHash, — вопреки прежнему имени пакета и топикам репозитория (phash, phash-similarity). Включение .preproc_dct() изменило бы результаты на существующих датасетах, так что это отдельное решение; расхождение описано в README.
  • Сложность O(N · n²) — матрица расстояний пересчитывается на каждой итерации. Описано в README как известное ограничение.
  • img_hash 3.2 заброшен с ~2020 и тянет устаревший image 0.23. Переход на image_hasher — отдельная задача.

🤖 Generated with Claude Code

Критичное:
- cargo.toml -> Cargo.toml. Cargo ищет манифест строго с большой буквы;
  на Windows/macOS регистр не мешает, а на Linux сборка не находила манифест —
  единственный запуск CI падал за 7 секунд
- вернут разбор аргументов: путь и число удалений были захардкожены
  на C:/projects/rust-hasher/m/ и 20, разбор args лежал закомментированным
- check_image больше не паникует: image::open(...).expect() ронял программу
  на любом не-изображении в папке (desktop.ini, .txt, битый файл).
  Такие файлы теперь пропускаются с сообщением

Безопасность удаления:
- сухой прогон по умолчанию, реальное удаление только по --apply
- порог похожести -t: раньше удалялось ровно N файлов независимо от того,
  похожи они или нет. Теперь удаление прекращается, когда ближайшая пара
  дальше порога
- ошибки чтения/удаления возвращаются наверх вместо expect()

Прочее:
- find_most_similar_to_all_other была мёртвым кодом (вызов закомментирован) —
  доступна как --strategy central
- порядок обхода директории отсортирован: read_dir отдаёт файлы в порядке ФС,
  а при равных расстояниях от него зависит выбор кандидата
- хешер создаётся один раз, а не на каждый файл
- имя пакета phash_image_cleaner -> image-dedup, по имени репозитория
- добавлены README.md, .gitignore и тесты разбора аргументов
  (CI запускал cargo test при полном отсутствии тестов)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@maximkr
maximkr merged commit 4277ae3 into main Aug 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant