Skip to content

fix(1c): Выбирать кодировку 1cestart.cfg по результату, а не по отсутствию ошибки - #45

Merged
zeegin merged 2 commits into
mainfrom
fix/1cestart-parsing
Sep 17, 2026
Merged

zeegin merged 2 commits into
mainfrom
fix/1cestart-parsing

Conversation

@zeegin

@zeegin zeegin commented Sep 17, 2026

Copy link
Copy Markdown
Member

Closes #18.

Корень

Перебор кодировок останавливался на первом кодеке, который не бросил исключение. utf-16le не бросает почти никогда: любая последовательность чётной длины декодируется в иероглифы. Отсюда четыре независимых симптома — и все они воспроизводятся на одном и том же содержимом.

До (тот же прогон, что в issue):

utf-8 без BOM      len=  97 -> [/home/user/tmplts, /srv/1c/tmplts]
utf-8 с BOM        len= 100 -> [/home/user/tmplts, /srv/1c/tmplts]
utf-16le С BOM     len= 196 -> [/srv/1c/tmplts]          <- потеряна первая строка
utf-16le БЕЗ BOM   len= 194 -> []
utf-16be С BOM     len= 196 -> []

После:

utf-8 без BOM      len=  97 -> [/home/user/tmplts, /srv/1c/tmplts]
utf-8 с BOM        len= 100 -> [/home/user/tmplts, /srv/1c/tmplts]
utf-16le С BOM     len= 196 -> [/home/user/tmplts, /srv/1c/tmplts]
utf-16le БЕЗ BOM   len= 194 -> [/home/user/tmplts, /srv/1c/tmplts]
utf-16be С BOM     len= 196 -> [/home/user/tmplts, /srv/1c/tmplts]
cp1251 кириллица   len=  53 -> [C:\Шаблоны 1С\tmplts]

Файл читается один раз в bytes, кодировка берётся по BOM, без BOM перебираются utf-8cp1251utf-16-leutf-16-be.

Критерий выбора — наличие самого ключа в декодированном тексте, а не отсутствие исключения и не эвристика по \x00. Issue предлагал второе; проверка по ключу строже и попутно закрывает utf-16be без BOM, который на \x00-эвристике прошёл бы как «валидный» (байты UTF-16BE, прочитанные как LE, дают иероглифы без нулей).

Разбор строк идёт после декодирования, поэтому частичный результат больше не накапливается между попытками — на файле из 251 строки возвращалось 174.

Остальное в том же слое

  • open_folder читает код возврата. xdg-open отвечает 3 или 4, когда нет ассоциации inode/directory, а пользователь видел «открыл».
  • Дочерней команде восстанавливается LD_LIBRARY_PATH из LD_LIBRARY_PATH_ORIG. В onefile-сборке gio/kioclient/gtk-launch подхватывали Qt и libstdc++ из каталога распаковки вместо системных. Замерено на поведении бутлоадера; на готовой Linux-сборке не проверялось — это остаётся непроверенным и здесь.
  • Путь передаётся абсолютным, а не через --. xdg-open разделитель опций не понимает и отвечает unexpected option с кодом 1, то есть вариант из issue сломал бы открытие папки на всех Linux.
  • GUI показывает отказ через QMessageBox с путём в тексте. show_message(..., is_error=True) тут не годится: он переводит окно в UIState.ERROR и прячет саму кнопку «Открыть папку», а в состоянии SUCCESS комбобокс с путём уже скрыт — узнать каталог было бы негде.
  • SettingsService.get_output_path откатывается на default, если QSettings вернул не строку. Правленный извне конфиг даёт list, и os.path.normpath ронял запуск до window.show(). ,.join не использую: Qt при разборе срезает пробел после запятой, и склейка дала бы молча неверный каталог вместо честного отката.

Тесты

254 → 274. Сняты три xfail(strict=True) — они перевернулись в XPASS(strict) ровно в тот момент, когда код починился, и это был первый сигнал, что правка работает:

[XPASS(strict)] #18: платформа 1С пишет конфиг в UTF-16, сейчас такой файл даёт пустой список
[XPASS(strict)] #18: utf-16le декодирует любую чётную последовательность без исключения

Обе новые проверки красные на обратных мутациях:

мутация результат
вернуть выбор «первый кодек, который не упал» 2 failed — utf-16 без BOM и большой cp1251
перестать читать returncode 1 failed — rc=4 больше не отличается от успеха

Одно ожидание в тесте я написал неверно и поправил по факту: при откате на default метка в комбобоксе выходит (last used), а не (default) — ветка last_used срабатывает первой и занимает тот же путь. Это существующее поведение разметки, а не следствие отката; issue про него предупреждал, трогать здесь не стал.

274 passed, 2 xfailed
покрытие 87.17%, os_utils.py и settings_service.py — 100%
ruff: All checks passed

…ствию ошибки

Перебор останавливался на первом кодеке, который не бросил исключение,
а utf-16le не бросает почти никогда: любая последовательность чётной
длины декодируется в иероглифы. Из-за этого корректно разбирался только
utf-8, cp1251 проходил через раз — в зависимости от чётности размера
файла, — а UTF-16 не разбирался вовсе. Каталоги шаблонов молча не
попадали в выпадающий список, и пользователь не знал, что подсказка
потерялась.

Файл теперь читается один раз в bytes, кодировка берётся по BOM, а без
BOM перебираются utf-8, cp1251, utf-16-le и utf-16-be. Критерий выбора
прямой: в декодированном тексте должен найтись сам ключ. Разбор строк
идёт после декодирования, поэтому частичный результат больше не
накапливается между попытками — на файле из 251 строки возвращалось 174.

Рядом в том же слое:

- open_folder читает код возврата. xdg-open отвечает 3 или 4, когда нет
  ассоциации inode/directory, а пользователь видел «открыл».
- Дочерней команде восстанавливается LD_LIBRARY_PATH из
  LD_LIBRARY_PATH_ORIG: в onefile-сборке gio и kioclient подхватывали Qt
  и libstdc++ из каталога распаковки вместо системных.
- Путь передаётся абсолютным, а не через разделитель опций "--":
  xdg-open его не понимает и отвечает кодом 1.
- GUI показывает отказ открытия папки через QMessageBox с путём в тексте.
  show_message тут не годится: он переводит окно в UIState.ERROR и прячет
  саму кнопку, а в состоянии SUCCESS комбобокс с путём уже скрыт.
- SettingsService.get_output_path откатывается на default, если QSettings
  вернул не строку. Правленный извне конфиг даёт list, и os.path.normpath
  ронял запуск до window.show() — без окна и без сообщения.

Тесты: 254 -> 274, сняты три xfail(strict=True). os_utils.py и
settings_service.py покрыты полностью.

Closes #18
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 17, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-17T12:38:58.923923Z 742b519 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

os.sep выглядит платформенно-независимым, но форма абсолютного пути им
не описывается: на Windows он начинается с буквы диска, а не с
разделителя, поэтому startswith(os.sep) там всегда ложен.
@zeegin
zeegin merged commit 193b625 into main Sep 17, 2026
3 checks passed
@zeegin
zeegin deleted the fix/1cestart-parsing branch September 17, 2026 13:20
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.

Разбор 1cestart.cfg работает только в UTF-8: каталоги шаблонов теряются

1 participant