Commit Graph

23 Commits

Author SHA1 Message Date
Tran G. (Revernomad) Khoa
4fde566cf4 Merge branch 'main' of https://git.revoluxiant.io.vn/revernomad17/arma-modlist-tools 2026-04-10 22:38:20 +07:00
Tran G. (Revernomad) Khoa
68fcaaf6d9 fix: decode run_tool subprocess output as UTF-8 to handle tqdm Unicode chars on Windows 2026-04-10 22:37:35 +07:00
revernomad17
06f0c6eb92 fix: guard against None stdout in fix_console_encoding for pythonw.exe
When launched via pythonw.exe (no console), sys.stdout/stderr are None.
Accessing .encoding on None raised AttributeError, caught by the GUI's
pipeline import guard and shown as 'Failed to load pipeline'. Added
None check before the encoding check in fix_console_encoding(), added
a test, and documented the pitfall in CLAUDE.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 10:10:13 +07:00
Tran G. (Revernomad) Khoa
3276f4b63f fix: silent pipeline log and server indexing progress
Three issues caused the Logs view to appear blank during a real pipeline run:

1. `from run import step_fetch, step_link` was outside the worker's
   try/except/finally. An import failure silently killed the thread,
   leaving _pipeline_done uncalled and the Run button stuck disabled
   forever. Now wrapped in its own try/except that posts the error to
   the log and resets the UI.

2. `build_server_index` makes N sequential HTTP requests (one per mod
   folder's meta.cpp) with no output during the scan. Added an optional
   `progress_fn(current, total, name)` callback; step_fetch wires it to
   print progress every 25 folders so the log never goes silent.

3. No immediate feedback after clicking Start — the log was blank until
   the worker thread started printing. Now posts a "Pipeline started"
   banner from the main thread before the worker launches.
2026-04-08 23:35:26 +07:00
Tran G. (Revernomad) Khoa
e0c2dfb32a docs: update README and VI guide for orphan cleanup and test count
- Add quick-reference card at top of README (short-form cheat sheet)
- Document clean_orphans.py in ToC, Individual Scripts, folder structure
- Update GUI Tools view table: note Clean Orphans tab
- Fix Running Tests: 96 → 142, remove stale '1 failing test' note, list all 15 groups
- Add clean_orphans.py to folder structure tree
- Add cleaner.py to arma_modlist_tools/ listing
- VI guide: add summary table for Tools tabs, document Clean Orphans tab in full
- VI guide: add 'Mod thừa / Orphan' to glossary
2026-04-08 20:11:41 +07:00
Tran G. (Revernomad) Khoa
5c824280c6 chore: ignore coverage artifacts (.coverage, *.py,cover, htmlcov/) 2026-04-08 20:04:02 +07:00
Tran G. (Revernomad) Khoa
90cc6c00ff feat: add orphan mod cleanup tool with GUI integration and live-server tests
- Add arma_modlist_tools/cleaner.py: find_orphan_folders() detects @ModName
  folders no longer referenced in comparison.json; uses _normalize_name from
  fetcher for consistent three-level matching
- Add clean_orphans.py: CLI with --dry-run and --yes/-y flags; junction-safe
  deletion via _is_junction() guard before shutil.rmtree
- Add Clean Orphans tab to gui/views/tools.py: scrollable checkbox list,
  background scan/delete threads, pending-done-msg pattern for post-scan
  status, EN/VI localization strings in gui/locales.py
- Add 23 unit tests (section 12), 6 E2E subprocess tests (section 13),
  23 coverage-gap tests (section 14), 9 live-server fetcher tests (section 15)
- Fix leaked builtins.open mock in _test_read_os_release_parses_file
- Overall coverage: 84% → 93%; fetcher.py: 36% → 72%
2026-04-08 20:02:42 +07:00
Tran G. (Revernomad) Khoa
85bc406236 fix: smooth GUI during pipeline downloads and harden wizard connection test
GUI log batching (_poll_log now drains queue into a single CTkTextbox.insert
call per 80 ms tick instead of N calls, each with see("end") scroll).

_QueueWriter strips ANSI/CSI escape codes and bare \r before enqueuing so
tqdm progress output is legible in the log textbox. OSC sequences terminated
by both BEL (\x07) and ST (\x1b\) are handled.

Wizard "Test Connection" moved off the main thread: requests.get runs in a
daemon thread; result posted back via after(0, ...). Widget refs captured
before thread launch to prevent stale updates if user navigates away. Bare
except narrowed to TclError (destroyed-widget guard only).

Code quality: import os moved to module level in app.py; _read_raw_config()
helper extracted to deduplicate dual raw config.json reads; return type
annotations added to _get_view_class, _get_dashboard, and cfg property.

Tests: 11 new unit tests for _QueueWriter (RED -> GREEN on OSC-ST fix).
2026-04-08 17:27:25 +07:00
Tran G. (Revernomad) Khoa
903cd366e2 feat: add Vietnamese localization to GUI
Introduces a two-language (EN/VI) i18n system with hot-swap support.
All ~160 user-facing strings are centralised in gui/locales.py; views
retranslate in-place on language switch without restarting the app.

- gui/locales.py: new file — _EN/_VI dicts, t() lookup, set_language(),
  get_language(); assert guard ensures EN/VI key parity
- gui/app.py: switch_language(), _apply_startup_language(),
  _save_language_pref(), _rebuild_nav_labels(); language stored in
  config.json under ui.language; pipeline step headers and run_tool
  status lines translated
- gui/views/settings.py: Language dropdown card (English / Tiếng Việt)
- gui/views/dashboard.py: all strings via t(); static header widgets
  stored and retranslated in refresh()
- gui/views/mods.py: all strings via t(); _STATUS dict built at call
  time so server status labels update on language switch
- gui/views/tools.py: all strings via _translatable registry; tab names
  and segmented-button values kept in English (CTkTabview constraint)
- gui/views/logs.py: title + Copy/Clear buttons stored, retranslated
- gui/wizard.py: all 3 pages fully translated
- docs/huong-dan-su-dung.md: full Vietnamese user guide
- CLAUDE.md: documents localization architecture and constraints
2026-04-08 16:58:41 +07:00
revernomad17
4478ec3cab docs: document run_tool subprocess streaming pattern in CLAUDE.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 16:11:24 +07:00
revernomad17
b7dbf54512 Fix tool log streaming — switch from subprocess.run to Popen
subprocess.run with capture_output=True blocked until process exit,
dumping all output at once. Now uses Popen with line-by-line reading,
-u flag, and PYTHONUNBUFFERED=1 so logs stream in real time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 16:10:36 +07:00
revernomad17
80ecd3a919 docs: document _find_folder three-level name matching in CLAUDE.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:57:11 +07:00
revernomad17
6197659568 Fix mods view showing wrong download status for name-mismatched mods
_find_folder() used a plain lowercase compare which failed when the
server canonical folder name differs from the comparison.json mod name
in more than just case (e.g. spaces vs underscores: "NIArms All in One"
vs "@NIArms_All_In_One"). These mods showed ✗ even though the pipeline
found and linked them correctly.

Add a normalized-name fallback (strips non-alphanumeric, same logic as
fetcher._normalize_name) so the lookup matches the same way the fetcher
resolves mods from the server index.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:54:30 +07:00
revernomad17
85fdfebd74 Fix failing integration test after adding test HTML presets
comparison.json was stale (built from 2 test presets only) while
modlist_html/ now has 4 files. Regenerated comparison.json from all
presets to restore consistency.

Also added _SkipTest exception to the test harness so the
consistency check skips gracefully on a fresh clone (comparison.json
is gitignored) instead of raising AssertionError.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:37:56 +07:00
revernomad17
57895a04d3 Add GUI desktop application
- Add gui/ package: CustomTkinter app with dashboard, mods, tools, logs,
  and settings views; first-run SetupWizard for config.json generation
- Add gui.py root entry point (calls gui.run_app())
- Add selection.json for GUI selection state persistence
- Add customtkinter to requirements.txt
- Fix link_mods.py minor issues surfaced during GUI integration
- Add modlist_html/Test_Preset_A.html and Test_Preset_B.html as example inputs
- Update README.md: add GUI prerequisites, gui.py script section, gui/ folder
  structure, customtkinter to prerequisites table
- Update CLAUDE.md: add python gui.py to common commands, document GUI package
  architecture and views

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:33:58 +07:00
revernomad17
595544e94f add CLAUDE.md for Claude Code context
Covers: common commands, package vs CLI architecture, data flow,
group naming convention, server index structure, junction/symlink
rules (critical: never shutil.rmtree), check_names two-pass
classification, Python 3.9 from __future__ requirement, and
test suite structure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 17:33:16 +07:00
revernomad17
ef2f6329f6 update README: add check_names.py, update Python version, migrating existing mods section
- Documents check_names.py (--fix, --fix-ids, status codes table)
- Adds Migrating Existing Mods section for servers with pre-existing mods
- Updates Python requirement from 3.11 to 3.9
- Updates test count from 71 to 85
- Updates check_deps example output to show 3.9.2
- Adds check_names.py to folder structure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 17:29:50 +07:00
revernomad17
9dea44fa3d check_names: add --fix-ids to repair wrong steam_ids in meta.cpp
ID_COLLISION status (previously NOT_ON_SERVER) now has its own label
and shows the bad steam_id in the report output.

--fix-ids cross-references comparison.json to find the correct
publishedid for each colliding folder and rewrites it in-place in
meta.cpp using regex, preserving all other content.

New helpers: _lookup_detailed (returns server_name + local_sid tuple),
_write_steam_id (regex-replace publishedid in meta.cpp),
_build_comparison_id_map (builds normalized_name -> steam_id map
from comparison.json).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 17:21:21 +07:00
revernomad17
2ab6d87532 fix check_names false positives from server steam_id collisions
When a server folder's meta.cpp publishedid appears in a local folder
that has a completely different name, the steam_id lookup was returning
a wrong MISMATCH. Added a two-pass classification: any proposed rename
target that is already an exact OK match for another folder is
reclassified as NOT_ON_SERVER (steam_id collision) instead of MISMATCH.

_resolve_status moved to module level and takes ok_disk_names as a
parameter so it can be unit-tested independently.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 17:15:30 +07:00
revernomad17
e706e71f29 add check_names.py: detect and fix mod folder name mismatches
Compares @Mod folder names in downloads/ against server canonical
names. Uses meta.cpp steam_id as primary lookup (most reliable),
falls back to normalized name. Reports OK / MISMATCH / NOT_ON_SERVER
per folder.

--fix mode renames mismatched folders and updates arma_dir junctions
in one pass so the full pipeline can run cleanly afterward.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 16:56:10 +07:00
revernomad17
da9e7782d6 fix Python 3.9 compatibility (str | None union syntax)
parser.py and update_mods.py were missing
'from __future__ import annotations', causing a TypeError on
Python < 3.10 when the X | Y union syntax is evaluated at runtime.
All other modules already had the import.

Also lowers MIN_PYTHON from 3.11 to 3.9 -- the toolchain does not
use any Python 3.10/3.11-specific stdlib features beyond the union
annotation syntax which is now handled by the future import.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 16:16:38 +07:00
revernomad17
86a6ab9b01 fix check_deps.py crash on Python < 3.10
str | None union syntax requires Python 3.10+. Adding
from __future__ import annotations makes all annotations
lazy so the script can run on older Python and report the
version requirement instead of crashing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 16:13:47 +07:00
revernomad17
91a38b269b Initial release: full Arma 3 mod management toolchain
Pipeline: parse HTML presets, compare modlists, download from Caddy
file server, create junctions/symlinks to Arma 3 Server directory.
Includes update/sync flows, missing-mod reporting, OS compat layer,
shared config, dep checker, comprehensive test suite (71 tests).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 16:04:36 +07:00