Add MPQ verify modes, harden CI assertions, fix CRLF/docstring
CI / build-and-smoke (push) Failing after 31s

- mpqpack gains --list and --cat (StormLib-backed) for reading archives back
- CI now asserts the archive lists the expected file and that version
  substitution landed inside the MPQ, not just that a file exists
- Dockerfile strips CRLF from entrypoint/package so local Windows builds work
- drop invalid escape in package.py docstring
This commit is contained in:
2026-06-25 21:54:09 -05:00
parent 64abb39d0b
commit 922aea9bc1
5 changed files with 59 additions and 5 deletions
+10 -2
View File
@@ -28,8 +28,16 @@ jobs:
-v "$PWD/test:/work" \
mpq-packager:ci
- name: Assert artifact exists
- name: Assert archive is valid and contains the expected file
run: |
set -euo pipefail
test -s test/dist/patch-Z.mpq
echo "OK: $(stat -c%s test/dist/patch-Z.mpq) bytes"
echo "size: $(stat -c%s test/dist/patch-Z.mpq) bytes"
# Read the archive back with StormLib (mpqpack --list/--cat).
docker run --rm --entrypoint mpqpack -v "$PWD/test:/work" mpq-packager:ci \
--list /work/dist/patch-Z.mpq | tee /tmp/list.txt
grep -q 'Interface\\AddOns\\Fixture\\Hello.lua' /tmp/list.txt
docker run --rm --entrypoint mpqpack -v "$PWD/test:/work" mpq-packager:ci \
--cat /work/dist/patch-Z.mpq 'Interface\AddOns\Fixture\Hello.lua' \
| grep -q 'VERSION = "v0.0.0-ci"'
echo "OK: archive valid, path + substitution confirmed"
+3
View File
@@ -2,3 +2,6 @@ dist/
test/dist/
*.mpq
*.o
# local validation helpers (not needed in CI)
test/stub_mpqpack.py
test/mpqpack.cmd
+3 -1
View File
@@ -37,6 +37,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
COPY --from=build /usr/local/bin/mpqpack /usr/local/bin/mpqpack
COPY package.py /opt/mpq-packager/package.py
COPY entrypoint.sh /opt/mpq-packager/entrypoint.sh
RUN chmod +x /opt/mpq-packager/entrypoint.sh
# Strip any CRLF (Windows checkouts) so the shebang and bash parse correctly.
RUN sed -i 's/\r$//' /opt/mpq-packager/entrypoint.sh /opt/mpq-packager/package.py \
&& chmod +x /opt/mpq-packager/entrypoint.sh
ENTRYPOINT ["/opt/mpq-packager/entrypoint.sh"]
+1 -1
View File
@@ -23,7 +23,7 @@ Manifest schema (all keys optional except `contents`):
extensions: [".lua", ".xml", ".toc"]
contents:
- src: . # path in the repo (file or dir)
dest: Interface/GlueXML # in-MPQ path (forward slashes; converted to \)
dest: Interface/GlueXML # in-MPQ path (forward slashes become backslashes)
ignore: # glob patterns, matched against repo-relative paths
- ".git/**"
- ".gitea/**"
+42 -1
View File
@@ -80,9 +80,50 @@ static unsigned walk(const char *dir, int add) {
return count;
}
/* --list <mpq>: enumerate archive contents (names + sizes). */
static int cmd_list(const char *mpq) {
HANDLE h;
if (!SFileOpenArchive(mpq, 0, STREAM_FLAG_READ_ONLY, &h)) die("open", mpq);
SFILE_FIND_DATA fd;
HANDLE find = SFileFindFirstFile(h, "*", &fd, NULL);
if (find) {
do {
printf("%-50s %u\n", fd.cFileName, fd.dwFileSize);
} while (SFileFindNextFile(find, &fd));
SFileFindClose(find);
}
SFileCloseArchive(h);
return 0;
}
/* --cat <mpq> <internal-name>: dump one file's bytes to stdout. */
static int cmd_cat(const char *mpq, const char *name) {
HANDLE h, f;
if (!SFileOpenArchive(mpq, 0, STREAM_FLAG_READ_ONLY, &h)) die("open", mpq);
if (!SFileOpenFileEx(h, name, 0, &f)) die("openfile", name);
char buf[65536];
DWORD got;
while (SFileReadFile(f, buf, sizeof buf, &got, NULL) || got) {
fwrite(buf, 1, got, stdout);
if (got < sizeof buf) break;
}
SFileCloseFile(f);
SFileCloseArchive(h);
return 0;
}
int main(int argc, char **argv) {
if (argc >= 3 && !strcmp(argv[1], "--list"))
return cmd_list(argv[2]);
if (argc >= 4 && !strcmp(argv[1], "--cat"))
return cmd_cat(argv[2], argv[3]);
if (argc < 3) {
fprintf(stderr, "usage: %s <output.mpq> <staging-dir> [maxFiles]\n", argv[0]);
fprintf(stderr,
"usage: %s <output.mpq> <staging-dir> [maxFiles]\n"
" %s --list <mpq>\n"
" %s --cat <mpq> <internal-name>\n",
argv[0], argv[0], argv[0]);
return 2;
}
const char *out = argv[1];