diff-based mod removal via --previous-manifest
Adds removal-detection: when --previous-manifest <path> is given, the converter diffs the previous publish against current packwiz state and emits modify[].type=remove entries for mods/resourcepacks/etc that disappeared, using simple-mod-sync's on-disk naming convention as the regex pattern. Reverse-engineered from upstream source: - simple-mod-sync writes <sanitized_name>-<sanitized_version>.<ext> - StringUtils.sanitize strips [^a-zA-Z0-9.\-_] - GetOlderVersion() finds files starting with <name>- and auto-deletes on version bumps. So version upgrades need no converter handling; only full removals do. 8 new tests including end-to-end CLI verification with a synthetic previous manifest. 23/23 pass.
This commit is contained in:
@@ -33,8 +33,26 @@ python3 packwiz_to_sms.py /path/to/packwiz/pack \
|
||||
-o manifest.json \
|
||||
--bundle-non-mods overrides.zip \
|
||||
--bundle-url https://packs.example.com/overrides.zip
|
||||
|
||||
# Generate removal entries for mods dropped since the previous publish
|
||||
python3 packwiz_to_sms.py /path/to/packwiz/pack \
|
||||
-o manifest.json \
|
||||
--previous-manifest /path/to/last-published-manifest.json
|
||||
```
|
||||
|
||||
## Mod removal
|
||||
|
||||
Two cases, handled differently:
|
||||
|
||||
| What changed | Who handles cleanup |
|
||||
|---|---|
|
||||
| **Mod version bump** (Sodium 0.5 → 0.6) | simple-mod-sync itself — it writes downloaded files as `<sanitized_name>-<sanitized_version>.<ext>` and on update looks for any prior file starting with `<name>-` and deletes it. No converter intervention needed. |
|
||||
| **Mod removed entirely** (no longer in pack) | Converter emits an explicit `modify[].type=remove` entry with a regex matching simple-mod-sync's on-disk naming. Triggered by `--previous-manifest <path>` flag. |
|
||||
|
||||
Without `--previous-manifest`, removed mods stay on player disk forever. In CI, keep the last-published manifest and feed it in as the previous one on every run.
|
||||
|
||||
The regex follows simple-mod-sync's `StringUtils.sanitize()` rules: `[^a-zA-Z0-9.\-_]` characters are stripped. So `"Fabric API (Old)"` → pattern `^mods/FabricAPIOld-.*\.jar$`.
|
||||
|
||||
## What gets emitted
|
||||
|
||||
| Packwiz path | Becomes simple-mod-sync `type` |
|
||||
@@ -51,7 +69,6 @@ CurseForge mods that use `mode = "metadata:curseforge"` (no direct URL) are skip
|
||||
## What's not handled
|
||||
|
||||
- **Optional mods** — simple-mod-sync has no per-client toggle UI. All non-server mods are emitted unconditionally. Ship two manifests (with/without optional) if you need this.
|
||||
- **Mod removal** — simple-mod-sync's `modify`/`remove` is not auto-populated. Convert by hand if you're dropping mods.
|
||||
- **Rename / regex transforms** — packwiz has no equivalent concept, so we don't generate `modify.rename` entries.
|
||||
|
||||
## How it works
|
||||
|
||||
Reference in New Issue
Block a user