add testing
Some checks failed
Build / build-windows (push) Successful in 34s
Build / build-linux (push) Failing after 38s
Build / package-dist (push) Has been skipped

This commit is contained in:
2025-02-17 21:10:16 -06:00
parent 75c7e304de
commit 1ae73aed06
12 changed files with 115 additions and 340 deletions

View File

@@ -9,7 +9,6 @@ RUN echo "https://dl-cdn.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositor
# Update indexes and install packages # Update indexes and install packages
RUN apk update && \ RUN apk update && \
apk add --no-cache \ apk add --no-cache \
# Basic dev tools
build-base \ build-base \
binutils \ binutils \
mold \ mold \
@@ -19,21 +18,13 @@ RUN apk update && \
git \ git \
pkgconf \ pkgconf \
ccache \ ccache \
# Node.js + npm
nodejs \ nodejs \
npm \ npm \
# Misc
zip \ zip \
# Audio/Video dev libs
alsa-lib-dev \ alsa-lib-dev \
pulseaudio-dev \ pulseaudio-dev \
libudev-zero-dev \ libudev-zero-dev \
# Wayland dev libs
wayland-dev \ wayland-dev \
wayland-protocols \ wayland-protocols \
mesa-dev \ mesa-dev \
# Finally, the new SDL3 dev package on Alpine edge
sdl3 sdl3
# (Optional) If you want a default working directory:
WORKDIR /workspace

View File

@@ -1,8 +1,7 @@
# Dockerfile.linux FROM ubuntu:plucky
FROM ubuntu:24.04
RUN apt-get update && \ RUN apt-get update && apt-get install -y --no-install-recommends \
apt-get install -y --no-install-recommends \ python3 python3-pip \
libasound2-dev \ libasound2-dev \
libpulse-dev \ libpulse-dev \
libudev-dev \ libudev-dev \
@@ -24,8 +23,10 @@ RUN apt-get update && \
build-essential \ build-essential \
binutils \ binutils \
mold \ mold \
meson \
pkg-config \ pkg-config \
npm nodejs zip \ meson \
ccache && \ ccache \
mingw-w64 \
wine \
npm nodejs zip && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*

View File

@@ -1,5 +1,4 @@
# Dockerfile.windows-cross FROM ubuntu:plucky
FROM ubuntu:24.04
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
@@ -10,8 +9,7 @@ RUN apt-get update && \
build-essential \ build-essential \
binutils \ binutils \
pkg-config \ pkg-config \
meson \
zip \ zip \
npm nodejs \ ccache \
ccache && \ npm nodejs && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*

View File

@@ -11,7 +11,6 @@ jobs:
build-linux: build-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
# Pull and run inside your prebuilt Docker image for Linux
image: gitea.pockle.world/john/prosperon/linux:latest image: gitea.pockle.world/john/prosperon/linux:latest
steps: steps:
@@ -48,14 +47,27 @@ jobs:
- name: Build Prosperon (Linux) - name: Build Prosperon (Linux)
run: | run: |
export PKG_CONFIG_PATH="${PWD}/sdl3-build/installed_sdl3/lib/pkgconfig:$PKG_CONFIG_PATH" export PKG_CONFIG_PATH="${PWD}/sdl3-build/installed_sdl3/lib/pkgconfig:$PKG_CONFIG_PATH"
meson setup build_dbg -Dbuildtype=debugoptimized meson setup build -Dbuildtype=release -Db_lto=true -Db_ndebug=true
meson compile -C build_dbg meson compile -C build
- name: Test Prosperon (Linux)
env:
TRACY_NO_INVARIANT_CHECK: 1
run: |
meson test --print-errorlogs -C build
- name: Upload Test Log (Linux)
if: ${{ always() }}
uses: actions/upload-artifact@v3
with:
name: testlog-linux
path: build/meson-logs/testlog.txt
- name: Create artifact folder (Linux) - name: Create artifact folder (Linux)
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
run: | run: |
mkdir _pack mkdir _pack
cp build_dbg/prosperon _pack/ cp build/prosperon _pack/
# Adjust wildcard if there's a versioned libSDL3. e.g. libSDL3-0.600.0.so
cp sdl3-build/installed_sdl3/lib/libSDL3.so _pack/ cp sdl3-build/installed_sdl3/lib/libSDL3.so _pack/
- name: Upload Artifact (Linux) - name: Upload Artifact (Linux)
@@ -68,8 +80,7 @@ jobs:
build-windows: build-windows:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
# Pull and run inside your prebuilt Docker image for Windows cross-compilation image: gitea.pockle.world/john/prosperon/linux:latest
image: gitea.pockle.world/john/prosperon/mingw:latest
steps: steps:
- name: Check Out Code - name: Check Out Code
@@ -112,13 +123,13 @@ jobs:
- name: Build Prosperon (Windows cross) - name: Build Prosperon (Windows cross)
run: | run: |
meson setup -Dbuildtype=debugoptimized --cross-file mingw32.cross build_win meson setup build -Dbuildtype=release -Db_lto=true -Db_ndebug=true --cross-file mingw32.cross
meson compile -C build_win meson compile -C build
- name: Create package folder - name: Create package folder
run: | run: |
mkdir _pack mkdir _pack
cp build_win/prosperon.exe _pack/ cp build/prosperon.exe _pack/
cp sdl3-build-win/installed_sdl3_win/bin/SDL3.dll _pack/ cp sdl3-build-win/installed_sdl3_win/bin/SDL3.dll _pack/
- name: Upload Artifact (Windows cross) - name: Upload Artifact (Windows cross)

View File

@@ -151,9 +151,7 @@ core = custom_target('core.zip',
'cd ' + meson.project_source_root() + 'cd ' + meson.project_source_root() +
' && echo "Rebuilding core.zip" && rm -f ' + meson.current_build_dir() + '/core.zip && ' + ' && echo "Rebuilding core.zip" && rm -f ' + meson.current_build_dir() + '/core.zip && ' +
'zip -r ' + meson.current_build_dir() + '/core.zip scripts fonts icons shaders' 'zip -r ' + meson.current_build_dir() + '/core.zip scripts fonts icons shaders'
], ]
build_always_stale: true,
build_by_default: true
) )
prosperon_raw = executable('prosperon_raw', sources, prosperon_raw = executable('prosperon_raw', sources,
@@ -175,16 +173,36 @@ prosperon = custom_target('prosperon',
input: [prosperon_raw, core], input: [prosperon_raw, core],
command: [ command: [
'sh', '-c', 'sh', '-c',
'cat "$1" "$2" > "$3"', 'cat "$1" "$2" > "$3" && chmod +x "$3" >/dev/null 2>&1',
'concat', 'concat',
'@INPUT0@', '@INPUT0@',
'@INPUT1@', '@INPUT1@',
'@OUTPUT@' '@OUTPUT@'
], ],
build_always: true, build_always: true
build_by_default: true
) )
prosperon_dep = declare_dependency( prosperon_dep = declare_dependency(
link_with:prosperon link_with:prosperon
) )
copy_tests = custom_target(
'copy_tests',
output: 'tests',
command: [
'cp', '-rf',
join_paths(meson.source_root(), 'tests'),
meson.build_root()
],
build_always: true
)
tests = [
'spawn_actor',
'empty'
]
foreach file : tests
test(file, prosperon, args:['tests/' + file + '.js'], depends:copy_tests)
endforeach

View File

@@ -14,4 +14,4 @@ cpu = 'x86_64'
endian = 'little' endian = 'little'
[properties] [properties]
needs_exe_wrapper = false needs_exe_wrapper = true

View File

@@ -1156,7 +1156,7 @@ var os = use_embed('os')
var js = use_embed('js') var js = use_embed('js')
prosperon.on('SIGINT', function() { prosperon.on('SIGINT', function() {
os.exit() os.exit(1)
}) })
prosperon.on('SIGABRT', function() { prosperon.on('SIGABRT', function() {
@@ -1218,7 +1218,6 @@ var script_fn = function script_fn(path) {
var file = resources.find_script(path) var file = resources.find_script(path)
if (!file) { if (!file) {
// attempt to bare load
parsed.module_ret = bare_load(path) parsed.module_ret = bare_load(path)
if (!parsed.module_ret) throw new Error(`Module ${path} could not be created`) if (!parsed.module_ret) throw new Error(`Module ${path} could not be created`)
return parsed return parsed
@@ -1237,8 +1236,6 @@ var script_fn = function script_fn(path) {
if (parsed.module_ret === undefined || parsed.module_ret === null) if (parsed.module_ret === undefined || parsed.module_ret === null)
throw new Error(`Module ${module_name} must return a value`) throw new Error(`Module ${module_name} must return a value`)
parsed.module_fn = module_fn parsed.module_fn = module_fn
// console.log(`api for ${path}`)
// print_api(parsed.module_ret)
} }
if (parsed.program) { if (parsed.program) {
@@ -1265,6 +1262,7 @@ function console_rec(category, priority, line, file, msg) {
return `${file}:${line}: [${category} ${priority}]: ${msg}\n` return `${file}:${line}: [${category} ${priority}]: ${msg}\n`
} }
io.mkdir('.prosperon')
var logfile = io.open('.prosperon/log.txt') var logfile = io.open('.prosperon/log.txt')
function pprint(msg, lvl = 0) { function pprint(msg, lvl = 0) {

View File

@@ -1,6 +1,6 @@
var io = use('io') var io = use('io')
var util = use('util') var util = use('util')
var loop = use('loop')
var dumpfolder = ".prosperon"; var dumpfolder = ".prosperon";
@@ -24,51 +24,6 @@ Cmdline.register_order = function (order, fn, doc, usage = "") {
fn.usage = `${order} ${usage}`; fn.usage = `${order} ${usage}`;
}; };
Cmdline.register_order(
"edit",
function () {
if (!io.exists(projectfile)) {
console.print("No game to edit. Try making one with 'prosperon init'.");
return;
}
},
"Edit the project in this folder. Give it the name of an UR to edit that specific object.",
"?UR?",
);
Cmdline.register_order(
"init",
function () {
if (io.exists(projectfile)) {
console.print("Already a game here.");
return;
}
io.mkdir(dumpfolder);
var project = {};
project.version = prosperon.version;
project.revision = prosperon.revision;
io.slurpwrite(projectfile, json.encode(project));
},
"Turn the directory into a Prosperon game.",
);
Cmdline.register_order(
"debug",
function () {
Cmdline.orders.play([]);
},
"Play the game with debugging enabled.",
);
Cmdline.register_order(
"web",
function () {
Cmdline.orders.play([]);
},
"Play the game in a web browser.",
);
Cmdline.register_order( Cmdline.register_order(
"makedoc", "makedoc",
function() { function() {
@@ -115,12 +70,9 @@ for (var m of globals) {
"Make documentation." "Make documentation."
}) })
Cmdline.register_order( function spawn_root(script)
"play", {
function (argv) { return actor.spawn(script, {}, function(underling, msg) {
var app
if (io.exists("main.js"))
app = actor.spawn("main.js", {}, function(underling, msg) {
if (msg.message !== "created") return; if (msg.message !== "created") return;
Object.defineProperty(underling, 'then', { Object.defineProperty(underling, 'then', {
configurable:false, configurable:false,
@@ -130,72 +82,26 @@ Cmdline.register_order(
} }
}); });
}) })
}
Cmdline.register_order(
"play",
function (argv) {
var app
if (io.exists("main.js"))
app = spawn_root("main.js")
else else
app = actor.spawn("nogame.js"); app = spawn_root("nogame.js")
// rm actor so it can't be tampered // rm actor so it can't be tampered
globalThis.actor = undefined globalThis.actor = undefined
var ren = use('render') var loop = use('loop')
while(1) loop.step(); while(1) loop.step();
}, },
"Play the game present in this folder.", "Play the game present in this folder.",
); );
Cmdline.register_order(
"pack",
function (str) {
var packname;
if (str.length === 0) packname = "game.zip";
else if (str.length > 1) {
console.warn("Give me a single filename for the pack.");
return;
} else packname = str[0];
console.print(`Packing into ${packname}`);
io.pack_start(packname);
files = allfiles.filter(f => !f.startsWith(".git"));
files = files.filter(f => !f.startsWith(".nova"));
files = files.filter(f => !f.includes(".DS_Store"));
files = files.filter(f => !f.startsWith(".gitignore"));
console.print(files);
for (var f of files) io.pack_add(f);
io.pack_end();
},
"Pack the game into the given name.",
"NAME",
);
Cmdline.register_order(
"cdb",
function (argv) {
var cdb = "game.zip";
if (!io.exists(cdb)) {
console.print(`No 'game.zip' present.`);
return;
}
if (argv.length === 0) {
console.print(`cdb name: ${cdb}`);
}
},
"CDB commands.",
);
Cmdline.register_order(
"qoa",
function (argv) {
var sounds = Resources.sounds.filter(x => x !== "qoa");
for (var file of argv) {
if (!sounds.includes(file.ext())) continue;
console.print(`converting ${file}`);
io.save_qoa(file);
}
},
"Convert file(s) to qoa.",
);
Cmdline.register_order( Cmdline.register_order(
"about", "about",
function (argv) { function (argv) {
@@ -213,92 +119,6 @@ Cmdline.register_order(
"Get information about this game.", "Get information about this game.",
); );
Cmdline.register_order(
"ur",
function (argv) {
// game.loadurs();
for (var i of ur._list.sort()) console.print(i);
},
"Get information about the ur types in your game.",
);
Cmdline.register_order(
"env",
function (argv) {
if (argv.length > 2) return;
var gg = json.decode(io.slurp(projectfile));
if (argv.length === 0) {
console.print(json.encode(gg, null, 1));
return;
}
if (argv.length === 1) {
var v = gg[argv[0]];
if (!v) {
console.print(`Value ${argv[0]} not found.`);
return;
}
console.print(`${argv[0]}:${v}`);
} else {
gg[argv[0]] = argv[1];
console.print(`Set ${argv[0]}:${v}`);
console.print(json.encode(gg, null, 1));
io.slurpwrite(projectfile, json.encode(gg));
}
},
"Get or set game variables.",
);
Cmdline.register_order(
"unpack",
function () {
console.print("Unpacking not implemented.");
},
"Unpack this binary's contents into this folder for editing.",
);
Cmdline.register_order(
"build",
function () {
console.print("Building not implemented.");
},
"Build static assets for this project.",
);
Cmdline.register_order(
"nota",
function (argv) {
for (var file of argv) {
if (!io.exists(file)) {
console.print(`File ${file} does not exist.`);
continue;
}
var obj = json.decode(io.slurp(file));
var nn = nota.encode(obj);
io.slurpwrite(file.strip_ext() + ".nota", nn);
}
},
"Create a nota file from a json.",
);
Cmdline.register_order(
"json",
function (argv) {
for (var file of argv) {
if (!io.exists(file)) {
console.print(`File ${file} does not exist.`);
continue;
}
console.print(file.ext());
var obj = nota.decode(io.slurp(file));
var nn = json.encode(obj);
io.slurpwrite(file.strip_ext() + ".json", nn);
}
},
"Create a JSON from a nota.",
);
Cmdline.register_order( Cmdline.register_order(
"api", "api",
function (obj) { function (obj) {
@@ -330,8 +150,12 @@ Cmdline.register_order(
console.print("Need something to run."); console.print("Need something to run.");
return; return;
} }
try {
console.print(eval(script)); spawn_root(script)
} catch(e) {
console.error(e);
os.exit(1);
}
}, },
"Run a given script. SCRIPT can be the script itself, or a file containing the script", "Run a given script. SCRIPT can be the script itself, or a file containing the script",
"SCRIPT", "SCRIPT",
@@ -384,80 +208,12 @@ function cmd_args(cmds) {
cmds.shift() cmds.shift()
if (cmds.length === 0) cmds[0] = "play"; if (cmds.length === 0) cmds[0] = "play";
else if (!Cmdline.orders[cmds[0]]) { else if (!Cmdline.orders[cmds[0]]) {
console.warn(`Command ${cmds[0]} not found. Playing instead.`); // assume it's a script
cmds[0] = "play"; cmds[1] = cmds[0]
cmds[0] = "run"
} }
Cmdline.orders[cmds[0]](cmds.slice(1)); Cmdline.orders[cmds[0]](cmds.slice(1));
} }
Cmdline.register_order(
"clean",
function (argv) {
console.print("Cleaning not implemented.");
},
"Clean up a given object file.",
"JSON ...",
);
Cmdline.register_order(
"test",
function (argv) {
use("test.js");
},
"Run tests.",
);
Cmdline.register_cmd(
"l",
function (n) {
console.level = n;
},
"Set log level.",
);
function convertYAMLtoJSON(yamlString) {
const lines = yamlString.split("\n");
const jsonObj = {};
let currentKey = "";
let currentValue = "";
let currentDepth = 0;
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (!line || line.startsWith("#")) {
continue;
}
const depth = (line.match(/^\s+/g) || [""])[0].length;
const keyValue = line.split(":");
const key = keyValue[0].trim();
const value = keyValue[1].trim();
if (depth > currentDepth) {
jsonObj[currentKey] = convertYAMLtoJSON(currentValue);
currentKey = key;
currentValue = value;
} else if (depth === currentDepth) {
jsonObj[currentKey] = convertYAMLtoJSON(currentValue);
currentKey = key;
currentValue = value;
} else {
jsonObj[currentKey] = convertYAMLtoJSON(currentValue);
currentKey = "";
currentValue = "";
i--; // To reprocess the current line with updated values
}
currentDepth = depth;
}
if (currentKey) {
jsonObj[currentKey] = convertYAMLtoJSON(currentValue);
}
return jsonObj;
}
return cmd_args; return cmd_args;

View File

@@ -93,15 +93,18 @@ if (!ret) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
prosperon = argv[0]; prosperon = argv[0];
PHYSFS_init(argv[0]); PHYSFS_init(argv[0]);
char *base = PHYSFS_getBaseDir(); char *base = PHYSFS_getBaseDir();
PHYSFS_setWriteDir(base); PHYSFS_setWriteDir(base);
PHYSFS_mount(base, "/", 0); PHYSFS_mount(base, "/", 0);
prosperon_mount_core(); prosperon_mount_core();
/* int mounted = PHYSFS_mount("core.zip", NULL, 0);
if (!mounted) {
printf("Could not mount core. Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return 1;
}
*/
script_startup(argc, argv); // runs engine.js script_startup(argc, argv); // runs engine.js
return 0; return 0;
} }

View File

@@ -31,16 +31,11 @@ JSValue on_exception = JS_UNDEFINED;
#define ENGINE "scripts/core/engine.js" #define ENGINE "scripts/core/engine.js"
#ifndef NDEBUG
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT #define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT
#else
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP
#endif
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
#include <tracy/TracyC.h> #include <tracy/TracyC.h>
#if defined(__APPLE__) #if defined(__APPLE__)
#define MALLOC_OVERHEAD 0 #define MALLOC_OVERHEAD 0
#else #else
@@ -183,6 +178,7 @@ void script_startup(int argc, char **argv) {
void script_stop() void script_stop()
{ {
return;
JS_FreeContext(js); JS_FreeContext(js);
JS_FreeRuntime(rt); JS_FreeRuntime(rt);
JS_FreeValue(js,on_exception); JS_FreeValue(js,on_exception);

1
tests/empty.js Normal file
View File

@@ -0,0 +1 @@
os.exit(1)

2
tests/spawn_actor.js Normal file
View File

@@ -0,0 +1,2 @@
this.spawn()
console.log("SPAWNED")