From bb5fd15df7fc65a2295a8a44cc070fe83894d7cb Mon Sep 17 00:00:00 2001 From: longvo920 Date: Mon, 7 Sep 2026 23:40:39 +0700 Subject: [PATCH] docs: rewrite README voice, trim CLAUDE.md to invariants The README read like generated prose: 28 em-dash asides, metaphors the repo's own doc rules ban ("the generator's fingerprints", "not the same kind of nothing"), and filler intensifiers. Same claims, plainer sentences, 6 em dashes left. CLAUDE.md dropped from 289 to 140 lines. Kept the invariants that are expensive to rediscover from the code (fail-safe rule, verdict vocabulary and where it is decided, shared seams, stdlib-only .pyz, exit-code contract); dropped the prescriptive workflow sections. The Vietnamese README was restructured separately; fixed four anchors that pointed at English headings docs/vi/usage.md does not have, and a stray non-Vietnamese word in the contributing note. --- CLAUDE.md | 460 ++++++++++++++++++---------------------------- README.md | 302 +++++++++++++++++++++--------- docs/vi/README.md | 378 +++++++++++++++++++++---------------- 3 files changed, 605 insertions(+), 535 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 00e3f98..e7f3227 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,289 +1,185 @@ -# CodeGen Compare Tool — working rules - -This tool diffs two AUTOSAR MATLAB/Simulink codegen folders and reports **only -the changes that matter**. Regenerating a model rewrites timestamps, UUIDs, -comment banners, version stamps and auto-generated identifiers even when the -behaviour is identical; the tool classifies every hunk so the reviewer is not -drowned in that churn. - -The whole product is a claim: *"you can ignore what I hid."* Every rule below -exists to keep that claim true. - -Repo `codegen-compare-tool`, local folder `code-review`, package -`compare_tool`. Where this file and `~/.claude/CLAUDE.md` disagree, this one -wins. - -`docs/architecture.md` explains how the pieces fit and why — layering, the two -diff passes, the shared seams, the result-dict contract. Read it before a change -that crosses module boundaries; this file is the rules, that one is the map. - -## 1. Fail-safe is not negotiable - -**If it cannot be *proven* to be noise, it is a real change.** A rule that is -"probably safe" is not safe: a missed real change is the one failure mode this -tool exists to prevent, and a reviewer who stops trusting the filter stops -using the tool. - -- A path that could not be listed, read or compared is a loud `error`: exit - code `2`, a red banner in the report and the viewer, never a silent - omission. `--exit-zero` does not suppress it. -- A noise pattern **beside** a real change never launders it. Always add a - test in that shape — see `test_arxml_sw_version_bump_beside_real_change_stays_real`. -- Never widen a rule to make a diff look cleaner. Narrow claims must be exact. - -When adding a noise rule, the checklist is: text-based (preserve line count), -anchored regex, joined into the ruleset shadow, one labelled variant in -`_build_variants`, plus two tests — "alone it is noise" and "next to a real -change it stays real". - -## 2. The classification vocabulary is fixed - -`identical` · `comment-only` · `ignorable-only` · `real-change` · `added` · -`deleted` · `error` - -`comment-only` is deliberately separate from `ignorable-only`: "only the -comment banner moved" triages very differently from "an identifier was -renamed". A file mixing comments *with* other noise stays `ignorable-only` — -the narrower claim has to be exact. The verdict is decided in exactly one -place, `diff_engine._status_of`. - -Only noise verdicts are foldable (`scanner.FOLDABLE`). `real-change`, `added`, -`deleted` and `error` can **never** be folded away by a UI toggle. - -**A viewer toggle never changes a verdict.** Unticking `Comment` or -`Unimportant` **greys** those rows (`view_model.mute_rows`) and drops them from -the minimap and `F7`/`F8` — nothing else. The file keeps saying Comment, the -counts keep counting it, and `Hide identical` still leaves it in the tree, -because it is not identical. Re-judging it to `identical` is what the viewer -used to do, and it was wrong twice over: the tree then disagreed with the -exported report about the same file, and "Identical" is the one word a reviewer -is entitled to read as *nothing differs here at all*. - -Removing those rows instead of greying them was tried and reverted too: a -regenerated file is mostly banner churn, so a `⋯ N lines hidden` placeholder -took away the context the surviving hunks have to be read in. - -Both noise verdicts wear the same `≈` mark, in the report's tree and the -viewer's alike — they are one answer to "must I read this?", and the label -beside the mark says which kind of nothing it is. The mark lives once, in -`view_model.VERDICT_MARK`: the two trees each kept a copy and drifted, so the -same file read `≉` in one and `≈` in the other. - -## 3. One seam per shared decision - -Any fact two renderers need lives in **one** module they both import. -`compare_tool/view_model.py` holds `mode_of`, `char_span`, `aligned_rows` and -`mute_rows`; `compare_tool/theme.py` holds every colour as a named role, one -value per theme. The HTML report and the Qt viewer both consume them, so they -cannot disagree about what changed or how it is coloured. - -A colour literal outside `theme.py` is a bug: it paints one theme correctly and -the other by accident. Add a role to **both** palettes (an import-time assert -enforces it), then use `var(--role)` in the report's CSS or `theme.c(role)` in -Qt. - -Re-implementing a mapping inline "because it is only four lines" is the bug: -the copies drift the moment a new kind is added. If you find a duplicated -mapping, promote the original to public and import it. - -## 4. The record is never the filtered view - -An exported report is built from the **raw scan**, not from what is on screen -(`MainWindow._export_report` uses `self._raw_results`). A category the reviewer -collapsed in the UI must still appear in the file with its real verdict — -otherwise an exported report could show a file as Identical when it is not. - -Same principle for the quick-changes rollup: it reports the scan, never the -folded view. - -## 5. Dependencies are fine — the compare core is the exception - -Add libraries where they help. The viewer, the packaging spec, the tests and -any dev script take whatever they need; no need to ask first. - -The exception is **what ships in `compare_tool.pyz`**: the scan, the rules, the -diff, the report, the review store and `gitsource` import stdlib only. That -zipapp needs nothing installed, and is the documented fallback for -the machines where antivirus blocks the `.exe` — one third-party import in -`scanner.py` and it stops running there, which is a shipped promise broken by -an import nobody reviewed. - -PySide6 therefore lives **only** under `compare_tool/qtviewer/` and is imported -lazily, when the viewer opens. Viewer logic that can be Qt-free must be Qt-free -— `tree.py`, `summary_model.py` and `compare_tool/resources.py` have no PySide6 -import, so the suite runs headless on a box with no Qt. Widgets stay dumb: they -walk a model and paint it. - -Wanting a library in the core is a legitimate answer — it just costs the `.pyz` -and the "zero dependencies" line in the README. Say that out loud and let the -call be made; do not smuggle the import in and leave the claim standing. - -Two more promises the same machines depend on: - -- **`requires-python = ">=3.8"`.** No `match`, no `X | Y` at runtime; `list[str]` - in an annotation needs `from __future__ import annotations`. CI runs 3.8 and - 3.11 on Linux and Windows, so a 3.10-ism passes locally and fails there. -- **The HTML report is self-contained.** CSS and JS inline, no CDN, nothing - fetched when the file is opened. It gets mailed around and opened on boxes - with no internet; a report that renders blank there is worse than no report. - -## 6. Verify UI by rendering it, not by reasoning about it - -Tests pass on layouts that look broken. Every UI change gets looked at: +# CodeGen Compare Tool -Write a throwaway script under `%TEMP%` that builds the widget, grabs it and -saves a png — then read the png: - -```powershell -$env:QT_QPA_PLATFORM = 'offscreen' -python $env:TEMP\smoke.py # widget.grab().save(png) +Tool for comparing AUTOSAR MATLAB/Simulink codegen folders and identifying real changes while filtering generator noise. + +Repo: `codegen-compare-tool` +Package: `compare_tool` +Architecture: `docs/architecture.md` + +This file contains **project invariants only**. Do not duplicate general coding guidance. + +--- + +## Core Rule + +**If a difference cannot be proven to be noise, it is a real change.** + +Never hide, downgrade or silently ignore a potentially real change. + +A scan/read/compare failure is an `error`, never an empty result. + +--- + +## Verdicts + +Supported file verdicts: + +```text +identical +comment-only +ignorable-only +real-change +added +deleted +error +``` + +* Verdict logic has a single source of truth. +* Only noise verdicts may be folded/hidden by the UI. +* `real-change`, `added`, `deleted` and `error` must remain visible. +* UI filtering must never change the underlying verdict or counts. +* Reports and summaries must use the **raw scan result**, not the filtered UI state. + +--- + +## Noise Rules + +A noise rule must be conservative. + +Every new rule should prove both: + +1. The pattern alone is noise. +2. The same pattern next to a real change remains a real change. + +Prefer text-based, anchored rules that preserve line structure where possible. + +Never add a rule simply because it makes a diff smaller. + +--- + +## Architecture + +Keep shared decisions in one place. + +* Shared comparison/view-model logic must not be duplicated between CLI, viewer and report. +* Shared visual roles belong in `theme.py`; do not add raw colour literals elsewhere. +* The comparison core must remain independent of Qt. +* `compare_tool/qtviewer/` is the only Qt-dependent area. +* Keep reusable parsing/model modules Qt-free so headless tests continue to work. + +See `docs/architecture.md` before making structural changes. + +--- + +## Dependencies + +The comparison core and `compare_tool.pyz` must remain **Python standard-library only**. + +PySide6 is allowed only for the desktop viewer and must be imported lazily. + +The CLI must remain usable on locked-down machines with no installed third-party dependencies. + +Python support: + +```text +>= 3.8 ``` -and, for anything about colour or legibility, a real window on the desktop. -This is not ceremony — rendering caught a near-black wordmark invisible on the -dark chrome, a header band pushing the diff into the bottom half, and an -OLD/NEW banner whose red/green field read as a changed diff row. No assertion -would have caught any of them. - -**A failing check is guilty until proven otherwise — of being wrong itself.** -A smoke script once reported "0 visible files" because its tree walker only -recursed into children and missed root-level items. Fix the harness, not the -app. - -## 7. Do not repeat a fact across surfaces - -Screen space spent restating something is space not spent on the diff. - -- The verdict is the tree's Status column, so the diff header does not repeat - it — it names the file, the moved-line note and `Change 3 of 7`. -- The quick-changes panel does not list changed files: the folder tree above - already does. - -Before adding a label, ask what already shows it. - -## 8. Degrade, never crash - -A cosmetic failure must not take the tool down, and a missing dependency must -not print a traceback. - -- A missing icon leaves a button with its text label (`resources.py` getters - return `None`, callers cope). -- No PySide6 → a plain sentence explaining the `viewer` extra, not a stack - trace. -- Windows consoles run legacy codepages: `stream.reconfigure(errors='replace')` - so a print can never kill a run. - -The exception is the compare itself: a render or scan failure is **loud**, and -never an empty, clean-looking result. - -## 9. Packaging - -The exit code is a contract with somebody's pipeline. Do not change it: - -| Code | Meaning | -|---|---| -| 0 | No real change | -| 1 | Real changes found (the CI gate) | -| 2 | Compare INCOMPLETE — a path could not be listed, read or compared, or the report could not be written (no record == not a clean run) | - -`build.ps1` produces one `dist\compare-tool.exe` carrying the CLI and the -viewer. It is a **console** build on purpose: a terminal run must keep stdout -and its exit code (CI gates on `1` / `2`). A windowed build makes the shell -stop waiting and throws the exit code away — so the console *window* is hidden -at runtime instead, and un-hidden on a crash. - -`main.viewer_requested()` owns the "which front end does this argv want" -decision; the frozen entry point asks it rather than re-deriving it. - -### Cutting a release - -Two moves, and the repo is only edited by the first one. - -1. A normal PR bumps `compare_tool.__version__` and moves the CHANGELOG - `[Unreleased]` entries under `## [X.Y.Z] — `. A human merges it. -2. `.github/workflows/release.yml` builds and publishes: - - ```bash - python packaging/release_check.py 1.3.1 # same check the workflow runs - gh workflow run release.yml --ref main -f version=1.3.1 # rehearsal - gh workflow run release.yml --ref main -f version=1.3.1 -f publish=true # for real - ``` - -**The default does not publish.** A run without `publish` builds both -artifacts, runs each one against the fixtures and stops, so the expensive half -can be proven without creating a tag that cannot be taken back. Both runs -upload the binaries, because the point of a rehearsal is to be able to look at -what would have shipped. - -`packaging/release_check.py` owns every precondition — version matches -`__init__.py`, the CHANGELOG has that section, nothing is left under -`[Unreleased]` — and prints what to change rather than just failing. It is one -script so the answer is the same locally and in CI. The workflow adds the two -facts a file cannot know: the ref is `main`, and the tag is not taken. - -Releases are not moved. A published version is refused, never overwritten. - -## 10. Docs are written for someone who did not build the tool - -The README, `docs/usage.md`, the CHANGELOG and the `docs/vi/` translations ship -with the product. The reader is an engineer who knows AUTOSAR and Simulink but -has never seen this codebase — not a reviewer who already knows why a rule -exists. - -- **Define the thing before leaning on it.** "A model's ARXML is its interface - contract, its A2L is its calibration surface" tells that reader nothing. - "Its ARXML declares which ports, runnables and events the model has; its A2L - declares the calibration and measurement variables" tells them what the files - hold, so the rule built on top of it lands. -- **No metaphor where a plain description fits.** "the fingerprint of a quick - regen", "only the screen is quiet", "a near-tie is not an answer" all read as - writing. Say what happens: "you probably regenerated only model A", "the lines - are still in the file, the report just doesn't render them", "generated files - resemble each other, so a close second match isn't trustworthy". -- **Give the user's reason, not the internal one.** *Why* Comment is its own - category is rule 2's problem. The doc's job is "a rewritten comment you can - skim; a renamed identifier you have to check." -- **Three conditions in one paragraph become a list.** Prose that chains - "and… and… but only when…" is where a reader loses the thread. The rename and - reorder rules are both lists for that reason. -- **CHANGELOG entries lead with the outcome**, one bold sentence naming what - the user now gets, then a sentence or two on when they hit it. Same language - rules as above. - -`docs/vi/` translates the **meaning**, never the words. "Hợp đồng interface" is -what "interface contract" turns into when it is translated literally, and it is -meaningless in Vietnamese. Terms that live in the tool and in the industry — -port, runnable, calibration, noise, hunk, verdict — stay in English rather than -being forced into a Vietnamese word nobody uses. The English file is the -source of truth: when a fix to the Vietnamese actually changes what a sentence -claims, fix the English in the same change or the two versions quietly diverge. - -## 11. Workflow - -- **Commit per phase / per goal batch.** The message explains *why*, not what - the diff already shows. -- **Run the suite before every commit**: `python -m unittest discover -s tests`. - Add a test for any new rule. `python -m ruff check .` too — it is a CI gate, - and it is what catches a `list[str]` or `X | Y` that a modern interpreter - accepts and 3.8 does not. -- **A green suite is not the same as a suite that ran.** Qt tests skip - themselves when PySide6 is absent, so CI installs it on the 3.11 legs and - asserts the import. The 3.8 legs stay dependency-free on purpose: they are - the proof that the stdlib-only core still runs with nothing installed. -- **Say when you reinterpreted a request.** "Remove rescan" was implemented as - removing both the button and rescan-on-toggle, because folding is a pure - function of the hunks — that reading was stated, not assumed silently. -- **Report outcomes plainly.** If a check was skipped or a push failed and - succeeded on retry, say so. -- Comments explain the *reason* a line is the way it is, especially where the - obvious implementation is wrong (why a console build, why raw results, why - an anchored regex). Match the density of the surrounding file. +Do not introduce syntax/runtime features unavailable on Python 3.8. + +The HTML report must remain fully self-contained: + +* CSS inline +* JavaScript inline +* No CDN +* No network requests + +--- + +## Fail Safe + +Prefer graceful degradation for non-critical UI resources. + +Examples: + +* Missing icons → keep the text label. +* Missing PySide6 → provide a clear viewer-install message. +* Legacy Windows console → handle encoding safely. + +But **never degrade silently for comparison failures**. + +A failed or incomplete comparison must be obvious and must not look like a clean comparison. + +--- + +## Exit Codes + +```text +0 No real changes +1 Real changes found +2 Compare incomplete / error +``` + +Exit code `2` is part of the CI contract and must never be suppressed by `--exit-zero`. + +--- + +## Release + +For a normal release: + +1. Bump `compare_tool.__version__`. +2. Move the relevant CHANGELOG entries from `[Unreleased]` to the new version/date. +3. Let the release workflow build and publish. +4. Never overwrite an already published version. + +`packaging/release_check.py` owns release preconditions. + +--- + +## Documentation + +The English documentation is the source of truth. + +Vietnamese documentation in `docs/vi/` should translate meaning, not terminology. + +Keep industry/tool terms in English where appropriate: + +```text +port, runnable, calibration, noise, hunk, verdict, SWC, A2L, ARXML +``` + +When changing a documented behavior or claim, update the relevant documentation in the same change. + +--- + +## Common Commands ```bash +# Compare python -m compare_tool --report out.html -python -m unittest discover -s tests # unittest, NOT pytest -python -m ruff check . # correctness gate, incl. the 3.8 promise -.\build.ps1 # dist\compare-tool.exe (needs pyinstaller + PySide6) -.\build.ps1 -Pyz # plus dist\compare_tool.pyz -.\build.ps1 -PyzOnly # zipapp only, no build dependencies + +# Tests +python -m unittest discover -s tests + +# Lint +python -m ruff check . + +# Build EXE +.\build.ps1 + +# Build EXE + zipapp +.\build.ps1 -Pyz + +# Zipapp only +.\build.ps1 -PyzOnly +``` + +Before committing: + +```bash +python -m unittest discover -s tests +python -m ruff check . ``` + +Qt tests may skip when PySide6 is unavailable, so a green test run without PySide6 does not prove viewer tests were executed. diff --git a/README.md b/README.md index 7590096..61c54b8 100644 --- a/README.md +++ b/README.md @@ -1,174 +1,296 @@

+ CodeGen Compare Tool +

- Test - Python 3.8+ - License: MIT - Release + +Test Python 3.8+ License: MIT Release +

-

🇻🇳 Tiếng Việt: README · Hướng dẫn · Kiến trúc

+

+🇻🇳 Tiếng Việt: +README · +Hướng dẫn · +Kiến trúc +

+ +# CodeGen Compare Tool -Regenerate a Simulink model and the diff against yesterday's output can run into thousands of lines — a new timestamp banner, a fresh UUID on every ARXML element, variable names the codegen renumbered from scratch. Somewhere in that pile there might be an actual behaviour change, or there might not be, and finding out by scrolling is how a five-minute code review turns into an afternoon. +**See what actually changed after AUTOSAR code generation.** -This tool reads both folders, works out which of those thousands of lines are just the generator's fingerprints and which ones are real, and shows you only the second kind. Point it at an old codegen output and a new one, and it tells you — in plain terms, and in AUTOSAR terms — what actually changed. +Regenerating a Simulink/AUTOSAR project can produce thousands of changed lines caused by timestamps, UUIDs, generated identifiers and other generator churn. -It gives you two ways to look at that answer: a **desktop viewer** for reviewing interactively, and a **CLI** that writes a self-contained **HTML report** and sets an exit code your pipeline can gate on. Both run on the exact same compare engine, so you never get two different answers depending on which one you opened. +CodeGen Compare Tool compares two generated-code snapshots, filters out changes that can be proven to be generator noise, and highlights the changes that matter. -| | What it's for | When it runs | -|---|---|---| -| **Viewer** | Reviewing by hand — folder tree, two-pane diff, minimap, review notes | No folders given on the command line (or you double-click the `.exe`) | -| **CLI** | Pipelines and scripts — writes the report, exit code gates the build | Both folders named on the command line | +It compares not only generated **C/C++ and XML**, but also the **AUTOSAR and A2L objects** behind them. -The compare itself — scanning, the noise rules, the diff, the HTML report — is **pure Python standard library**. Nothing to `pip install`, no server, no network call, ever. The viewer is the one piece that needs PySide6, and even that is only imported the moment it actually opens. +--- -📖 **[Usage guide](docs/usage.md)** — every flag, the viewer's shortcuts, the exact noise rules, how the report is laid out, CI and packaging. +## Why CodeGen Compare? -🏗 **[Architecture](docs/architecture.md)** — how the pieces fit together and why. +General-purpose diff tools compare text. They cannot tell whether a changed UUID is noise, whether a generated identifier was safely renamed, or whether ARXML and generated C are no longer consistent. -## Why not Beyond Compare, WinMerge or `diff`? +CodeGen Compare is designed specifically for generated automotive software. -Those are excellent general-purpose diff tools. The difference is that they diff -*text*, and this tool diffs *AUTOSAR codegen* — it knows what a regenerate does -to a file and what it means. +| | General diff tools | CodeGen Compare | +| ---------------------------- | ---------------------------- | ------------------------------------------ | +| Generator timestamps / UUIDs | Show as changes | Filtered automatically | +| Generated identifier renames | Look like changes everywhere | Recognised when safely explainable | +| AUTOSAR changes | Text only | SWCs, ports, runnables, events, RTE access | +| A2L changes | Text only | Characteristics / measurements | +| Incomplete regeneration | Usually invisible | Cross-file consistency check | +| CI build gate | Manual | Exit codes + JSON + SARIF | -| | Beyond Compare / WinMerge / `diff` | This tool | -|---|---|---| -| Timestamp / UUID / version-stamp churn | shown as changes — you filter it by eye or by hand-written rules | classified as noise automatically; a file whose only differences are noise reads as such | -| Renamed generated identifiers (`rtb_AND_c4nxjoom3d` → `rtb_AND_j2kqp1wxab`) | a change on every line that uses the name | recognised as a 1-to-1 rename and folded — but only when the whole file's mapping is consistent, so a real rename stays a real change | -| "What changed in the model?" | not answered — it is a text tool | an AUTOSAR summary: which ports, runnables, events, RTE access points and A2L objects changed, per model | -| Stale or partial regenerate (the ARXML changed but the C did not follow) | invisible — each file looks fine on its own | flagged: the two files no longer agree | -| A build gate | none — it is interactive | an exit code (`0` / `1` / `2`) a pipeline can gate on, plus JSON and SARIF output | -| Your team's own generator churn (TargetLink, DaVinci) | hand-written per-tool rules | built-in Embedded Coder rules, extensible with `--rules` (see [usage.md](docs/usage.md#custom-noise-rules)) | +> **Rule:** if a difference cannot be proven to be noise, it remains a real change. -The honest short version: for reading any two text files side by side, a general -diff tool is fine. This one earns its place when the two folders are AUTOSAR -codegen and most of the diff is the generator repeating itself. +For ordinary text files, use a general-purpose diff tool. +For AUTOSAR code generation, use CodeGen Compare. -## Getting it +--- -You can run it straight out of a clone, nothing to install: +## Quick Start + +### Compare two generated folders ```bash -git clone https://github.com/longvo92/codegen-compare-tool.git -cd codegen-compare-tool -python -m compare_tool --help +python -m compare_tool old_gen_folder new_gen_folder --report report.html ``` -Or install it as a proper command, `compare-tool`: +The result is a **self-contained HTML report** that can be opened in any browser or published as a CI artifact. + +ZIP files can be compared directly: ```bash -pip install git+https://github.com/longvo92/codegen-compare-tool.git +python -m compare_tool baseline.zip current.zip --report report.html ``` -Stuck on a machine that won't let you install anything at all? There's a [single-file build](docs/usage.md#single-file-build) for that. - -## A first compare +### Open the desktop viewer ```bash -python -m compare_tool --report out.html +python -m compare_tool ``` -That writes one self-contained HTML file — open it in any browser, email it, nothing else needed. Either side can also be a `.zip` (a build artifact pulled straight from Azure DevOps, say); it's unpacked read-only into a temp folder, compared as if it were a normal directory, and cleaned up afterwards. The report still shows the zip's name, not the temp path: +With no folders supplied, the interactive viewer opens. + +### Install + +Run directly from a clone: ```bash -python -m compare_tool baseline.zip current.zip --report out.html +git clone https://github.com/longvo92/codegen-compare-tool.git +cd codegen-compare-tool +python -m compare_tool --help ``` -Leave the folders off entirely and the viewer opens instead — just drag the two folders (or two `.zip`s) onto it: +Or install as a command: ```bash -python -m compare_tool +pip install git+https://github.com/longvo92/codegen-compare-tool.git ``` -If you're wiring this into a build, the exit code is the contract: +A single-file build is also available for machines where installing software is restricted. -| Code | Meaning | -|---|---| -| `0` | No real changes | -| `1` | Real changes found — the usual CI gate | -| `2` | **Compare INCOMPLETE** — some path couldn't be listed, read or compared, or the report couldn't be written | +See the [Usage Guide](docs/usage.md) for installation, packaging and all command-line options. -Exit `2` is loud on purpose: `!!` in the terminal, a red banner in the report, and `--exit-zero` does not silence it. A run that couldn't produce a real answer should never look like a clean one. +--- -## What actually gets filtered out +## Viewer or CLI? -| Kind | What it catches | Files | -|---|---|---| -| `comment` | C/C++/A2L comments (`//`, `/* */`), XML comments (``), `#` line comments (Python, YAML) | .c .h .cpp .hpp .arxml .a2l .py .yaml .yml | -| `rename` | A consistent 1-to-1 rename of generator-owned names — anything the mapping can't fully explain is still a real change | .c .h | -| `reorder` | Independent statements the codegen emitted in a different order — folded only when the block is straight-line scalar assignments and the new order preserves every data dependence, else it stays a real change | .c .h | -| `uuid` | `UUID="..."` attributes | .arxml .xml | -| `timestamp` | `` blocks, `` | .arxml .xml | -| `sw-version` | `` stamps, which bump on every regenerate | .arxml .xml | -| `description` | ``, ``, `` | .arxml .xml | -| `whitespace` | Indentation, trailing spaces, blank lines | all | -| `line-endings` | CRLF vs LF, BOM | all | +Both use the **same comparison engine**, so they always produce the same comparison result. -The rule the tool never bends: **if it can't be proven to be noise, it's a real change.** `SIG_TORQUE_MIN` becoming `SIG_TORQUE_MAX` is a real change; `rtb_AND_c4nxjoom3d` becoming `rtb_AND_j2kqp1wxab` is a rename the generator made up. A block that moved intact gets its own `moved` label, coloured blue, and still counts toward Modified — it's not hidden, just explained. A file that's only had its comments touched gets its own category too, separate from the merely-unimportant, because "the comment banner moved" and "an identifier got renamed" are not the same kind of nothing. +| | Desktop Viewer | CLI | +| ---------- | ------------------ | ------------------- | +| Best for | Interactive review | CI / automation | +| Input | Folders / ZIP | Folders / ZIP | +| Output | Interactive diff | HTML / JSON / SARIF | +| Build gate | — | Exit code | -→ [the exact rules, one by one](docs/usage.md#what-counts-as-noise) +--- -## An AUTOSAR-level summary, not just a text diff +## Key Features -Both the viewer and the report open with what changed **in AUTOSAR terms** before you ever look at a line of C or XML: port interfaces, SWCs, ports, runnables, events (a `TIMING-EVENT` period going from `0.01s` to `0.02s` shows up as exactly that), `Rte_*` access points, and A2L `CHARACTERISTIC` / `MEASUREMENT` objects — grouped by the Simulink model they belong to. +### 1. Generator-noise filtering -→ [what gets extracted, and how it's shown](docs/usage.md#autosar-semantic-summary) +Automatically identifies common code-generation churn: -## Catching a stale or partial regenerate +* UUIDs and timestamps +* Generated version stamps +* Comments and formatting +* Generated identifier renames +* Safe statement reordering +* Configurable custom noise rules -A model's ARXML declares its interface — which ports, runnables and events it has. Its A2L declares the calibration and measurement variables. The generated C has to match both: add a port in the ARXML and the code needs a matching `Rte_*` call, add a characteristic in the A2L and the code needs a matching variable. +Changes that cannot be safely explained remain visible as real changes. -So when a port, runnable or calibration variable is added or removed in the ARXML/A2L but that model's C file didn't change by a single byte, the tool flags it — usually the sign of a regenerate that didn't finish. A file-by-file diff can't catch this, because each file is fine on its own; what's wrong is that the two no longer agree. +See [What Counts as Noise](docs/usage.md#what-counts-as-noise). -It also checks across models: if model A's code gains a new `Rte_*` call while model B's code is untouched, you probably regenerated only model A. That new `Rte_*` call needs the RTE layer regenerated before the code will build and integrate. Both are heads-up flags shown next to the AUTOSAR summary — neither changes a file's verdict or the exit code. +--- -→ [how the consistency check works](docs/usage.md#consistency-check) +### 2. AUTOSAR-level change summary -## The desktop viewer +See what changed **in AUTOSAR terms**, not only as changed lines of C or XML. -```bash -pip install "codegen-compare-tool[viewer] @ git+https://github.com/longvo92/codegen-compare-tool.git" -python -m compare_tool +The tool extracts changes to: + +* SWCs +* Ports and port interfaces +* Runnables +* Events +* `Rte_*` access points +* A2L `CHARACTERISTIC` / `MEASUREMENT` objects + +Changes are grouped by the Simulink model they belong to. + +A timing change such as: + +```text +TIMING-EVENT: 0.01 s → 0.02 s ``` +is reported as a semantic AUTOSAR change instead of forcing you to find it in generated XML. + +See [AUTOSAR Semantic Summary](docs/usage.md#autosar-semantic-summary). + +--- + +### 3. Detect incomplete regeneration + +Generated artifacts should agree with each other. + +CodeGen Compare cross-checks **ARXML, A2L and generated C** to detect suspicious inconsistencies. + +For example: + +```text +ARXML changed + C unchanged +→ possible incomplete regeneration + +A2L changed + C unchanged +→ possible incomplete regeneration + +Model A gains an Rte_* call +while Model B remains unchanged +→ possible partial regeneration +``` + +These checks are advisory and do not change the file verdict or CI exit code. + +See [Consistency Check](docs/usage.md#consistency-check). + +--- + +## Desktop Viewer + ![Side-by-side viewer](resources/pic/main_page.png) -A folder tree on the left, a two-pane diff with a minimap and syntax colouring on the right. `F7`/`F8` step through every change in the whole compare, `Ctrl+F` searches across every file, and you can leave a review note on any individual change. A caption above the diff tracks whatever you're scrolled into — the enclosing C/C++ function, the Python class or method, the AUTOSAR SHORT-NAME, the A2L block — so you're never lost about *where* you are. There's also a commit picker, so you can compare one folder in a git checkout against its own history instead of against a second folder. Press `F1` for the built-in user guide; it works offline like everything else here. +The viewer provides: -→ [reading a scan, review mode, every shortcut](docs/usage.md#side-by-side-viewer) +* Folder tree +* Side-by-side diff +* Minimap and syntax highlighting +* Change navigation +* Review notes +* Git history comparison +* Offline user guide -## The HTML report +It is designed for manually reviewing large generated-code changes without losing context. + +See [Side-by-side Viewer](docs/usage.md#side-by-side-viewer). + +--- + +## HTML Report ![Report viewer](resources/pic/report_page.png) -One file per compare, and it's genuinely self-contained — badge toggles, folder tree, a filter box, diffs you can collapse, all in a single `.html` you can attach to an email. It shows three lines of context on either side of each real change rather than the whole file, so the noise sitting around it takes up no screen space until you specifically ask to see it. Every change is captioned with the function it's inside, and a modified file lists every function its changes touch. Both dark and light themes are baked in, so switching doesn't fetch anything — it'll render exactly the same on a machine with no internet as on yours. +Every comparison can produce a self-contained HTML report containing: + +* File and change summaries +* Filtering and collapsible diffs +* Context around each change +* Function-level change information +* Dark / light themes +* AUTOSAR semantic summaries +* Consistency advisories + +The report requires **no server, database or internet connection** and can be published directly as a CI artifact. + +See [HTML Report](docs/usage.md#html-report). + +--- + +## CI Integration -→ [the layout, the badges, what collapses and why](docs/usage.md#html-report) +Use the exit code as a build gate: -## Wiring it into CI +| Code | Meaning | +| ---: | ---------------------------- | +| `0` | No real changes | +| `1` | Real changes found | +| `2` | Compare incomplete or failed | + +Example: ```bash -python -m compare_tool old_dir new_dir --exit-zero --exclude compare_report.html +python -m compare_tool old_dir new_dir \ + --report compare_report.html \ + --exit-zero ``` -`--exit-zero` keeps the build green even when the only thing that happened was a regenerate; `--exclude` stops the previous run's own report from being counted as part of the diff. Publish `compare_report.html` as a build artifact and you've got a clickable record of every run. [azure-pipelines.yml](azure-pipelines.yml) has a working example if you want to see it end to end. +Available machine-readable outputs: + +* `--json` — complete comparison data +* `--sarif` — SARIF 2.1.0 for code-scanning systems + +Publish the HTML report as a build artifact for every comparison. + +See [CI Integration](docs/usage.md#ci-integration). + +--- + +## What does it require? + +The **compare engine uses only the Python standard library**. + +No: -Need the result as data instead of a page? `--json out.json` writes the full scan — per-file verdict, hunks, renames, the run summary, the consistency advisories and the exit code. `--sarif out.sarif` writes a SARIF 2.1.0 log of just the files that need action (modified / added / deleted / error), so GitHub or Azure DevOps code scanning annotates them inline. +* Database +* Server +* Network connection +* `pip install` required for CLI comparison -→ [flags, exit codes, and packaging for locked-down build machines](docs/usage.md#ci-integration) +The desktop viewer uses **PySide6**, loaded only when the viewer is opened. + +This makes the CLI suitable for locked-down build environments. + +--- + +## Documentation + +* 📖 [Usage Guide](docs/usage.md) — commands, viewer shortcuts, noise rules, reports, CI and packaging +* 🏗 [Architecture](docs/architecture.md) — module structure and design decisions +* 🇻🇳 [Vietnamese Documentation](docs/vi/README.md) + +--- ## Contributing +Run the test suite: + ```bash python -m unittest discover -s tests ``` -CI runs that suite on Linux and Windows against Python 3.8 and 3.11, plus a headless scan over the fixture tree that checks both the report and the exit code. +The compare core must remain **standard-library-only**. + +See [Architecture](docs/architecture.md) before making changes. + +Issues and pull requests are welcome. -Issues and pull requests are welcome. The one rule that matters: the **compare core stays stdlib-only** — it has to run on build servers where nothing gets installed, so PySide6 lives entirely inside `compare_tool/qtviewer/` and is only imported once the viewer actually opens. If you're adding a noise rule, add a test for it under `tests/` too. [docs/architecture.md](docs/architecture.md) has the module map and a table of what to touch for what kind of change. +--- ## Author diff --git a/docs/vi/README.md b/docs/vi/README.md index 6497bc8..ec00a85 100644 --- a/docs/vi/README.md +++ b/docs/vi/README.md @@ -1,246 +1,298 @@ +

+ + CodeGen Compare Tool + +

+ +

+ +Test Python 3.8+ License: MIT Release + +

+ +

+🇬🇧 English: README +

+ # CodeGen Compare Tool -> Bản tiếng Việt của [README](../../README.md). Bản tiếng Anh là bản chuẩn — khi -> hai bên lệch nhau, tin bản tiếng Anh. +**Nhìn thấy những gì thực sự thay đổi sau khi generate AUTOSAR code.** -Regenerate xong một model Simulink, diff với bản hôm qua có khi lên tới hàng -nghìn dòng — banner timestamp mới, UUID mới toanh trên từng phần tử ARXML, tên -biến bị codegen đánh số lại từ đầu. Đâu đó trong đống đó có thể có một thay đổi -hành vi thật, có thể không, và cách duy nhất để biết là cuộn qua từng dòng — thế -là một buổi review 5 phút thành cả buổi chiều. +Mỗi lần regenerate một project Simulink/AUTOSAR có thể tạo ra hàng nghìn dòng thay đổi do timestamp, UUID, generated identifier và các thay đổi khác từ code generator. -Tool này đọc cả hai thư mục, tách ra dòng nào chỉ là do generator ghi lại -(timestamp, UUID, tên biến tự sinh) và dòng nào là thay đổi thật, rồi chỉ hiện -loại thứ hai. Trỏ vào một bản codegen cũ và một bản mới, nó liệt kê ra cái gì -thực sự đã đổi — ở mức code, và ở mức AUTOSAR. +CodeGen Compare Tool so sánh hai snapshot của generated code, tự động loại bỏ những khác biệt có thể chứng minh là **generator noise**, và tập trung vào những thay đổi thực sự cần review. -Có hai cách để xem kết quả đó: một **viewer desktop** để review bằng tay, và -một **CLI** ghi ra **HTML report** self-contained kèm exit code để pipeline -gate theo. Cả hai chạy trên đúng một compare engine, nên không có chuyện mở -bằng cách này ra kết quả khác, mở bằng cách kia ra kết quả khác. +Tool không chỉ so sánh **C/C++ và XML**, mà còn phân tích các **AUTOSAR và A2L objects** phía sau generated files. -| | Dùng cho | Chạy khi | -|---|---|---| -| **Viewer** | Review bằng tay — cây thư mục, diff hai pane, minimap, note review | Không truyền thư mục trên command line (hoặc double-click `.exe`) | -| **CLI** | Pipeline và script — ghi report, exit code gate build | Truyền đủ hai thư mục trên command line | +--- -Phần lõi — scan, luật lọc noise, diff, HTML report — **chỉ dùng standard -library của Python**. Không cần `pip install` gì, không server, không bao giờ -gọi mạng. Viewer là phần duy nhất cần PySide6, và cũng chỉ import đúng lúc nó -mở lên. +## Tại sao cần CodeGen Compare? -📖 **[Hướng dẫn sử dụng](usage.md)** — đầy đủ flag, phím tắt của viewer, luật -noise chính xác, cách report dựng trang, CI và đóng gói. +Các diff tool thông thường chỉ nhìn thấy text. Chúng không biết UUID thay đổi có phải noise hay không, một generated identifier có chỉ đơn giản được rename hay không, hoặc ARXML và generated C có còn nhất quán với nhau hay không. -🏗 **[Kiến trúc](architecture.md)** — các mảnh ghép với nhau ra sao và tại sao. +CodeGen Compare được thiết kế cho workflow **AUTOSAR code generation**. -## Tại sao không dùng Beyond Compare, WinMerge hay `diff`? +| | Diff tool thông thường | CodeGen Compare | +| --------------------------- | ------------------------------------------ | --------------------------------------- | +| Timestamp / UUID | Hiển thị như thay đổi | Tự động lọc | +| Generated identifier rename | Có thể tạo ra thay đổi trên hàng loạt dòng | Nhận diện khi có thể chứng minh an toàn | +| AUTOSAR changes | Chỉ thấy text | SWC, port, runnable, event, RTE access | +| A2L changes | Chỉ thấy text | Characteristic / measurement | +| Regenerate không đầy đủ | Thường không phát hiện | Cross-file consistency check | +| CI build gate | Phải tự xử lý | Exit code + JSON + SARIF | -Đó đều là các tool diff tổng quát rất tốt. Khác biệt là chúng diff *text*, còn -tool này diff *AUTOSAR codegen* — nó biết một lần regenerate làm gì với file và -điều đó nghĩa là gì. +> **Nguyên tắc:** Nếu một khác biệt không thể được chứng minh là noise, nó được xem là **real change**. -| | Beyond Compare / WinMerge / `diff` | Tool này | -|---|---|---| -| Churn timestamp / UUID / version stamp | hiện ra như thay đổi — bạn tự lọc bằng mắt hoặc bằng rule viết tay | tự phân loại là noise; file chỉ khác nhau ở noise được báo đúng như vậy | -| Tên định danh do generator đổi (`rtb_AND_c4nxjoom3d` → `rtb_AND_j2kqp1wxab`) | thành thay đổi ở mọi dòng dùng tên đó | nhận ra là rename 1-1 và gộp lại — nhưng chỉ khi mapping toàn file nhất quán, nên một rename thật vẫn là thay đổi thật | -| "Model đã đổi gì?" | không trả lời được — nó là tool text | summary AUTOSAR: port, runnable, event, RTE access point, đối tượng A2L nào đã đổi, theo từng model | -| Regenerate dở dang (ARXML đổi nhưng C không theo) | không thấy được — từng file nhìn riêng đều ổn | được cảnh báo: hai file không còn khớp nhau | -| Gate cho build | không có — nó là tool tương tác | exit code (`0` / `1` / `2`) để pipeline gate, kèm output JSON và SARIF | -| Churn của generator riêng nhóm bạn (TargetLink, DaVinci) | rule viết tay theo từng tool | rule Embedded Coder sẵn có, mở rộng được bằng `--rules` (xem [usage.md](usage.md#custom-noise-rules)) | +Với các file text thông thường, hãy dùng diff tool thông thường. +Với generated code từ AUTOSAR, hãy dùng CodeGen Compare. -Nói thẳng: để đọc hai file text cạnh nhau thì tool diff tổng quát là đủ. Tool -này đáng dùng khi hai thư mục là AUTOSAR codegen và phần lớn diff chỉ là -generator tự lặp lại. +--- -## Lấy tool +## Quick Start -Chạy thẳng từ clone, không cần cài gì: +### So sánh hai thư mục generated code ```bash -git clone https://github.com/longvo92/codegen-compare-tool.git -cd codegen-compare-tool -python -m compare_tool --help +python -m compare_tool old_gen_folder new_gen_folder --report report.html ``` -Hoặc cài thành một lệnh riêng, `compare-tool`: +Kết quả là một **HTML report độc lập**, có thể mở trực tiếp bằng trình duyệt hoặc publish thành CI artifact. + +Có thể so sánh trực tiếp hai file ZIP: ```bash -pip install git+https://github.com/longvo92/codegen-compare-tool.git +python -m compare_tool baseline.zip current.zip --report report.html ``` -Máy bị khoá không cài được gì hết? Có sẵn [bản build một file](usage.md#build-một-file). - -## Lần compare đầu tiên +### Mở Desktop Viewer ```bash -python -m compare_tool --report out.html +python -m compare_tool ``` -Lệnh này ghi ra một file HTML self-contained duy nhất — mở bằng browser bất kỳ, -gửi mail thoải mái, không cần gì thêm. Mỗi phía cũng có thể là một `.zip` (ví -dụ artifact build tải thẳng từ Azure DevOps); nó được giải nén read-only vào -thư mục tạm, so sánh như một thư mục bình thường, rồi dọn sạch sau đó. Report -vẫn ghi tên file zip, không phải đường dẫn tạm: +Khi không truyền folder vào command line, interactive viewer sẽ được mở. + +### Cài đặt + +Có thể chạy trực tiếp từ source: ```bash -python -m compare_tool baseline.zip current.zip --report out.html +git clone https://github.com/longvo92/codegen-compare-tool.git +cd codegen-compare-tool +python -m compare_tool --help ``` -Bỏ hai thư mục ra thì viewer mở lên — kéo thả hai thư mục (hoặc hai `.zip`) -vào đó là xong: +Hoặc cài đặt thành command: ```bash -python -m compare_tool +pip install git+https://github.com/longvo92/codegen-compare-tool.git ``` -Nếu bạn đang gắn vào build, exit code chính là contract: +Tool cũng hỗ trợ **single-file build** cho các máy bị hạn chế quyền cài đặt. -| Code | Ý nghĩa | -|---|---| -| `0` | Không có thay đổi thật | -| `1` | Có thay đổi thật — CI gate thường dùng cái này | -| `2` | **Compare INCOMPLETE** — có path không list / đọc / so sánh được, hoặc không ghi được report | +Xem [Hướng dẫn sử dụng](usage.md) để biết thêm về installation, packaging và toàn bộ command-line options. -Exit `2` được làm cho khó bỏ sót: `!!` ngoài terminal, banner đỏ trong report, -và `--exit-zero` cũng không tắt được nó. Một lần chạy không so sánh được đầy đủ -thì không được phép trông giống một lần chạy sạch. +--- -## Cái gì thực sự bị lọc +## Viewer hay CLI? -| Kind | Bắt cái gì | File | -|---|---|---| -| `comment` | Comment C/C++/A2L (`//`, `/* */`), comment XML (``), comment dòng `#` (Python, YAML) | .c .h .cpp .hpp .arxml .a2l .py .yaml .yml | -| `rename` | Đổi tên 1-1 nhất quán các tên do generator sở hữu — cái gì mapping không giải thích trọn vẹn thì vẫn là thay đổi thật | .c .h | -| `reorder` | Các câu lệnh độc lập bị codegen emit theo thứ tự khác — chỉ gộp khi block là các phép gán scalar straight-line và thứ tự mới giữ nguyên mọi data dependence, không thì vẫn là thay đổi thật | .c .h | -| `uuid` | Attribute `UUID="..."` | .arxml .xml | -| `timestamp` | Block ``, `` | .arxml .xml | -| `sw-version` | Version stamp ``, tăng mỗi lần regenerate | .arxml .xml | -| `description` | ``, ``, `` | .arxml .xml | -| `whitespace` | Thụt đầu dòng, khoảng trắng cuối dòng, dòng trống | tất cả | -| `line-endings` | CRLF vs LF, BOM | tất cả | +Cả hai đều sử dụng **cùng một comparison engine**, vì vậy kết quả so sánh luôn nhất quán. -Luật mà tool không bao giờ nới lỏng: **cái gì không chứng minh được là noise -thì là thay đổi thật.** `SIG_TORQUE_MIN` đổi thành `SIG_TORQUE_MAX` là thay đổi -thật; `rtb_AND_c4nxjoom3d` đổi thành `rtb_AND_j2kqp1wxab` là generator tự đặt -tên lại. Một block bị dịch chuyển nguyên vẹn được gán nhãn `moved` riêng, tô -xanh dương, và vẫn tính vào Modified — nó không bị giấu đi, chỉ được nói rõ đó -là di chuyển chứ không phải sửa nội dung. File chỉ khác nhau ở comment được xếp -vào hạng mục riêng, không gộp chung với Unimportant: comment bị viết lại thì -bạn đọc lướt qua được, còn một biến bị đổi tên thì phải kiểm. +| | Desktop Viewer | CLI | +| ----------- | ---------------- | ------------------- | +| Phù hợp với | Review trực tiếp | CI / automation | +| Input | Folder / ZIP | Folder / ZIP | +| Output | Interactive diff | HTML / JSON / SARIF | +| Build gate | — | Exit code | -→ [luật chính xác, từng cái một](usage.md#cái-gì-bị-tính-là-noise) +--- -## Summary ở mức AUTOSAR, không chỉ là diff text +## Các tính năng chính -Cả viewer lẫn report đều mở ra bằng cái gì đã đổi **ở mức AUTOSAR** trước khi -bạn nhìn vào một dòng C hay XML nào: port interface, SWC, port, runnable, event -(chu kỳ `TIMING-EVENT` đi từ `0.01s` sang `0.02s` hiện ra đúng như vậy), lời -gọi `Rte_*`, và đối tượng A2L `CHARACTERISTIC` / `MEASUREMENT` — nhóm theo đúng -model Simulink mà chúng thuộc về. +### 1. Lọc generator noise -→ [trích ra những gì, hiển thị ra sao](usage.md#summary-ngữ-nghĩa-autosar) +Tự động nhận diện các thay đổi phổ biến do code generator tạo ra: -## Bắt được một lần regenerate dở dang +* UUID và timestamp +* Generated version stamps +* Comment và formatting +* Generated identifier rename +* Safe statement reordering +* Custom noise rules -ARXML của một model là file khai báo interface của model đó — có những port -nào, runnable nào, event nào. A2L là file khai báo các biến calibration và -measurement. Code C sinh ra phải khớp với cả hai: thêm một port trong ARXML thì -trong code phải có thêm một lời gọi `Rte_*` tương ứng, thêm một characteristic -trong A2L thì trong code phải có thêm biến tương ứng. +Những thay đổi không thể giải thích một cách an toàn vẫn được giữ lại như **real changes**. -Nên khi ARXML hoặc A2L có thêm/bớt một port, runnable hay biến calibration mà -file C của model đó không đổi một byte nào, tool sẽ cảnh báo — đó thường là -dấu hiệu lần regenerate chạy chưa xong. Một diff xem từng file riêng lẻ không -phát hiện được chuyện này, vì bản thân mỗi file đều bình thường; chỗ sai nằm ở -việc hai file không khớp nhau. +Xem [What Counts as Noise](usage.md#cái-gì-bị-tính-là-noise). -Tool cũng đối chiếu giữa các model với nhau: nếu code của model A có thêm lời -gọi `Rte_*` mới mà code của model B không đổi gì cả, nhiều khả năng bạn chỉ -regenerate mình model A chứ chưa regenerate lại toàn bộ architecture. Lời gọi -`Rte_*` mới đó cần RTE layer sinh lại thì mới build và tích hợp được. +--- -Cả hai đều chỉ là cảnh báo để bạn đi kiểm tra — chúng không đổi verdict của -file nào, cũng không đổi exit code. +### 2. Phân tích thay đổi ở mức AUTOSAR -→ [consistency check hoạt động thế nào](usage.md#consistency-check) +Không chỉ xem những dòng C/XML thay đổi, bạn có thể xem **thứ gì đã thay đổi ở mức AUTOSAR**. -## Viewer desktop +Tool phân tích các thay đổi liên quan đến: -```bash -pip install "codegen-compare-tool[viewer] @ git+https://github.com/longvo92/codegen-compare-tool.git" -python -m compare_tool +* SWC +* Port và port interface +* Runnable +* Event +* `Rte_*` access point +* A2L `CHARACTERISTIC` / `MEASUREMENT` + +Các thay đổi được nhóm theo Simulink model mà chúng thuộc về. + +Ví dụ: + +```text +TIMING-EVENT: 0.01 s → 0.02 s ``` -![Viewer side-by-side](../../resources/pic/main_page.png) +được báo cáo như một thay đổi semantic của AUTOSAR thay vì buộc bạn phải tự tìm trong hàng nghìn dòng generated XML. + +Xem [AUTOSAR Semantic Summary](usage.md#summary-ngữ-nghĩa-autosar). + +--- + +### 3. Phát hiện regenerate không đầy đủ -Cây thư mục bên trái, diff hai pane có minimap và tô cú pháp bên phải. -`F7`/`F8` đi hết mọi change trong cả lần compare, `Ctrl+F` tìm xuyên mọi file, -và bạn để lại note review trên từng change riêng lẻ được. Phía trên diff có -một dòng hiện tên hàm C/C++ (hoặc class/method Python, SHORT-NAME AUTOSAR, -block A2L) chứa đoạn code bạn đang xem, cập nhật liên tục khi cuộn — file -codegen dài hàng nghìn dòng thì cái này giúp biết mình đang ở hàm nào. Có cả -commit picker, để so một thư mục trong git checkout với chính lịch sử của nó -thay vì phải có sẵn hai thư mục. Bấm `F1` để mở user guide có sẵn trong app, -chạy offline. +Các generated artifacts phải nhất quán với nhau. -→ [đọc một lần scan, review mode, mọi phím tắt](usage.md#viewer-side-by-side) +CodeGen Compare kiểm tra chéo giữa **ARXML, A2L và generated C** để phát hiện những trường hợp có khả năng regenerate không hoàn chỉnh. -## HTML report +Ví dụ: + +```text +ARXML thay đổi + C không thay đổi +→ có thể regenerate chưa hoàn tất + +A2L thay đổi + C không thay đổi +→ có thể regenerate chưa hoàn tất + +Model A có thêm Rte_* call +nhưng Model B không thay đổi +→ có thể chỉ regenerate một phần +``` + +Các consistency check này mang tính **advisory** và không thay đổi file verdict hoặc CI exit code. + +Xem [Consistency Check](usage.md#consistency-check). + +--- + +## Desktop Viewer + +![Side-by-side viewer](../../resources/pic/main_page.png) + +Viewer cung cấp: + +* Folder tree +* Side-by-side diff +* Minimap và syntax highlighting +* Điều hướng giữa các thay đổi +* Review notes +* Git history comparison +* Offline user guide + +Viewer được thiết kế để review generated-code changes một cách trực quan mà vẫn giữ được context cần thiết. + +Xem [Side-by-side Viewer](usage.md#viewer-side-by-side). + +--- + +## HTML Report ![Report viewer](../../resources/pic/report_page.png) -Một file cho mỗi lần compare, và nó self-contained thật sự — badge bật/tắt, -cây thư mục, ô lọc, diff xếp gọn được, tất cả trong một `.html` duy nhất đính -kèm mail thoải mái. Nó hiện ba dòng ngữ cảnh trên và dưới mỗi change thật thay -vì cả file, nên noise xung quanh không chiếm chỗ màn hình nào cho tới khi bạn -chủ động bấm hiện. Mỗi change được chú thích bằng hàm nó nằm trong, và một file -Modified liệt kê mọi hàm mà change của nó đụng tới. Cả hai theme sáng/tối đều -nhúng sẵn, nên đổi theme không tải gì cả — render y hệt trên máy không có -internet như trên máy bạn. +Mỗi lần compare có thể tạo một HTML report độc lập, bao gồm: + +* File và change summary +* Filtering và collapsible diffs +* Context xung quanh mỗi thay đổi +* Function-level change information +* Dark / light theme +* AUTOSAR semantic summary +* Consistency advisories + +Report **không cần server, database hoặc internet connection** và có thể publish trực tiếp thành CI artifact. + +Xem [HTML Report](usage.md#html-report). + +--- + +## Tích hợp CI -→ [bố cục, badge, cái gì bị gộp và tại sao](usage.md#html-report) +Exit code có thể được sử dụng trực tiếp làm build gate: -## Gắn vào CI +| Code | Ý nghĩa | +| ---: | ---------------------------------------- | +| `0` | Không có real change | +| `1` | Phát hiện real change | +| `2` | Compare không hoàn chỉnh hoặc xảy ra lỗi | + +Ví dụ: ```bash -python -m compare_tool old_dir new_dir --exit-zero --exclude compare_report.html +python -m compare_tool old_dir new_dir \ + --report compare_report.html \ + --exit-zero ``` -`--exit-zero` giữ build xanh ngay cả khi việc duy nhất xảy ra là regenerate; -`--exclude` không cho report của lần chạy trước bị tính vào diff. Publish -`compare_report.html` như một build artifact là có luôn bản ghi có thể bấm vào -cho từng lần chạy. [azure-pipelines.yml](../../azure-pipelines.yml) có ví dụ -chạy được từ đầu đến cuối nếu bạn muốn xem. +Các output dành cho machine processing: + +* `--json` — toàn bộ dữ liệu của comparison +* `--sarif` — SARIF 2.1.0 cho các hệ thống code scanning + +Có thể publish HTML report thành build artifact để lưu lại kết quả của từng lần compare. + +Xem [CI Integration](usage.md#tích-hợp-ci). + +--- + +## Yêu cầu hệ thống + +**Comparison engine chỉ sử dụng Python standard library.** + +Không cần: -Cần kết quả ở dạng dữ liệu thay vì một trang? `--json out.json` ghi toàn bộ -scan — verdict từng file, hunk, rename, summary của lần chạy, các advisory -consistency và exit code. `--sarif out.sarif` ghi một log SARIF 2.1.0 chỉ gồm -các file cần xử lý (modified / added / deleted / error), để code scanning của -GitHub hay Azure DevOps chú thích chúng inline. +* Database +* Server +* Network connection +* `pip install` cho CLI comparison -→ [flag, exit code, và đóng gói cho máy bị khoá chặt](usage.md#tích-hợp-ci) +Desktop Viewer sử dụng **PySide6**, nhưng chỉ được import khi viewer thực sự được mở. + +Điều này giúp CLI có thể chạy trên các build server hoặc môi trường bị hạn chế quyền cài đặt. + +--- + +## Tài liệu + +* 📖 [Hướng dẫn sử dụng](usage.md) — command, viewer shortcuts, noise rules, report, CI và packaging +* 🏗 [Kiến trúc](architecture.md) — module structure và các quyết định thiết kế +* 🇬🇧 [English Documentation](../../README.md) + +--- ## Đóng góp +Chạy test suite: + ```bash python -m unittest discover -s tests ``` -CI chạy bộ test đó trên Linux và Windows với Python 3.8 và 3.11, cộng thêm một -lần scan headless trên cây fixture kiểm cả report lẫn exit code. +Comparison core phải tiếp tục **chỉ dùng Python standard library**. + +Xem [Kiến trúc](architecture.md) trước khi thực hiện các thay đổi lớn. + +Issue và pull request luôn được chào đón. -Issue và pull request đều được hoan nghênh. Luật quan trọng nhất: **compare -core chỉ dùng stdlib** — nó phải chạy được trên build server bị khoá chặt, nên -PySide6 nằm gọn trong `compare_tool/qtviewer/` và chỉ import đúng lúc viewer -mở lên. Thêm luật lọc noise mới thì nhớ thêm test dưới `tests/`. -[architecture.md](architecture.md) có bản đồ module và bảng *sửa cái gì thì -đụng vào đâu*. +--- ## Tác giả **Long Vo Thien** -## Giấy phép +## License Phát hành theo [MIT License](../../LICENSE) © 2026 Long Vo Thien.