Add MPQ verify modes, harden CI assertions, fix CRLF/docstring
CI / build-and-smoke (push) Failing after 31s
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:
+10
-2
@@ -28,8 +28,16 @@ jobs:
|
|||||||
-v "$PWD/test:/work" \
|
-v "$PWD/test:/work" \
|
||||||
mpq-packager:ci
|
mpq-packager:ci
|
||||||
|
|
||||||
- name: Assert artifact exists
|
- name: Assert archive is valid and contains the expected file
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
test -s test/dist/patch-Z.mpq
|
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"
|
||||||
|
|||||||
@@ -2,3 +2,6 @@ dist/
|
|||||||
test/dist/
|
test/dist/
|
||||||
*.mpq
|
*.mpq
|
||||||
*.o
|
*.o
|
||||||
|
# local validation helpers (not needed in CI)
|
||||||
|
test/stub_mpqpack.py
|
||||||
|
test/mpqpack.cmd
|
||||||
|
|||||||
+3
-1
@@ -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 --from=build /usr/local/bin/mpqpack /usr/local/bin/mpqpack
|
||||||
COPY package.py /opt/mpq-packager/package.py
|
COPY package.py /opt/mpq-packager/package.py
|
||||||
COPY entrypoint.sh /opt/mpq-packager/entrypoint.sh
|
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"]
|
ENTRYPOINT ["/opt/mpq-packager/entrypoint.sh"]
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ Manifest schema (all keys optional except `contents`):
|
|||||||
extensions: [".lua", ".xml", ".toc"]
|
extensions: [".lua", ".xml", ".toc"]
|
||||||
contents:
|
contents:
|
||||||
- src: . # path in the repo (file or dir)
|
- 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
|
ignore: # glob patterns, matched against repo-relative paths
|
||||||
- ".git/**"
|
- ".git/**"
|
||||||
- ".gitea/**"
|
- ".gitea/**"
|
||||||
|
|||||||
+42
-1
@@ -80,9 +80,50 @@ static unsigned walk(const char *dir, int add) {
|
|||||||
return count;
|
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) {
|
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) {
|
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;
|
return 2;
|
||||||
}
|
}
|
||||||
const char *out = argv[1];
|
const char *out = argv[1];
|
||||||
|
|||||||
Reference in New Issue
Block a user