Skip to content

Commit fd8ce7c

Browse files
committed
README.en.mdを追加
1 parent fcf3771 commit fd8ce7c

2 files changed

Lines changed: 244 additions & 0 deletions

File tree

README.en.md

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# FolderDiffIL4DotNet (English)
2+
3+
This repository hosts a .NET console application that compares two folders, classifies the differences, and writes a detailed Markdown report. When both inputs are .NET assemblies, the app ignores build-specific artifacts such as the `// MVID:` line, so assemblies that behave the same are treated as equal even if they were produced at different times.
4+
5+
> Looking for the Japanese version? See [README.md](README.md).
6+
7+
## Requirements
8+
9+
- .NET SDK 8.x
10+
- macOS / Windows / Linux / Unix-like OS (e.g., FreeBSD)
11+
- IL disassembler (the app automatically probes candidates in this order)
12+
- Preferred: `dotnet-ildasm` or `dotnet ildasm`
13+
- Fallback: `ilspycmd`
14+
15+
Installation example:
16+
17+
```bash
18+
dotnet tool install --global dotnet-ildasm
19+
# add $HOME/.dotnet/tools (Unix) or %USERPROFILE%\.dotnet\tools (Windows) to PATH if necessary
20+
```
21+
22+
```bash
23+
dotnet tool install -g ilspycmd
24+
# add $HOME/.dotnet/tools (Unix) or %USERPROFILE%\.dotnet\tools (Windows) to PATH if necessary
25+
```
26+
27+
## CI (GitHub Actions)
28+
29+
The repository includes `.github/workflows/dotnet.yml`. The workflow runs for pushes and pull requests targeting `main`, and it can also be triggered manually via `workflow_dispatch`.
30+
31+
- `actions/checkout` uses `fetch-depth: 0` so Nerdbank.GitVersioning can traverse the full commit history.
32+
- `actions/setup-dotnet` honors `global.json`, installing the same SDK (e.g., 8.0.413) that you use locally before running `dotnet restore` and a Release build.
33+
- `dotnet test` runs only when a project file matching `**/*Tests.csproj` or `**/*.Tests.csproj` exists, so repositories without tests still succeed.
34+
- NuGet packages inside `~/.nuget/packages` are cached via `actions/cache` to accelerate subsequent builds.
35+
- Release artifacts are produced with `dotnet publish FolderDiffIL4DotNet.csproj --output publish`, stripped of debug symbols (`*.pdb`), and uploaded as `FolderDiffIL4DotNet` via `actions/upload-artifact`.
36+
37+
How to use it:
38+
39+
1. Push this repo to GitHub—no additional configuration required.
40+
2. If your default branch is not `main`, edit `on.push.branches` and `on.pull_request.branches` in the workflow.
41+
3. When you add test projects, ensure their file names contain `Tests`, or adjust the job condition accordingly.
42+
4. Download the Release build from "Artifacts > FolderDiffIL4DotNet" on the workflow run page.
43+
44+
## What the app does
45+
46+
- Recursively compares the old folder (CLI arg #1) and the new folder (CLI arg #2).
47+
- Tracks each file as `MD5Match`, `MD5Mismatch`, `ILMatch`, `ILMismatch`, `TextMatch`, or `TextMismatch`.
48+
- Groups files into `Unchanged`, `Added`, `Removed`, and `Modified` buckets.
49+
- Writes per-bucket listings to `Reports/<report label>/diff_report.md`; paths are relative for `Unchanged`/`Modified` and absolute for `Added`/`Removed`.
50+
- Summarizes counts per bucket in the same report.
51+
- Optionally writes ignored files, unchanged files, timestamps, and warnings when at least one `MD5Mismatch` exists.
52+
53+
## File comparison flow
54+
55+
1. **MD5 hash** – if hashes match, the file is `Unchanged (MD5Match)`.
56+
2. **IL diff** – if the file is a .NET assembly (detected via PE/CLR headers, regardless of extension), the app disassembles both versions, strips `// MVID:` lines, and compares them line by line. Matches become `Unchanged (ILMatch)`; mismatches become `Modified (ILMismatch)`.
57+
3. **Text diff** – if the extension appears in `TextFileExtensions`, a line-based text diff runs. Matches are `Unchanged (TextMatch)`; mismatches are `Modified (TextMismatch)`.
58+
4. **Fallback** – remaining files are treated as `Modified (MD5Mismatch)`.
59+
60+
## Configuration (`config.json`)
61+
62+
Place `config.json` next to the executable. Example:
63+
64+
```json
65+
{
66+
"IgnoredExtensions": [".cache", ".DS_Store", ".db", ".ilcache", ".log", ".pdb"],
67+
"TextFileExtensions": [
68+
".asax",
69+
".ascx",
70+
".asmx",
71+
".aspx",
72+
".bat",
73+
".c",
74+
".cmd",
75+
".config",
76+
".cpp",
77+
".cs",
78+
".cshtml",
79+
".csproj",
80+
".csx",
81+
".css",
82+
".csv",
83+
".editorconfig",
84+
".env",
85+
".fs",
86+
".fsi",
87+
".fsproj",
88+
".fsx",
89+
".gitattributes",
90+
".gitignore",
91+
".gitmodules",
92+
".go",
93+
".gql",
94+
".graphql",
95+
".h",
96+
".hpp",
97+
".htm",
98+
".html",
99+
".http",
100+
".ini",
101+
".js",
102+
".json",
103+
".jsx",
104+
".less",
105+
".manifest",
106+
".md",
107+
".mod",
108+
".nlog",
109+
".nuspec",
110+
".plist",
111+
".props",
112+
".ps1",
113+
".psd1",
114+
".psm1",
115+
".py",
116+
".razor",
117+
".resx",
118+
".rst",
119+
".sass",
120+
".scss",
121+
".sh",
122+
".sln",
123+
".sql",
124+
".sqlproj",
125+
".sum",
126+
".svg",
127+
".targets",
128+
".toml",
129+
".ts",
130+
".tsv",
131+
".tsx",
132+
".txt",
133+
".vb",
134+
".vbproj",
135+
".vue",
136+
".xaml",
137+
".xml",
138+
".yaml",
139+
".yml"
140+
],
141+
"MaxLogGenerations": 5,
142+
"ShouldIncludeUnchangedFiles": true,
143+
"ShouldIncludeIgnoredFiles": true,
144+
"ShouldOutputILText": true,
145+
"ShouldOutputFileTimestamps": true,
146+
"MaxParallelism": 0,
147+
"EnableILCache": true,
148+
"ILCacheDirectoryAbsolutePath": "",
149+
"ILCacheStatsLogIntervalSeconds": 60,
150+
"ILCacheMaxDiskFileCount": 0,
151+
"ILCacheMaxDiskMegabytes": 0,
152+
"OptimizeForNetworkShares": false,
153+
"AutoDetectNetworkShares": true
154+
}
155+
```
156+
157+
| Key | Description |
158+
| --- | --- |
159+
| `IgnoredExtensions` | Excludes matching extensions from comparison (e.g., `.pdb`). |
160+
| `TextFileExtensions` | Treats matching extensions as text, diffed line by line. Include the dot (e.g., `.cs`, `.json`). |
161+
| `MaxLogGenerations` | Number of log files kept in rotation. |
162+
| `ShouldIncludeUnchangedFiles` | Whether to list `Unchanged` files inside `Reports/<label>/diff_report.md`. |
163+
| `ShouldIncludeIgnoredFiles` | Whether to output ignored files in the `## [ x ] Ignored Files` section (before `Unchanged`). |
164+
| `ShouldOutputILText` | Writes IL dumps to `Reports/<label>/IL/old` and `.../IL/new`. |
165+
| `ShouldOutputFileTimestamps` | Adds last modified timestamps to each file line inside the report. |
166+
| `MaxParallelism` | Degree of parallelism for file comparisons. `0` or omitted uses the logical core count. |
167+
| `EnableILCache` | Caches IL disassembly results (MD5 + tool/version) in memory and optionally on disk. |
168+
| `ILCacheDirectoryAbsolutePath` | Custom cache folder. Blank defaults to `<exe>/ILCache` with LRU + TTL control. |
169+
| `ILCacheStatsLogIntervalSeconds` | Interval (seconds) for logging IL cache statistics. `<= 0` falls back to 60 seconds. |
170+
| `ILCacheMaxDiskFileCount` | Upper bound for disk cache files. `<= 0` disables trimming. Oldest entries are removed first. |
171+
| `ILCacheMaxDiskMegabytes` | Disk cache size limit (MB). `<= 0` disables trimming. Oldest entries are removed until under the limit. |
172+
| `OptimizeForNetworkShares` | Optimizes comparisons on NAS/SMB shares by skipping MD5 pre-warming, reducing parallelism, and forcing sequential diffing of large text files. |
173+
| `AutoDetectNetworkShares` | Detects network paths automatically (UNC on Windows, `statfs` on macOS, `/proc/mounts`/`/etc/mtab` on Linux/Unix) and enables the same optimizations automatically. |
174+
175+
Notes:
176+
177+
- Files without extensions are still compared. Add an empty string to `TextFileExtensions` if you want them treated as text.
178+
- .NET "extensionless" executables (apphosts) may keep the same MD5 even after rebuilding.
179+
180+
## Usage
181+
182+
1. Review and adjust `config.json` next to the executable.
183+
2. Run the app with the following arguments:
184+
1. Absolute path to the old (baseline) folder.
185+
2. Absolute path to the new folder.
186+
3. Report label (used as the subfolder name under `Reports`).
187+
4. Optional `--no-pause` to skip the "Press any key" prompt.
188+
3. The prompt is automatically skipped when the process is non-interactive (I/O redirection).
189+
190+
Build and run example:
191+
192+
```bash
193+
dotnet build
194+
dotnet run "/Users/UserA/workspace/old" "/Users/UserA/workspace/new" "YYYYMMDD" --no-pause
195+
```
196+
197+
The console shows progress, and after completion the report is available at `Reports/<label>/diff_report.md`.
198+
199+
After writing the report, the following files are marked read-only (failures only generate warnings):
200+
201+
- `diff_report.md`
202+
- `IL/old/*_IL.txt` (when `ShouldOutputILText` is true)
203+
- `IL/new/*_IL.txt` (when `ShouldOutputILText` is true)
204+
205+
## Generated artifacts
206+
207+
- `Logs/log_YYYYMMDD.log` – application logs. Entries older than `MaxLogGenerations` are deleted.
208+
- If `ShouldOutputILText` is true:
209+
- `Reports/<label>/IL/old/*.txt` – IL dumps (build-specific noise removed) for files from the old folder.
210+
- `Reports/<label>/IL/new/*.txt` – IL dumps for the new folder.
211+
- IL dumps exclude lines that start with `// MVID:`.
212+
213+
## Performance optimizations
214+
215+
| Feature | Summary | Notes |
216+
| --- | --- | --- |
217+
| Parallel diffing | Compares files in parallel up to `MaxParallelism`. | Balances CPU and I/O usage. |
218+
| IL cache | Reuses IL text based on MD5 + tool label (command + version). | In-memory cache (LRU up to 2000 items, TTL 12h) with optional disk persistence. |
219+
| MD5 pre-warming | Precomputes MD5 for all targets in parallel before diffing. | Evens out cache key generation time. |
220+
| IL cache prefetch | Promotes disk cache entries into memory before diffing. | Further reduces disassembler launches. |
221+
| Parallel text diff | Files ≥512 KiB are split into 64 KiB chunks compared in parallel. | Only determines equality (no diff output). |
222+
| Tool failure blacklist | Skips IL tools that failed repeatedly (default: 3 times) for 10 minutes. | Reduces repeated launch overhead. |
223+
224+
### IL cache notes
225+
226+
- File names in the disk cache are sanitized (invalid chars/colon replaced with `_`, overly long names shortened) to avoid NTFS alternate data stream quirks.
227+
- Disk cache trimming obeys both LRU and the `ILCacheMaxDiskFileCount` / `ILCacheMaxDiskMegabytes` settings.
228+
229+
## Versioning (Nerdbank.GitVersioning)
230+
231+
The project uses [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) to produce SemVer versions.
232+
233+
- `version.json` declares release channels such as `main` or tags like `v1.2.3`.
234+
- The generated `AssemblyInformationalVersion` is recorded in `Reports/<label>/diff_report.md`.
235+
- You can override the version manually via `dotnet build /p:Version=1.2.3` when needed.
236+
237+
Tagging example:
238+
239+
```bash
240+
git tag v1.0.0
241+
git push origin v1.0.0
242+
```

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
2つのフォルダの差分をレポート出力するコンソールアプリケーションです。.NET アセンブリに関してはビルド固有情報(例: MVID)が存在する場合はこれを除外して IL 比較するため、ビルド日時が異なっていても実質同じ挙動であれば同一と判定します。
44

5+
> Need this document in English? See [README.en.md](README.en.md).
6+
57
## 必要環境
68

79
- .NET SDK 8.x

0 commit comments

Comments
 (0)